From ca9e7928444dd3138a2a77375547ab85d001b6f7 Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Mon, 30 Oct 2023 23:46:21 -0700 Subject: [PATCH 01/10] Add first design --- doc/pic.drawio | 372 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 372 insertions(+) create mode 100644 doc/pic.drawio diff --git a/doc/pic.drawio b/doc/pic.drawio new file mode 100644 index 0000000..91d06e2 --- /dev/null +++ b/doc/pic.drawio @@ -0,0 +1,372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 646f34cbb68f3eaf559683031705cd647872d04a Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Tue, 31 Oct 2023 23:04:50 -0700 Subject: [PATCH 02/10] Second diagram --- doc/pic.drawio | 258 ++++++++++++++++++++++++------------------------- 1 file changed, 125 insertions(+), 133 deletions(-) diff --git a/doc/pic.drawio b/doc/pic.drawio index 91d06e2..547a611 100644 --- a/doc/pic.drawio +++ b/doc/pic.drawio @@ -1,6 +1,6 @@ - + - + @@ -57,6 +57,15 @@ + + + + + + + + + @@ -140,25 +149,22 @@ - - - - - - - - - - - - + - + + + + + + + + + @@ -167,7 +173,7 @@ - + @@ -175,15 +181,29 @@ - + + + + + + - + + + + + + + + + + @@ -228,143 +248,115 @@ - + + + + + + - + - + + + + + + + + + + - - + + - - - + + + - - - - + - - + + - - - + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + From e3ad299edf19acf66e602659e37c842fab795f8e Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Tue, 31 Oct 2023 23:11:19 -0700 Subject: [PATCH 03/10] Update diagram again --- doc/pic.drawio | 55 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/doc/pic.drawio b/doc/pic.drawio index 547a611..d96fc65 100644 --- a/doc/pic.drawio +++ b/doc/pic.drawio @@ -1,6 +1,6 @@ - + - + @@ -194,7 +194,7 @@ - + @@ -261,7 +261,7 @@ - + @@ -270,7 +270,7 @@ - + @@ -314,10 +314,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -340,7 +373,12 @@ - + + + + + + @@ -358,6 +396,9 @@ + + + From 0fe57c6ad5b6f3892c2f30abd178cb2c87dba212 Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Tue, 31 Oct 2023 23:44:09 -0700 Subject: [PATCH 04/10] Add beginnings of interrupt controller --- hw/efinix_fpga/src/byte_sel_register.sv | 25 ++++++++ hw/efinix_fpga/src/interrupt_controller.sv | 70 ++++++++++++++++++---- hw/efinix_fpga/src/super6502.sv | 11 +--- hw/efinix_fpga/super6502.xml | 3 +- 4 files changed, 86 insertions(+), 23 deletions(-) create mode 100644 hw/efinix_fpga/src/byte_sel_register.sv diff --git a/hw/efinix_fpga/src/byte_sel_register.sv b/hw/efinix_fpga/src/byte_sel_register.sv new file mode 100644 index 0000000..7ea3e10 --- /dev/null +++ b/hw/efinix_fpga/src/byte_sel_register.sv @@ -0,0 +1,25 @@ +module byte_sel_register +#( + parameter DATA_WIDTH = 8, + parameter ADDR_WIDTH = 32 +)( + input i_clk, + input i_write, + input [$clog2(ADDR_WIDTH)-1:0] i_byte_sel, + input [DATA_WIDTH-1:0] i_data, + output [DATA_WIDTH-1:0] o_data, + output [DATA_WIDTH*ADDR_WIDTH-1:0] o_full_data +); + +logic [DATA_WIDTH*ADDR_WIDTH-1:0] r_data; + +assign o_data = r_data[DATA_WIDTH*i_byte_sel +: DATA_WIDTH]; + +always_ff @(posedge i_clk) begin + r_data <= r_data; + if (i_write) begin + r_data[DATA_WIDTH*i_byte_sel +: DATA_WIDTH] <= i_data; + end +end + +endmodule \ No newline at end of file diff --git a/hw/efinix_fpga/src/interrupt_controller.sv b/hw/efinix_fpga/src/interrupt_controller.sv index 4e00957..f5107bf 100644 --- a/hw/efinix_fpga/src/interrupt_controller.sv +++ b/hw/efinix_fpga/src/interrupt_controller.sv @@ -4,26 +4,72 @@ module interrupt_controller input reset, input [7:0] i_data, output logic [7:0] o_data, + input addr, input cs, input rwb, - output logic irqb_master, - - input irqb0, irqb1, irqb2, irqb3, - input irqb4, irqb5, irqb6, irqb7 + input [255:0] int_in, + output logic int_out ); +logic [7:0] w_enable_data; +logic [255:0] w_enable_full_data; -//All of the inputs are low level triggered. -logic [7:0] irqbv; -assign irqbv = {irqb0, irqb1, irqb2, irqb3, irqb4, irqb5, irqb6, irqb7}; +logic [4:0] w_byte_sel; -always @(posedge clk) begin - o_data <= irqbv; - irqb_master = &irqbv; +logic [7:0] irq_val; - if (cs & ~rwb) begin - o_data <= o_data | i_data; +byte_sel_register #( + .DATA_WIDTH(8), + .ADDR_WIDTH(32) +) reg_enable ( + .i_clk(clk), + .i_write(w_enable_write), + .i_byte_sel(w_byte_sel), + .i_data(i_data), + .o_data(w_enable_data), + .o_full_data(w_enable_full_data) +); + +logic [255:0] int_masked; +assign int_masked = int_in & w_enable_full_data; + + +logic [7:0] w_type_data; +logic [255:0] w_type_full_data; + +byte_sel_register #( + .DATA_WIDTH(8), + .ADDR_WIDTH(32) +) reg_type ( + .i_clk(clk), + .i_write(w_type_write), + .i_byte_sel(w_byte_sel), + .i_data(i_data), + .o_data(w_type_data), + .o_full_data(w_type_full_data) +); + +logic w_eoi; + +logic [255:0] r_int, r_int_next; + +always_comb begin + r_int_next = (~r_int | w_type_full_data) & int_masked; + if (w_eoi) begin + r_int_next[irq_val] = 0; + end +end + +always_ff @(posedge clk) begin + r_int <= r_int_next; +end + +always_comb begin + for (int i = 255; i == 0; i--) begin + if (r_int[i] == 1) begin + irq_val = i; + end end end diff --git a/hw/efinix_fpga/src/super6502.sv b/hw/efinix_fpga/src/super6502.sv index 66fd0fd..f296019 100644 --- a/hw/efinix_fpga/src/super6502.sv +++ b/hw/efinix_fpga/src/super6502.sv @@ -267,16 +267,7 @@ interrupt_controller u_interrupt_controller( .i_data(cpu_data_in), .o_data(w_irq_data_out), .cs(w_irq_cs), - .rwb(cpu_rwb), - .irqb_master(cpu_irqb), - .irqb0(w_timer_irqb), - .irqb1('1), - .irqb2('1), - .irqb3('1), - .irqb4('1), - .irqb5('1), - .irqb6('1), - .irqb7('1) + .rwb(cpu_rwb) ); diff --git a/hw/efinix_fpga/super6502.xml b/hw/efinix_fpga/super6502.xml index 013bb59..709d4f1 100644 --- a/hw/efinix_fpga/super6502.xml +++ b/hw/efinix_fpga/super6502.xml @@ -1,5 +1,5 @@ - + @@ -20,6 +20,7 @@ + From 2b248db94ffa1285284e5286248eaad59b403dda Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Wed, 15 Nov 2023 08:27:29 -0800 Subject: [PATCH 05/10] Add skeleton of interrupt controller --- hw/efinix_fpga/simulation/Makefile | 4 +- .../simulation/tbs/interrupt_controller_tb.sv | 93 +++++++++++++++++++ hw/efinix_fpga/src/byte_sel_register.sv | 12 ++- hw/efinix_fpga/src/interrupt_controller.sv | 55 ++++++++++- 4 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv diff --git a/hw/efinix_fpga/simulation/Makefile b/hw/efinix_fpga/simulation/Makefile index 612d07f..bb818ae 100644 --- a/hw/efinix_fpga/simulation/Makefile +++ b/hw/efinix_fpga/simulation/Makefile @@ -9,6 +9,8 @@ TEST_PROGRAM_NAME?=loop_test TEST_FOLDER?=$(REPO_TOP)/sw/test_code/$(TEST_PROGRAM_NAME) TEST_PROGRAM?=$(REPO_TOP)/sw/test_code/$(TEST_PROGRAM_NAME)/$(TEST_PROGRAM_NAME).hex +STANDALONE_TB= interrupt_controller_tb mapper_code_tb + #TODO implement something like sources.list TOP_MODULE=sim_top @@ -29,7 +31,7 @@ sim: $(TARGET) full_sim: $(TARGET) $(SD_IMAGE) vvp -i $(TARGET) -fst -mapper_tb: $(SRCS) $(TBS) +$(STANDALONE_TB): $(SRCS) $(TBS) iverilog -g2005-sv $(FLAGS) -s $@ -o $@ $(INC) $(SRCS) $(TBS) mapper_code_tb: $(SRCS) $(TBS) $(INIT_MEM) diff --git a/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv b/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv new file mode 100644 index 0000000..0f42817 --- /dev/null +++ b/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv @@ -0,0 +1,93 @@ +`timescale 1ns/1ps + +module interrupt_controller_tb(); + +logic r_clk_cpu; + +// clk_cpu +initial begin + r_clk_cpu <= '1; + forever begin + #125 r_clk_cpu <= ~r_clk_cpu; + end +end + +logic reset; +logic addr; +logic [7:0] i_data; +logic [7:0] o_data; +logic cs; +logic rwb; + +logic [255:0] int_in; +logic int_out; + +interrupt_controller u_interrupt_controller( + .clk(r_clk_cpu), + .reset(reset), + .i_data(i_data), + .o_data(o_data), + .addr(addr), + .cs(cs), + .rwb(rwb), + .int_in(int_in), + .int_out(int_out2) +); + +/* These should be shared */ +task write_reg(input logic [4:0] _addr, input logic [7:0] _data); + @(negedge r_clk_cpu); + cs <= '1; + addr <= _addr; + rwb <= '0; + i_data <= '1; + @(posedge r_clk_cpu); + i_data <= _data; + @(negedge r_clk_cpu); + cs <= '0; + rwb <= '1; +endtask + +task read_reg(input logic [2:0] _addr, output logic [7:0] _data); + @(negedge r_clk_cpu); + cs <= '1; + addr <= _addr; + rwb <= '1; + i_data <= '1; + @(posedge r_clk_cpu); + _data <= o_data; + @(negedge r_clk_cpu); + cs <= '0; + rwb <= '1; +endtask + +initial begin + repeat (5) @(posedge r_clk_cpu); + reset = 1; + cs = 0; + rwb = 1; + addr = '0; + i_data = '0; + int_in = '0; + repeat (5) @(posedge r_clk_cpu); + reset = 0; + repeat (5) @(posedge r_clk_cpu); + write_reg(0, 8'h10); + write_reg(1, 8'hff); + write_reg(0, 8'h20); + write_reg(1, 8'hff); + repeat (5) @(posedge r_clk_cpu); + int_in = 1; + @(posedge r_clk_cpu) + int_in = 0; + repeat (5) @(posedge r_clk_cpu); + $finish(); +end + +initial +begin + $dumpfile("interrupt_controller_tb.vcd"); + $dumpvars(0,interrupt_controller_tb); +end + +endmodule diff --git a/hw/efinix_fpga/src/byte_sel_register.sv b/hw/efinix_fpga/src/byte_sel_register.sv index 7ea3e10..c36c5c0 100644 --- a/hw/efinix_fpga/src/byte_sel_register.sv +++ b/hw/efinix_fpga/src/byte_sel_register.sv @@ -4,6 +4,7 @@ module byte_sel_register parameter ADDR_WIDTH = 32 )( input i_clk, + input i_reset, input i_write, input [$clog2(ADDR_WIDTH)-1:0] i_byte_sel, input [DATA_WIDTH-1:0] i_data, @@ -14,11 +15,16 @@ module byte_sel_register logic [DATA_WIDTH*ADDR_WIDTH-1:0] r_data; assign o_data = r_data[DATA_WIDTH*i_byte_sel +: DATA_WIDTH]; +assign o_full_data = r_data; always_ff @(posedge i_clk) begin - r_data <= r_data; - if (i_write) begin - r_data[DATA_WIDTH*i_byte_sel +: DATA_WIDTH] <= i_data; + if (i_reset) begin + r_data <= '0; + end else begin + r_data <= r_data; + if (i_write) begin + r_data[DATA_WIDTH*i_byte_sel +: DATA_WIDTH] <= i_data; + end end end diff --git a/hw/efinix_fpga/src/interrupt_controller.sv b/hw/efinix_fpga/src/interrupt_controller.sv index f5107bf..571619f 100644 --- a/hw/efinix_fpga/src/interrupt_controller.sv +++ b/hw/efinix_fpga/src/interrupt_controller.sv @@ -12,6 +12,7 @@ module interrupt_controller output logic int_out ); +logic w_enable_write; logic [7:0] w_enable_data; logic [255:0] w_enable_full_data; @@ -24,6 +25,7 @@ byte_sel_register #( .ADDR_WIDTH(32) ) reg_enable ( .i_clk(clk), + .i_reset(reset), .i_write(w_enable_write), .i_byte_sel(w_byte_sel), .i_data(i_data), @@ -31,10 +33,16 @@ byte_sel_register #( .o_full_data(w_enable_full_data) ); +logic we, re; + +assign we = cs & ~rwb; +assign re = cs & rwb; + logic [255:0] int_masked; assign int_masked = int_in & w_enable_full_data; +logic w_type_write; logic [7:0] w_type_data; logic [255:0] w_type_full_data; @@ -43,6 +51,7 @@ byte_sel_register #( .ADDR_WIDTH(32) ) reg_type ( .i_clk(clk), + .i_reset(reset), .i_write(w_type_write), .i_byte_sel(w_byte_sel), .i_data(i_data), @@ -50,6 +59,8 @@ byte_sel_register #( .o_full_data(w_type_full_data) ); +logic [7:0] cmd, cmd_next; + logic w_eoi; logic [255:0] r_int, r_int_next; @@ -59,10 +70,50 @@ always_comb begin if (w_eoi) begin r_int_next[irq_val] = 0; end + + if (addr == '0 && we) begin + cmd_next = i_data; + end else begin + cmd_next = cmd; + end + + + w_type_write = '0; + + if (addr == '1) begin + unique casez (cmd) + 8'h0?: begin + $display("Case 0 not handled"); + end + + 8'h1?: begin + w_enable_write = we; + w_byte_sel = cmd[3:0]; + o_data = w_enable_data; + end + + 8'h2?: begin + w_type_write = we; + w_byte_sel = cmd[3:0]; + o_data = w_type_data; + end + + 8'hff: begin + $display("Not handled"); + end + endcase + end + + int_out = |r_int; end -always_ff @(posedge clk) begin - r_int <= r_int_next; +always_ff @(negedge clk) begin + if (reset) begin + r_int <= '0; + end else begin + r_int <= r_int_next; + cmd <= cmd_next; + end end always_comb begin From 40c54e26c01b4f60f4a245134b74900ca6a50ee1 Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Wed, 15 Nov 2023 08:42:02 -0800 Subject: [PATCH 06/10] Demonstrate basic interrupt functionality --- .../simulation/tbs/interrupt_controller_tb.sv | 3 ++ hw/efinix_fpga/src/interrupt_controller.sv | 30 +++++++++++-------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv b/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv index 0f42817..b457ce2 100644 --- a/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv +++ b/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv @@ -81,6 +81,9 @@ initial begin @(posedge r_clk_cpu) int_in = 0; repeat (5) @(posedge r_clk_cpu); + write_reg(0, 8'hff); + write_reg(1, 8'h01); + repeat (5) @(posedge r_clk_cpu); $finish(); end diff --git a/hw/efinix_fpga/src/interrupt_controller.sv b/hw/efinix_fpga/src/interrupt_controller.sv index 571619f..71b7885 100644 --- a/hw/efinix_fpga/src/interrupt_controller.sv +++ b/hw/efinix_fpga/src/interrupt_controller.sv @@ -66,10 +66,7 @@ logic w_eoi; logic [255:0] r_int, r_int_next; always_comb begin - r_int_next = (~r_int | w_type_full_data) & int_masked; - if (w_eoi) begin - r_int_next[irq_val] = 0; - end + w_eoi = 0; if (addr == '0 && we) begin cmd_next = i_data; @@ -79,6 +76,7 @@ always_comb begin w_type_write = '0; + w_enable_write = '0; if (addr == '1) begin unique casez (cmd) @@ -99,29 +97,35 @@ always_comb begin end 8'hff: begin - $display("Not handled"); + // Kind of dumb, still requires a data write + w_eoi = i_data[0] & we; end endcase end int_out = |r_int; + + irq_val = 8'hff; + for (int i = 255; i >= 0; i--) begin + if (r_int[i] == 1) begin + irq_val = i; + end + end + + r_int_next = (~r_int | w_type_full_data) & int_masked | r_int; + if (w_eoi) begin + r_int_next[irq_val] = 0; + end end always_ff @(negedge clk) begin if (reset) begin r_int <= '0; + cmd <= '0; end else begin r_int <= r_int_next; cmd <= cmd_next; end end -always_comb begin - for (int i = 255; i == 0; i--) begin - if (r_int[i] == 1) begin - irq_val = i; - end - end -end - endmodule \ No newline at end of file From e163e9461fc6bad0645c1703e7e800013c0ab88c Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Wed, 15 Nov 2023 18:46:18 -0800 Subject: [PATCH 07/10] Fix makefile, fix how interrupts are triggered --- hw/efinix_fpga/simulation/Makefile | 10 +++--- .../simulation/tbs/interrupt_controller_tb.sv | 32 +++++++++++++++---- hw/efinix_fpga/src/interrupt_controller.sv | 27 +++++++++++++--- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/hw/efinix_fpga/simulation/Makefile b/hw/efinix_fpga/simulation/Makefile index bb818ae..2d6328d 100644 --- a/hw/efinix_fpga/simulation/Makefile +++ b/hw/efinix_fpga/simulation/Makefile @@ -9,7 +9,7 @@ TEST_PROGRAM_NAME?=loop_test TEST_FOLDER?=$(REPO_TOP)/sw/test_code/$(TEST_PROGRAM_NAME) TEST_PROGRAM?=$(REPO_TOP)/sw/test_code/$(TEST_PROGRAM_NAME)/$(TEST_PROGRAM_NAME).hex -STANDALONE_TB= interrupt_controller_tb mapper_code_tb +STANDALONE_TB= interrupt_controller_tb mapper_code_tb mapper_tb #TODO implement something like sources.list @@ -34,8 +34,8 @@ full_sim: $(TARGET) $(SD_IMAGE) $(STANDALONE_TB): $(SRCS) $(TBS) iverilog -g2005-sv $(FLAGS) -s $@ -o $@ $(INC) $(SRCS) $(TBS) -mapper_code_tb: $(SRCS) $(TBS) $(INIT_MEM) - iverilog -g2005-sv $(FLAGS) -s $@ -o $@ $(INC) $(SRCS) $(TBS) +# mapper_code_tb: $(SRCS) $(TBS) $(INIT_MEM) +# iverilog -g2005-sv $(FLAGS) -s $@ -o $@ $(INC) $(SRCS) $(TBS) $(TARGET): $(INIT_MEM) $(SRCS) @@ -57,5 +57,5 @@ clean: rm -rf $(TARGET) rm -rf $(INIT_MEM) rm -rf $(SD_IMAGE) - rm -rf mapper_tb - rm -rf mapper_tb.vcd + rm -rf $(STANDALONE_TB) + rm -rf *.vcd diff --git a/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv b/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv index b457ce2..08812e1 100644 --- a/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv +++ b/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv @@ -31,7 +31,7 @@ interrupt_controller u_interrupt_controller( .cs(cs), .rwb(rwb), .int_in(int_in), - .int_out(int_out2) + .int_out(int_out) ); /* These should be shared */ @@ -61,7 +61,11 @@ task read_reg(input logic [2:0] _addr, output logic [7:0] _data); rwb <= '1; endtask -initial begin +/* Test Level triggered IRQ by triggering IRQ0 + * and then clearing it, + */ + // TODO this needs to test that it does not trigger after we clear the irq. +task test_edge_irq(); repeat (5) @(posedge r_clk_cpu); reset = 1; cs = 0; @@ -72,18 +76,32 @@ initial begin repeat (5) @(posedge r_clk_cpu); reset = 0; repeat (5) @(posedge r_clk_cpu); - write_reg(0, 8'h10); - write_reg(1, 8'hff); - write_reg(0, 8'h20); - write_reg(1, 8'hff); + write_reg(0, 8'h10); // Enable register + write_reg(1, 8'hff); // 0-7 all enabled + write_reg(0, 8'h20); // Type register + write_reg(1, 8'h00); // 0-7 all level triggered? repeat (5) @(posedge r_clk_cpu); int_in = 1; @(posedge r_clk_cpu) - int_in = 0; + assert (int_out == 1) else begin + $error("Interrupt should be high!"); + end repeat (5) @(posedge r_clk_cpu); write_reg(0, 8'hff); write_reg(1, 8'h01); + @(posedge r_clk_cpu); + assert (int_out == 0) else begin + $error("Interrupt should be low!"); + end + int_in = 0; repeat (5) @(posedge r_clk_cpu); + assert (int_out == 0) else begin + $error("Interrupt should be low!"); + end +endtask + +initial begin + test_edge_irq(); $finish(); end diff --git a/hw/efinix_fpga/src/interrupt_controller.sv b/hw/efinix_fpga/src/interrupt_controller.sv index 71b7885..25b7f82 100644 --- a/hw/efinix_fpga/src/interrupt_controller.sv +++ b/hw/efinix_fpga/src/interrupt_controller.sv @@ -24,7 +24,7 @@ byte_sel_register #( .DATA_WIDTH(8), .ADDR_WIDTH(32) ) reg_enable ( - .i_clk(clk), + .i_clk(~clk), .i_reset(reset), .i_write(w_enable_write), .i_byte_sel(w_byte_sel), @@ -50,7 +50,7 @@ byte_sel_register #( .DATA_WIDTH(8), .ADDR_WIDTH(32) ) reg_type ( - .i_clk(clk), + .i_clk(~clk), .i_reset(reset), .i_write(w_type_write), .i_byte_sel(w_byte_sel), @@ -112,9 +112,26 @@ always_comb begin end end - r_int_next = (~r_int | w_type_full_data) & int_masked | r_int; - if (w_eoi) begin - r_int_next[irq_val] = 0; + for (int i = 0; i < 256; i++) begin + case (w_type_full_data[i]) + 0: begin // Edge triggered + if (w_eoi && i == irq_val) begin + r_int_next[i] = 0; + end else begin + r_int_next[i] = (~r_int[i] & int_masked[i]) | r_int[i]; + end + end + + 1: begin // Level Triggered + // If we are trying to clear this interrupt but it is still active, + // then we don't actually want to clear it. + if (w_eoi && i == irq_val) begin + r_int_next[i] = int_masked[i]; + end else begin + r_int_next[i] = r_int[i]; + end + end + endcase end end From 5d4bad80a21423be0f30b245d3e4e868ceb36c9f Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Thu, 16 Nov 2023 08:12:45 -0800 Subject: [PATCH 08/10] Fix level triggered test, add to ci --- .gitlab-ci.yml | 17 +++++- .../simulation/tbs/interrupt_controller_tb.sv | 58 ++++++++++++++++++- hw/efinix_fpga/src/interrupt_controller.sv | 2 +- 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 826d87d..eb2c7fa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -145,4 +145,19 @@ mapper_code sim: - cd hw/efinix_fpga/simulation - make clean - TEST_PROGRAM_NAME=mapper_test make mapper_code_tb - - ./mapper_code_tb \ No newline at end of file + - ./mapper_code_tb + +interrupt_controller sim: + tags: + - linux + - iverilog + stage: simulate + artifacts: + paths: + - hw/efinix_fpga/simulation/interrupt_controller.vcd + script: + - source init_env.sh + - cd hw/efinix_fpga/simulation + - make clean + - TEST_PROGRAM_NAME=mapper_test make interrupt_controller_tb + - ./interrupt_controller_tb \ No newline at end of file diff --git a/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv b/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv index 08812e1..3276027 100644 --- a/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv +++ b/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv @@ -66,6 +66,7 @@ endtask */ // TODO this needs to test that it does not trigger after we clear the irq. task test_edge_irq(); + $display("Testing Edge IRQ"); repeat (5) @(posedge r_clk_cpu); reset = 1; cs = 0; @@ -84,6 +85,7 @@ task test_edge_irq(); int_in = 1; @(posedge r_clk_cpu) assert (int_out == 1) else begin + errors = errors + 1; $error("Interrupt should be high!"); end repeat (5) @(posedge r_clk_cpu); @@ -91,18 +93,72 @@ task test_edge_irq(); write_reg(1, 8'h01); @(posedge r_clk_cpu); assert (int_out == 0) else begin + errors = errors + 1; $error("Interrupt should be low!"); end int_in = 0; repeat (5) @(posedge r_clk_cpu); + write_reg(0, 8'hff); + write_reg(1, 8'h01); assert (int_out == 0) else begin + errors = errors + 1; $error("Interrupt should be low!"); end endtask +task test_level_irq(); + $display("Testing level IRQ"); + repeat (5) @(posedge r_clk_cpu); + reset = 1; + cs = 0; + rwb = 1; + addr = '0; + i_data = '0; + int_in = '0; + repeat (5) @(posedge r_clk_cpu); + reset = 0; + repeat (5) @(posedge r_clk_cpu); + write_reg(0, 8'h10); // Enable register + write_reg(1, 8'hff); // 0-7 all enabled + write_reg(0, 8'h20); // Type register + write_reg(1, 8'hff); // 0-7 all level triggered? + repeat (5) @(posedge r_clk_cpu); + int_in = 1; + @(posedge r_clk_cpu) + assert (int_out == 1) else begin + errors = errors + 1; + $error("Interrupt should be high!"); + end + repeat (5) @(posedge r_clk_cpu); + write_reg(0, 8'hff); + write_reg(1, 8'h01); + @(posedge r_clk_cpu); + assert (int_out == 1) else begin + errors = errors + 1; + $error("Interrupt should be high!"); + end + int_in = 0; + repeat (5) @(posedge r_clk_cpu); + write_reg(0, 8'hff); + write_reg(1, 8'h01); + @(posedge r_clk_cpu); + repeat (5) @(posedge r_clk_cpu) + assert (int_out == 0) else begin + errors = errors + 1; + $error("Interrupt should be low!"); + end +endtask + +int errors; + initial begin + errors = 0; test_edge_irq(); - $finish(); + test_level_irq(); + if (errors > 0) + $finish_and_return(-1); + else + $finish(); end initial diff --git a/hw/efinix_fpga/src/interrupt_controller.sv b/hw/efinix_fpga/src/interrupt_controller.sv index 25b7f82..eee3aff 100644 --- a/hw/efinix_fpga/src/interrupt_controller.sv +++ b/hw/efinix_fpga/src/interrupt_controller.sv @@ -128,7 +128,7 @@ always_comb begin if (w_eoi && i == irq_val) begin r_int_next[i] = int_masked[i]; end else begin - r_int_next[i] = r_int[i]; + r_int_next[i] = r_int[i] | int_masked[i]; end end endcase From b259d7f0845173e5419be70f97e9c1e629824caa Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Thu, 16 Nov 2023 18:28:48 -0800 Subject: [PATCH 09/10] Fix edge trigger, reorganize testbench --- .../simulation/tbs/interrupt_controller_tb.sv | 160 +++++++++--------- hw/efinix_fpga/src/interrupt_controller.sv | 6 +- 2 files changed, 85 insertions(+), 81 deletions(-) diff --git a/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv b/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv index 3276027..cee9f5a 100644 --- a/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv +++ b/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv @@ -34,72 +34,25 @@ interrupt_controller u_interrupt_controller( .int_out(int_out) ); -/* These should be shared */ -task write_reg(input logic [4:0] _addr, input logic [7:0] _data); - @(negedge r_clk_cpu); - cs <= '1; - addr <= _addr; - rwb <= '0; - i_data <= '1; - @(posedge r_clk_cpu); - i_data <= _data; - @(negedge r_clk_cpu); - cs <= '0; - rwb <= '1; -endtask - -task read_reg(input logic [2:0] _addr, output logic [7:0] _data); - @(negedge r_clk_cpu); - cs <= '1; - addr <= _addr; - rwb <= '1; - i_data <= '1; - @(posedge r_clk_cpu); - _data <= o_data; - @(negedge r_clk_cpu); - cs <= '0; - rwb <= '1; -endtask - /* Test Level triggered IRQ by triggering IRQ0 * and then clearing it, */ - // TODO this needs to test that it does not trigger after we clear the irq. task test_edge_irq(); $display("Testing Edge IRQ"); - repeat (5) @(posedge r_clk_cpu); - reset = 1; - cs = 0; - rwb = 1; - addr = '0; - i_data = '0; - int_in = '0; - repeat (5) @(posedge r_clk_cpu); - reset = 0; - repeat (5) @(posedge r_clk_cpu); - write_reg(0, 8'h10); // Enable register - write_reg(1, 8'hff); // 0-7 all enabled - write_reg(0, 8'h20); // Type register - write_reg(1, 8'h00); // 0-7 all level triggered? - repeat (5) @(posedge r_clk_cpu); - int_in = 1; - @(posedge r_clk_cpu) + do_reset(); + set_enable(255'hff); + set_edge_type(255'h0); + set_interrupts(1); assert (int_out == 1) else begin errors = errors + 1; $error("Interrupt should be high!"); end - repeat (5) @(posedge r_clk_cpu); - write_reg(0, 8'hff); - write_reg(1, 8'h01); - @(posedge r_clk_cpu); + send_eoi(); assert (int_out == 0) else begin errors = errors + 1; $error("Interrupt should be low!"); end - int_in = 0; - repeat (5) @(posedge r_clk_cpu); - write_reg(0, 8'hff); - write_reg(1, 8'h01); + set_interrupts(0); assert (int_out == 0) else begin errors = errors + 1; $error("Interrupt should be low!"); @@ -108,41 +61,21 @@ endtask task test_level_irq(); $display("Testing level IRQ"); - repeat (5) @(posedge r_clk_cpu); - reset = 1; - cs = 0; - rwb = 1; - addr = '0; - i_data = '0; - int_in = '0; - repeat (5) @(posedge r_clk_cpu); - reset = 0; - repeat (5) @(posedge r_clk_cpu); - write_reg(0, 8'h10); // Enable register - write_reg(1, 8'hff); // 0-7 all enabled - write_reg(0, 8'h20); // Type register - write_reg(1, 8'hff); // 0-7 all level triggered? - repeat (5) @(posedge r_clk_cpu); - int_in = 1; - @(posedge r_clk_cpu) + do_reset(); + set_enable(255'hff); + set_edge_type(255'hff); + set_interrupts(1); assert (int_out == 1) else begin errors = errors + 1; $error("Interrupt should be high!"); end - repeat (5) @(posedge r_clk_cpu); - write_reg(0, 8'hff); - write_reg(1, 8'h01); - @(posedge r_clk_cpu); + send_eoi(); assert (int_out == 1) else begin errors = errors + 1; $error("Interrupt should be high!"); end - int_in = 0; - repeat (5) @(posedge r_clk_cpu); - write_reg(0, 8'hff); - write_reg(1, 8'h01); - @(posedge r_clk_cpu); - repeat (5) @(posedge r_clk_cpu) + set_interrupts(0); + send_eoi(); assert (int_out == 0) else begin errors = errors + 1; $error("Interrupt should be low!"); @@ -167,4 +100,71 @@ begin $dumpvars(0,interrupt_controller_tb); end +/* These should be shared */ +task write_reg(input logic [4:0] _addr, input logic [7:0] _data); + @(negedge r_clk_cpu); + cs <= '1; + addr <= _addr; + rwb <= '0; + i_data <= '1; + @(posedge r_clk_cpu); + i_data <= _data; + @(negedge r_clk_cpu); + cs <= '0; + rwb <= '1; + @(posedge r_clk_cpu); +endtask + +task read_reg(input logic [2:0] _addr, output logic [7:0] _data); + @(negedge r_clk_cpu); + cs <= '1; + addr <= _addr; + rwb <= '1; + i_data <= '1; + @(posedge r_clk_cpu); + _data <= o_data; + @(negedge r_clk_cpu); + cs <= '0; + rwb <= '1; + @(posedge r_clk_cpu); +endtask + +task do_reset(); + repeat (5) @(posedge r_clk_cpu); + reset = 1; + cs = 0; + rwb = 1; + addr = '0; + i_data = '0; + int_in = '0; + repeat (5) @(posedge r_clk_cpu); + reset = 0; + repeat (5) @(posedge r_clk_cpu); +endtask + +task set_enable(input logic [255:0] en); + for (int i = 0; i < 16; i++) begin + write_reg(0, 8'h10 | i); + write_reg(1, en[8*i +: 8]); + end +endtask + +task set_edge_type(input logic [255:0] edge_type); + for (int i = 0; i < 16; i++) begin + write_reg(0, 8'h20 | i); + write_reg(1, edge_type[8*i +: 8]); + end +endtask + +task set_interrupts(logic [255:0] ints); + int_in = ints; + @(posedge r_clk_cpu); +endtask + +task send_eoi(); + write_reg(0, 8'hff); + write_reg(1, 8'h01); +endtask + + endmodule diff --git a/hw/efinix_fpga/src/interrupt_controller.sv b/hw/efinix_fpga/src/interrupt_controller.sv index eee3aff..6d9a9e1 100644 --- a/hw/efinix_fpga/src/interrupt_controller.sv +++ b/hw/efinix_fpga/src/interrupt_controller.sv @@ -16,6 +16,8 @@ logic w_enable_write; logic [7:0] w_enable_data; logic [255:0] w_enable_full_data; +logic [255:0] int_in_d1; + logic [4:0] w_byte_sel; logic [7:0] irq_val; @@ -118,7 +120,7 @@ always_comb begin if (w_eoi && i == irq_val) begin r_int_next[i] = 0; end else begin - r_int_next[i] = (~r_int[i] & int_masked[i]) | r_int[i]; + r_int_next[i] = (~int_in_d1[i] & int_masked[i]) | r_int[i]; end end @@ -139,9 +141,11 @@ always_ff @(negedge clk) begin if (reset) begin r_int <= '0; cmd <= '0; + int_in_d1 <= '0; end else begin r_int <= r_int_next; cmd <= cmd_next; + int_in_d1 <= int_in; end end From 27066a7ace629699a89e8f7282135cd76112d9e4 Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Thu, 16 Nov 2023 18:54:25 -0800 Subject: [PATCH 10/10] Test interrupt priority --- .../simulation/tbs/interrupt_controller_tb.sv | 48 +++++++++++++++++-- hw/efinix_fpga/src/interrupt_controller.sv | 12 ++--- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv b/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv index cee9f5a..a234f5f 100644 --- a/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv +++ b/hw/efinix_fpga/simulation/tbs/interrupt_controller_tb.sv @@ -4,6 +4,8 @@ module interrupt_controller_tb(); logic r_clk_cpu; +localparam BITS_256 = 256'hffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; + // clk_cpu initial begin r_clk_cpu <= '1; @@ -82,12 +84,43 @@ task test_level_irq(); end endtask -int errors; +task test_irq_val(); + int irq_val = -1; + $display("Testing IRQ val output"); + do_reset(); + set_enable('1); + set_edge_type('1); + for (int i = 255; i >= 0; i--) begin + set_interrupts(BITS_256 << i); + read_irqval(irq_val); + assert(i == irq_val) else begin + errors = errors + 1; + $display("Expected %d got %d", i, irq_val); + end + end + + for (int i = 0; i < 256; i++) begin + set_interrupts(BITS_256 >> i); + read_irqval(irq_val); + assert(int_out == 1) else begin + errors = errors + 1; + $display("int_out should be asserted!"); + end + assert(0 == irq_val) else begin + errors = errors + 1; + $display("Expected %d got %d", i, irq_val); + end + end + +endtask + +int errors; initial begin errors = 0; test_edge_irq(); test_level_irq(); + test_irq_val(); if (errors > 0) $finish_and_return(-1); else @@ -143,15 +176,15 @@ task do_reset(); endtask task set_enable(input logic [255:0] en); - for (int i = 0; i < 16; i++) begin - write_reg(0, 8'h10 | i); + for (int i = 0; i < 32; i++) begin + write_reg(0, 8'h20 | i); write_reg(1, en[8*i +: 8]); end endtask task set_edge_type(input logic [255:0] edge_type); - for (int i = 0; i < 16; i++) begin - write_reg(0, 8'h20 | i); + for (int i = 0; i < 32; i++) begin + write_reg(0, 8'h40 | i); write_reg(1, edge_type[8*i +: 8]); end endtask @@ -166,5 +199,10 @@ task send_eoi(); write_reg(1, 8'h01); endtask +task read_irqval(output logic [7:0] _irq_val); + write_reg(0, 8'h00); + read_reg(1, _irq_val); +endtask + endmodule diff --git a/hw/efinix_fpga/src/interrupt_controller.sv b/hw/efinix_fpga/src/interrupt_controller.sv index 6d9a9e1..7f54f31 100644 --- a/hw/efinix_fpga/src/interrupt_controller.sv +++ b/hw/efinix_fpga/src/interrupt_controller.sv @@ -82,19 +82,19 @@ always_comb begin if (addr == '1) begin unique casez (cmd) - 8'h0?: begin - $display("Case 0 not handled"); + 8'b000?????: begin + o_data = irq_val; end - 8'h1?: begin + 8'b001?????: begin w_enable_write = we; - w_byte_sel = cmd[3:0]; + w_byte_sel = cmd[4:0]; o_data = w_enable_data; end - 8'h2?: begin + 8'b010?????: begin w_type_write = we; - w_byte_sel = cmd[3:0]; + w_byte_sel = cmd[4:0]; o_data = w_type_data; end