diff --git a/hw/application_fpga/core/tk1/rtl/tk1.v b/hw/application_fpga/core/tk1/rtl/tk1.v index eb31549..1f524f6 100644 --- a/hw/application_fpga/core/tk1/rtl/tk1.v +++ b/hw/application_fpga/core/tk1/rtl/tk1.v @@ -45,6 +45,8 @@ module tk1 #( output wire gpio3, output wire gpio4, + input wire syscall, + input wire cs, input wire we, input wire [ 7 : 0] address, @@ -448,7 +450,17 @@ module tk1 #( end // In unused space - if ((cpu_addr[29 : 24] > 6'h10) && (cpu_addr[29 : 24] < 6'h3f)) begin + if ((cpu_addr[29 : 24] > 6'h10) && (cpu_addr[29 : 24] < 6'h21)) begin + force_trap_set = 1'h1; + end + + // Outside SYSCALL + if (cpu_addr[29 : 24] == 6'h21 & |cpu_addr[23 : 2]) begin + force_trap_set = 1'h1; + end + + // In unused space + if ((cpu_addr[29 : 24] > 6'h21) && (cpu_addr[29 : 24] < 6'h3f)) begin force_trap_set = 1'h1; end diff --git a/hw/application_fpga/core/tk1/tb/tb_tk1.v b/hw/application_fpga/core/tk1/tb/tb_tk1.v index e74dfbb..617b644 100644 --- a/hw/application_fpga/core/tk1/tb/tb_tk1.v +++ b/hw/application_fpga/core/tk1/tb/tb_tk1.v @@ -878,6 +878,17 @@ module tb_tk1 (); // Unused trap range: 0xd1000000-0xfeffffff $display("--- test11: Unused"); cpu_read_check_range_should_trap(32'hd1000000, 32'hd100000f); + cpu_read_check_range_should_trap(32'he0fffff0, 32'he0ffffff); + + // SYSCALL trap range. 0xe1000004-0xe1ffffff + $display("--- test11: SYSCALL"); + cpu_read_check_range_should_not_trap(32'he1000000, 32'he1000003); + cpu_read_check_range_should_trap(32'he1000004, 32'he100000f); + cpu_read_check_range_should_trap(32'he1fffff0, 32'he1ffffff); + + // Unused trap range: 0xe2000000-0xfeffffff + $display("--- test11: Unused"); + cpu_read_check_range_should_trap(32'he2000000, 32'he200000f); cpu_read_check_range_should_trap(32'hfefffff0, 32'hfeffffff); // TK1 trap range: 0xff000400-0xffffffff diff --git a/hw/application_fpga/rtl/application_fpga.v b/hw/application_fpga/rtl/application_fpga.v index 09c1ecb..45ef32f 100644 --- a/hw/application_fpga/rtl/application_fpga.v +++ b/hw/application_fpga/rtl/application_fpga.v @@ -57,11 +57,13 @@ module application_fpga ( localparam UART_PREFIX = 6'h03; localparam TOUCH_SENSE_PREFIX = 6'h04; localparam FW_RAM_PREFIX = 6'h10; + localparam SYSCALL_PREFIX = 6'h21; localparam TK1_PREFIX = 6'h3f; // Instruction used to cause a trap. localparam ILLEGAL_INSTRUCTION = 32'h0; + localparam IRQ31_IRQ_MASK = 2 ** 31; //---------------------------------------------------------------- // Registers, memories with associated wires. @@ -80,11 +82,13 @@ module application_fpga ( wire reset_n; /* verilator lint_off UNOPTFLAT */ + reg [31 : 0] cpu_irq; wire cpu_trap; wire cpu_valid; wire cpu_instr; wire [03 : 0] cpu_wstrb; /* verilator lint_off UNUSED */ + wire [31 : 0] cpu_eoi; wire [31 : 0] cpu_addr; wire [31 : 0] cpu_wdata; @@ -139,6 +143,10 @@ module application_fpga ( wire [31 : 0] touch_sense_read_data; wire touch_sense_ready; + reg irq31_cs; + reg irq31_we; + reg irq31_eoi; + reg tk1_cs; reg tk1_we; reg [ 7 : 0] tk1_address; @@ -166,12 +174,17 @@ module application_fpga ( picorv32 #( - .ENABLE_COUNTERS(0), - .TWO_STAGE_SHIFT(0), - .CATCH_MISALIGN (0), - .COMPRESSED_ISA (1), - .ENABLE_FAST_MUL(1), - .BARREL_SHIFTER (1) + .ENABLE_COUNTERS (0), + .TWO_STAGE_SHIFT (0), + .CATCH_MISALIGN (0), + .COMPRESSED_ISA (1), + .ENABLE_FAST_MUL (1), + .BARREL_SHIFTER (1), + .ENABLE_IRQ (1), + .ENABLE_IRQ_QREGS(0), + .ENABLE_IRQ_TIMER(0), + .MASKED_IRQ (~IRQ31_IRQ_MASK), + .LATCHED_IRQ (IRQ31_IRQ_MASK) ) cpu ( .clk(clk), .resetn(reset_n), @@ -185,11 +198,12 @@ module application_fpga ( .mem_rdata(muxed_rdata_reg), .mem_instr(cpu_instr), + .irq(cpu_irq), + .eoi(cpu_eoi), + // Defined unused ports. Makes lint happy. But // we still needs to help lint with empty ports. /* verilator lint_off PINCONNECTEMPTY */ - .irq(32'h0), - .eoi(), .trace_valid(), .trace_data(), .mem_la_read(), @@ -353,6 +367,8 @@ module application_fpga ( .gpio3(app_gpio3), .gpio4(app_gpio4), + .syscall(irq31_eoi), + .cs(tk1_cs), .we(tk1_we), .address(tk1_address), @@ -379,6 +395,20 @@ module application_fpga ( end + //---------------------------------------------------------------- + // irq_ctrl + // Interrupt logic + //---------------------------------------------------------------- + always @* begin : irq_ctrl + reg irq31_set; + + irq31_set = irq31_cs & irq31_we; + cpu_irq = {irq31_set, 31'h0}; + + irq31_eoi = cpu_eoi[31]; + end + + //---------------------------------------------------------------- // cpu_mem_ctrl // CPU memory decode and control logic. @@ -428,6 +458,9 @@ module application_fpga ( touch_sense_we = |cpu_wstrb; touch_sense_address = cpu_addr[9 : 2]; + irq31_cs = 1'h0; + irq31_we = |cpu_wstrb; + tk1_cs = 1'h0; tk1_we = |cpu_wstrb; tk1_address = cpu_addr[9 : 2]; @@ -500,6 +533,11 @@ module application_fpga ( muxed_ready_new = fw_ram_ready; end + SYSCALL_PREFIX: begin + irq31_cs = 1'h1; + muxed_ready_new = 1'h1; + end + TK1_PREFIX: begin tk1_cs = 1'h1; muxed_rdata_new = tk1_read_data; diff --git a/hw/application_fpga/tb/application_fpga_sim.v b/hw/application_fpga/tb/application_fpga_sim.v index f2d4b33..e8fbf0a 100644 --- a/hw/application_fpga/tb/application_fpga_sim.v +++ b/hw/application_fpga/tb/application_fpga_sim.v @@ -70,11 +70,13 @@ module application_fpga_sim ( localparam UART_PREFIX = 6'h03; localparam TOUCH_SENSE_PREFIX = 6'h04; localparam FW_RAM_PREFIX = 6'h10; + localparam SYSCALL_PREFIX = 6'h21; localparam TK1_PREFIX = 6'h3f; // Instruction used to cause a trap. localparam ILLEGAL_INSTRUCTION = 32'h0; + localparam IRQ31_IRQ_MASK = 2 ** 31; //---------------------------------------------------------------- // Registers, memories with associated wires. @@ -92,11 +94,13 @@ module application_fpga_sim ( wire reset_n; /* verilator lint_off UNOPTFLAT */ + reg [31 : 0] cpu_irq; wire cpu_trap; wire cpu_valid; wire cpu_instr; wire [ 3 : 0] cpu_wstrb; /* verilator lint_off UNUSED */ + wire [31 : 0] cpu_eoi; wire [31 : 0] cpu_addr; wire [31 : 0] cpu_wdata; @@ -151,6 +155,10 @@ module application_fpga_sim ( wire [31 : 0] touch_sense_read_data; wire touch_sense_ready; + reg irq31_cs; + reg irq31_we; + reg irq31_eoi; + reg tk1_cs; reg tk1_we; reg [ 7 : 0] tk1_address; @@ -177,12 +185,17 @@ module application_fpga_sim ( picorv32 #( - .ENABLE_COUNTERS(0), - .TWO_STAGE_SHIFT(0), - .CATCH_MISALIGN (0), - .COMPRESSED_ISA (1), - .ENABLE_FAST_MUL(1), - .BARREL_SHIFTER (1) + .ENABLE_COUNTERS (0), + .TWO_STAGE_SHIFT (0), + .CATCH_MISALIGN (0), + .COMPRESSED_ISA (1), + .ENABLE_FAST_MUL (1), + .BARREL_SHIFTER (1), + .ENABLE_IRQ (1), + .ENABLE_IRQ_QREGS(0), + .ENABLE_IRQ_TIMER(0), + .MASKED_IRQ (~IRQ31_IRQ_MASK), + .LATCHED_IRQ (IRQ31_IRQ_MASK) ) cpu ( .clk(clk), .resetn(reset_n), @@ -196,11 +209,12 @@ module application_fpga_sim ( .mem_rdata(muxed_rdata_reg), .mem_instr(cpu_instr), + .irq(cpu_irq), + .eoi(cpu_eoi), + // Defined unused ports. Makes lint happy. But // we still needs to help lint with empty ports. /* verilator lint_off PINCONNECTEMPTY */ - .irq(32'h0), - .eoi(), .trace_valid(), .trace_data(), .mem_la_read(), @@ -366,6 +380,8 @@ module application_fpga_sim ( .gpio3(app_gpio3), .gpio4(app_gpio4), + .syscall(irq31_eoi), + .cs(tk1_cs), .we(tk1_we), .address(tk1_address), @@ -391,6 +407,20 @@ module application_fpga_sim ( end + //---------------------------------------------------------------- + // irq_ctrl + // Interrupt logic + //---------------------------------------------------------------- + always @* begin : irq_ctrl + reg irq31_set; + + irq31_set = irq31_cs & irq31_we; + cpu_irq = {irq31_set, 31'h0}; + + irq31_eoi = cpu_eoi[31]; + end + + //---------------------------------------------------------------- // cpu_mem_ctrl // CPU memory decode and control logic. @@ -442,6 +472,9 @@ module application_fpga_sim ( touch_sense_we = |cpu_wstrb; touch_sense_address = cpu_addr[9 : 2]; + irq31_cs = 1'h0; + irq31_we = |cpu_wstrb; + tk1_cs = 1'h0; tk1_we = |cpu_wstrb; tk1_address = cpu_addr[9 : 2]; @@ -534,6 +567,13 @@ module application_fpga_sim ( muxed_ready_new = fw_ram_ready; end + SYSCALL_PREFIX: begin + `verbose($display("Access to syscall interrupt trigger");) + ascii_state = "Syscall IRQ trigger"; + irq31_cs = 1'h1; + muxed_ready_new = 1'h1; + end + TK1_PREFIX: begin `verbose($display("Access to TK1 core");) ascii_state = "TK1 core";