From 32a78a4aff186698122e431985b21278988fdf74 Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Tue, 3 Jan 2023 18:20:34 -0500 Subject: [PATCH] Add interrupt based timer and test code --- hw/efinix_fpga/addr_decode.sv | 2 +- hw/efinix_fpga/debug_profile.wizard.json | 484 ++++++++++++++++++++++- hw/efinix_fpga/ip/bram/bram_ini.vh | 8 +- hw/efinix_fpga/ip/bram/init_hex.mem | 46 +-- hw/efinix_fpga/super6502.sv | 8 +- hw/efinix_fpga/super6502.xml | 2 +- hw/efinix_fpga/test_programs/Makefile | 11 +- hw/efinix_fpga/test_programs/timer.s | 14 +- hw/efinix_fpga/test_programs/timer_irq.s | 39 ++ hw/efinix_fpga/timer.sv | 99 +++-- 10 files changed, 639 insertions(+), 74 deletions(-) create mode 100644 hw/efinix_fpga/test_programs/timer_irq.s diff --git a/hw/efinix_fpga/addr_decode.sv b/hw/efinix_fpga/addr_decode.sv index a725971..c2152c4 100644 --- a/hw/efinix_fpga/addr_decode.sv +++ b/hw/efinix_fpga/addr_decode.sv @@ -10,7 +10,7 @@ module addr_decode assign o_rom_cs = i_addr >= 16'hf000 && i_addr <= 16'hffff; assign o_leds_cs = i_addr == 16'hefff; -assign o_timer_cs = i_addr >= 16'heff8 && i_addr <= 16'heffe; +assign o_timer_cs = i_addr >= 16'heff8 && i_addr <= 16'heffb; assign o_sdram_cs = i_addr < 16'h8000; endmodule \ No newline at end of file diff --git a/hw/efinix_fpga/debug_profile.wizard.json b/hw/efinix_fpga/debug_profile.wizard.json index df03548..1b2e4d9 100644 --- a/hw/efinix_fpga/debug_profile.wizard.json +++ b/hw/efinix_fpga/debug_profile.wizard.json @@ -3,7 +3,7 @@ { "name": "la0", "type": "la", - "uuid": "eca5777d2e5a40ed85ba29fd5435f87f", + "uuid": "281a52604f2c437c9bde96b89d672260", "trigin_en": false, "trigout_en": false, "auto_inserted": true, @@ -30,6 +30,36 @@ "name": "cpu_sync", "width": 1, "probe_type": 1 + }, + { + "name": "u_timer/count_en", + "width": 1, + "probe_type": 1 + }, + { + "name": "cpu_data_out", + "width": 8, + "probe_type": 1 + }, + { + "name": "u_timer/timer_latch", + "width": 16, + "probe_type": 1 + }, + { + "name": "u_timer/pulsecount", + "width": 16, + "probe_type": 1 + }, + { + "name": "u_timer/timer_counter", + "width": 16, + "probe_type": 1 + }, + { + "name": "cpu_irqb", + "width": 1, + "probe_type": 1 } ] } @@ -289,6 +319,394 @@ "name": "la0_probe3", "net": "cpu_sync", "path": [] + }, + { + "name": "la0_probe4", + "net": "count_en", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe5[0]", + "net": "cpu_data_out[0]", + "path": [] + }, + { + "name": "la0_probe5[1]", + "net": "cpu_data_out[1]", + "path": [] + }, + { + "name": "la0_probe5[2]", + "net": "cpu_data_out[2]", + "path": [] + }, + { + "name": "la0_probe5[3]", + "net": "cpu_data_out[3]", + "path": [] + }, + { + "name": "la0_probe5[4]", + "net": "cpu_data_out[4]", + "path": [] + }, + { + "name": "la0_probe5[5]", + "net": "cpu_data_out[5]", + "path": [] + }, + { + "name": "la0_probe5[6]", + "net": "cpu_data_out[6]", + "path": [] + }, + { + "name": "la0_probe5[7]", + "net": "cpu_data_out[7]", + "path": [] + }, + { + "name": "la0_probe6[0]", + "net": "timer_latch[0]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe6[1]", + "net": "timer_latch[1]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe6[2]", + "net": "timer_latch[2]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe6[3]", + "net": "timer_latch[3]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe6[4]", + "net": "timer_latch[4]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe6[5]", + "net": "timer_latch[5]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe6[6]", + "net": "timer_latch[6]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe6[7]", + "net": "timer_latch[7]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe6[8]", + "net": "timer_latch[8]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe6[9]", + "net": "timer_latch[9]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe6[10]", + "net": "timer_latch[10]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe6[11]", + "net": "timer_latch[11]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe6[12]", + "net": "timer_latch[12]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe6[13]", + "net": "timer_latch[13]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe6[14]", + "net": "timer_latch[14]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe6[15]", + "net": "timer_latch[15]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[0]", + "net": "pulsecount[0]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[1]", + "net": "pulsecount[1]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[2]", + "net": "pulsecount[2]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[3]", + "net": "pulsecount[3]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[4]", + "net": "pulsecount[4]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[5]", + "net": "pulsecount[5]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[6]", + "net": "pulsecount[6]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[7]", + "net": "pulsecount[7]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[8]", + "net": "pulsecount[8]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[9]", + "net": "pulsecount[9]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[10]", + "net": "pulsecount[10]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[11]", + "net": "pulsecount[11]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[12]", + "net": "pulsecount[12]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[13]", + "net": "pulsecount[13]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[14]", + "net": "pulsecount[14]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe7[15]", + "net": "pulsecount[15]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[0]", + "net": "timer_counter[0]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[1]", + "net": "timer_counter[1]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[2]", + "net": "timer_counter[2]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[3]", + "net": "timer_counter[3]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[4]", + "net": "timer_counter[4]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[5]", + "net": "timer_counter[5]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[6]", + "net": "timer_counter[6]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[7]", + "net": "timer_counter[7]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[8]", + "net": "timer_counter[8]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[9]", + "net": "timer_counter[9]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[10]", + "net": "timer_counter[10]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[11]", + "net": "timer_counter[11]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[12]", + "net": "timer_counter[12]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[13]", + "net": "timer_counter[13]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[14]", + "net": "timer_counter[14]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe8[15]", + "net": "timer_counter[15]", + "path": [ + "u_timer" + ] + }, + { + "name": "la0_probe9", + "net": "cpu_irqb", + "path": [] } ] } @@ -340,6 +758,70 @@ "selected_probe_type": "DATA AND TRIGGER", "child": [], "path": [] + }, + { + "name": "count_en", + "width": 1, + "clk_domain": "clk_2", + "selected_probe_type": "DATA AND TRIGGER", + "child": [], + "path": [ + "u_timer" + ] + }, + { + "name": "cpu_data_out", + "width": 8, + "clk_domain": "clk_2", + "selected_probe_type": "DATA AND TRIGGER", + "child": [], + "path": [], + "net_idx_left": 7, + "net_idx_right": 0 + }, + { + "name": "timer_latch", + "width": 16, + "clk_domain": "clk_2", + "selected_probe_type": "DATA AND TRIGGER", + "child": [], + "path": [ + "u_timer" + ], + "net_idx_left": 15, + "net_idx_right": 0 + }, + { + "name": "pulsecount", + "width": 16, + "clk_domain": "clk_2", + "selected_probe_type": "DATA AND TRIGGER", + "child": [], + "path": [ + "u_timer" + ], + "net_idx_left": 15, + "net_idx_right": 0 + }, + { + "name": "timer_counter", + "width": 16, + "clk_domain": "clk_2", + "selected_probe_type": "DATA AND TRIGGER", + "child": [], + "path": [ + "u_timer" + ], + "net_idx_left": 15, + "net_idx_right": 0 + }, + { + "name": "cpu_irqb", + "width": 1, + "clk_domain": "clk_2", + "selected_probe_type": "DATA AND TRIGGER", + "child": [], + "path": [] } ], "top_module": "super6502", diff --git a/hw/efinix_fpga/ip/bram/bram_ini.vh b/hw/efinix_fpga/ip/bram/bram_ini.vh index fb9ba57..743dba0 100644 --- a/hw/efinix_fpga/ip/bram/bram_ini.vh +++ b/hw/efinix_fpga/ip/bram/bram_ini.vh @@ -4,9 +4,9 @@ input integer index;//Mode type input integer val_; //Port A index, Port B Index, Number of Items in Loop, Port A Start, Port B Start, reserved case (index) 0: bram_ini_table= -(val_== 0)?256'h00ef000ff0009c0001000085000ef000f8000ad000ef000fd0008d000ff000a9: -(val_== 1)?256'h086000f40009000020000e90003800010000e500038000aa000ef000f8000ad0: -(val_== 2)?256'h00000000000000000000000000000000000ed00080000ef000ff000ee0001000: +(val_== 0)?256'h008d00000000a9000ef000fb0008d00001000a9000ef000fa0008d000ff000a9: +(val_== 1)?256'h0f8000ad000fd00080000cb00058000ef000f80008d00010000a9000ef000f90: +(val_== 2)?256'h000000000000000000000000000000000000000040000ef000ff000ee000ef00: (val_== 3)?256'h0000000000000000000000000000000000000000000000000000000000000000: (val_== 4)?256'h0000000000000000000000000000000000000000000000000000000000000000: (val_== 5)?256'h0000000000000000000000000000000000000000000000000000000000000000: @@ -23,7 +23,7 @@ case (index) (val_==16)?256'h0000000000000000000000000000000000000000000000000000000000000000: (val_==17)?256'h0000000000000000000000000000000000000000000000000000000000000000: (val_==18)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_==19)?256'h000ff00000000ff00000000ff000000000000000000000000000000000000000: +(val_==19)?256'h000ff00018000ff00000000ff000000000000000000000000000000000000000: (val_==20)?256'h0000000000000000000000000000000000000000000000000000000000000000: (val_==21)?256'h0000000000000000000000000000000000000000000000000000000000000000: (val_==22)?256'h0000000000000000000000000000000000000000000000000000000000000000: diff --git a/hw/efinix_fpga/ip/bram/init_hex.mem b/hw/efinix_fpga/ip/bram/init_hex.mem index 7e115d3..521126c 100644 --- a/hw/efinix_fpga/ip/bram/init_hex.mem +++ b/hw/efinix_fpga/ip/bram/init_hex.mem @@ -1,35 +1,35 @@ a9 ff 8d +fa +ef +a9 +01 +8d +fb +ef +a9 +00 +8d +f9 +ef +a9 +10 +8d +f8 +ef +58 +cb +80 fd -ef ad f8 ef -85 -10 -9c -ff -ef -ad -f8 -ef -aa -38 -e5 -10 -38 -e9 -20 -90 -f4 -86 -10 ee ff ef -80 -ed +40 +00 00 00 00 @@ -252,5 +252,5 @@ ed ff 00 ff -00 +18 ff diff --git a/hw/efinix_fpga/super6502.sv b/hw/efinix_fpga/super6502.sv index daf4ce5..3fd9b80 100644 --- a/hw/efinix_fpga/super6502.sv +++ b/hw/efinix_fpga/super6502.sv @@ -114,7 +114,7 @@ leds u_leds( .o_leds(leds) ); -logic w_timer_irq; +logic w_timer_irqb; timer u_timer( .clk(clk_2), @@ -123,8 +123,8 @@ timer u_timer( .o_data(w_timer_data_out), .cs(w_timer_cs), .rwb(cpu_rwb), - .addr(cpu_addr[2:0]), - .irq(w_timer_irq) + .addr(cpu_addr[1:0]), + .irqb(w_timer_irqb) ); sdram_adapter u_sdram_adapter( @@ -164,7 +164,7 @@ interrupt_controller u_interrupt_controller( .cs(w_irq_cs), .rwb(cpu_rwb), .irqb_master(cpu_irqb), - .irqb0(w_timer_irq), + .irqb0(w_timer_irqb), .irqb1('1), .irqb2('1), .irqb3('1), diff --git a/hw/efinix_fpga/super6502.xml b/hw/efinix_fpga/super6502.xml index b1010f0..a9fd886 100644 --- a/hw/efinix_fpga/super6502.xml +++ b/hw/efinix_fpga/super6502.xml @@ -1,5 +1,5 @@ - + diff --git a/hw/efinix_fpga/test_programs/Makefile b/hw/efinix_fpga/test_programs/Makefile index f042c1c..4e73332 100644 --- a/hw/efinix_fpga/test_programs/Makefile +++ b/hw/efinix_fpga/test_programs/Makefile @@ -1,11 +1,18 @@ -TARGETS=stacktest runram timer +TARGETS=stacktest runram timer timer_irq +SRC=$(wildcard *.s) +DIR=../ip/bram all: $(TARGETS) -$(TARGETS): +$(TARGETS): $(SRC) cl65 --cpu 65c02 -C link.ld -l $@.list $@.s xxd -ps $@ | fold -w 2 > $@.hex +install: + cp $(TARGET).hex $(DIR)/init_hex.mem + cd $(DIR);python3 efx_mem_init_script.py hex init_hex.mem + + clean: rm -f $(TARGETS) rm *.hex diff --git a/hw/efinix_fpga/test_programs/timer.s b/hw/efinix_fpga/test_programs/timer.s index 6e8590d..4c84a7e 100644 --- a/hw/efinix_fpga/test_programs/timer.s +++ b/hw/efinix_fpga/test_programs/timer.s @@ -2,13 +2,21 @@ LEDS = $efff TIMER_BASE = $eff8 -TIMER_DIVISOR = 5 - +TIMER_DIVISOR = 2 +TIMER_CL = 0 +TIMER_LL = 0 +TIMER_CH = 1 +TIMER_LH = 1 +TIMER_STATUS = 3 TIMER_OLD = $10 main: - lda #$ff + lda #$01 sta TIMER_BASE+TIMER_DIVISOR + lda #$00 + sta TIMER_BASE+TIMER_LH + lda #$0F + sta TIMER_BASE+TIMER_LL lda TIMER_BASE sta TIMER_OLD stz LEDS diff --git a/hw/efinix_fpga/test_programs/timer_irq.s b/hw/efinix_fpga/test_programs/timer_irq.s new file mode 100644 index 0000000..c5b2342 --- /dev/null +++ b/hw/efinix_fpga/test_programs/timer_irq.s @@ -0,0 +1,39 @@ +.code + +LEDS = $efff +TIMER_BASE = $eff8 +TIMER_DIVISOR = 2 +TIMER_CL = 0 +TIMER_LL = 0 +TIMER_CH = 1 +TIMER_LH = 1 +TIMER_STATUS = 3 +TIMER_CONTROL = 3 +TIMER_OLD = $10 + +main: + lda #$ff + sta TIMER_BASE+TIMER_DIVISOR + lda #$01 + sta TIMER_BASE+TIMER_CONTROL + lda #$00 + sta TIMER_BASE+TIMER_LH + lda #$10 + sta TIMER_BASE+TIMER_LL + cli + +loop: + wai + bra loop + +irq: + lda TIMER_BASE + inc LEDS + rti + + +.segment "VECTORS" + +.addr main +.addr main +.addr irq diff --git a/hw/efinix_fpga/timer.sv b/hw/efinix_fpga/timer.sv index 67a0ffd..fa7f743 100644 --- a/hw/efinix_fpga/timer.sv +++ b/hw/efinix_fpga/timer.sv @@ -6,8 +6,8 @@ module timer output logic [7:0] o_data, input cs, input rwb, - input [2:0] addr, - output logic irq + input [1:0] addr, + output logic irqb ); //new idea for timer: @@ -15,43 +15,88 @@ module timer //it can either cause an interrupt or not. //if you want it to do both, add another timer. +/* +Addr Read Write +0 Counter Low Latch Low +1 Counter High Latch High +2 Divisor Divisor +3 Status Control +*/ + logic [15:0] timer_latch, timer_counter; //control register // bit 0: Enable interrupts // bit 1: Enable 1 shot mode -//by default it just starts counting up +//writing to latch low starts the timer logic [7:0] divisor, status, control; +logic count_en; + +assign status[0] = count_en; logic [15:0] pulsecount; //I think this should be negedge so that writes go through always @(negedge clk) begin if (reset) begin + count_en = '0; timer_counter <= '0; pulsecount <= '0; - timer_latch <= '0; + timer_latch <= '1; divisor <= '0; - status <= '0; control <= '0; - irq <= '1; + irqb <= '1; end else begin - if (pulsecount[15:8] == divisor) begin - timer_counter <= timer_counter + 16'b1; - pulsecount <= '0; - end else begin - pulsecount <= pulsecount + 16'b1; + if (count_en) begin + if (pulsecount[15:8] == divisor) begin + timer_counter <= timer_counter + 16'b1; + pulsecount <= '0; + end else begin + pulsecount <= pulsecount + 16'b1; + end + end + + if (timer_counter == timer_latch) begin + // if interrupts are enabled + if (control[0]) begin + irqb <= '0; + end + + // if oneshot mode is enabled + if (control[1]) begin + count_en <= '0; + end else begin + timer_counter <= '0; + end + + end + + if (cs & rwb) begin + irqb <= '1; end if (cs & ~rwb) begin case (addr) - 3'h5: begin + 2'h0: begin + count_en <= '1; + timer_latch[7:0] <= i_data; + end + + 2'h1: begin + timer_latch[15:8] <= i_data; + end + + 2'h2: begin divisor <= i_data; - end + end + + 2'h3: begin + control <= i_data; + end endcase end @@ -62,36 +107,20 @@ always_comb begin o_data = '0; unique case (addr) - 3'h0: begin + 2'h0: begin o_data = timer_counter[7:0]; end - 3'h1: begin + 2'h1: begin o_data = timer_counter[15:8]; end - 3'h2: begin - + 2'h2: begin + o_data = divisor; end - 3'h3: begin - - end - - 3'h4: begin - - end - - 3'h5: begin - - end - - 3'h6: begin - - end - - 3'h7: begin - + 2'h3: begin + o_data = status; end endcase