diff --git a/README.md b/README.md index 41aa7d885..075c6ae5f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Ariane RISC-V CPU -Ariane is a 6-stage, single issue, in-order CPU which implements the 64-bit RISC-V instruction set. It fully implements I, M and C extensions as specified in Volume I: User-Level ISA V 2.1 as well as the draft privilege extension 1.10. It implements three privilege levels M, S, U to fully support a Unix-like operating system. Furthermore it is compliant to the draft external debug spec 0.13. +Ariane is a 6-stage, single issue, in-order CPU which implements the 64-bit RISC-V instruction set. It fully implements I, M, A and C extensions as specified in Volume I: User-Level ISA V 2.1 as well as the draft privilege extension 1.10. It implements three privilege levels M, S, U to fully support a Unix-like operating system. Furthermore it is compliant to the draft external debug spec 0.13. It has configurable size, separate TLBs, a hardware PTW and branch-prediction (branch target buffer and branch history table). The primary design goal was on reducing critical path length. @@ -92,16 +92,16 @@ If you call `simc` instead of `sim` it will run without the GUI. QuestaSim uses ### CI Testsuites and Randomized Constrained Testing with Torture -We provide two CI configuration files for Travis CI and GitLab CI that run the RISCV assembly tests, the RISCV benchmarks and a randomized RISCV Torture test. The difference between the two is that Travis CI runs these tests only on Verilator, whereas GitLab CI runs the same tests on QuestaSim and Verilator. +We provide two CI configuration files for Travis CI and GitLab CI that run the RISCV assembly tests, the RISCV benchmarks and a randomized RISCV Torture test. The difference between the two is that Travis CI runs these tests only on Verilator, whereas GitLab CI runs the same tests on QuestaSim and Verilator. -If you would like to run the CI test suites locally on your machine, follow any of the two scripts `ci.travis-ci-emul.sh` and `ci.travis-ci-emul.sh` (depending on whether you have QuestaSim or not). In particular, you have to get the required packages for your system, the paths in `ci/path-setup.sh` to match your setup, and run the installation and build scripts prior to running any of the tests suites. +If you would like to run the CI test suites locally on your machine, follow any of the two scripts `ci.travis-ci-emul.sh` and `ci.travis-ci-emul.sh` (depending on whether you have QuestaSim or not). In particular, you have to get the required packages for your system, the paths in `ci/path-setup.sh` to match your setup, and run the installation and build scripts prior to running any of the tests suites. Once everything is set up and installed, you can run the tests suites as follows (using Verilator): ``` -$ make verilate -$ make run-asm-tests-verilator -$ make run-benchmarks-verilator +$ make verilate +$ make run-asm-tests-verilator +$ make run-benchmarks-verilator ``` In order to run randomized Torture tests, you first have to generate the randomized program prior to running the simulation: @@ -111,7 +111,7 @@ $ make torture-gen $ make torture-rtest-verilator ``` -This runs the randomized program on Spike and on the RTL target, and checks whether the two signatures match. The random instruction mix can be configured in the `./tmp/riscv-torture/config/default.config` file. +This runs the randomized program on Spike and on the RTL target, and checks whether the two signatures match. The random instruction mix can be configured in the `./tmp/riscv-torture/config/default.config` file. # Contributing diff --git a/include/ariane_pkg.sv b/include/ariane_pkg.sv index 9e1366da3..62d6b31b3 100644 --- a/include/ariane_pkg.sv +++ b/include/ariane_pkg.sv @@ -32,7 +32,9 @@ package ariane_pkg; localparam BITS_SATURATION_COUNTER = 2; localparam NR_COMMIT_PORTS = 2; - localparam logic [63:0] ISA_CODE = (1 << 2) // C - Compressed extension + localparam logic [63:0] ISA_CODE = + | (1 << 0) // A - Atomic extension + | (1 << 2) // C - Compressed extension | (1 << 8) // I - RV32I/64I/128I base ISA | (1 << 12) // M - Integer Multiply/Divide extension | (0 << 13) // N - User level interrupts supported @@ -218,7 +220,7 @@ package ariane_pkg; endcase endfunction - function automatic logic is_amo_op (fu_op op); + function automatic logic is_amo (fu_op op); case (op) AMO_LRD, AMO_SCD, AMO_SWAPD, AMO_ADDD, diff --git a/src/amo_buffer.sv b/src/amo_buffer.sv new file mode 100644 index 000000000..9487589a6 --- /dev/null +++ b/src/amo_buffer.sv @@ -0,0 +1,82 @@ +// Copyright 2018 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. +// +// Author: Florian Zaruba, ETH Zurich +// Date: 20.09.2018 +// Description: Buffers AMO requests +// This unit buffers an atomic memory operations for the cache subsyste. +// Furthermore it handles interfacing with the commit stage + +module amo_buffer ( + input logic clk_i, // Clock + input logic rst_ni, // Asynchronous reset active low + input logic flush_i, // pipeline flush + + input logic valid_i, // AMO is valid + output logic ready_o, // AMO unit is ready + input ariane_pkg::amo_t amo_op_i, // AMO Operation + input logic [63:0] paddr_i, // physical address of store which needs to be placed in the queue + input logic [63:0] data_i, // data which is placed in the queue + input logic [1:0] data_size_i, // type of request we are making (e.g.: bytes to write) + // D$ + output ariane_pkg::amo_req_t amo_req_o, // request to cache subsytem + input ariane_pkg::amo_resp_t amo_resp_i, // response from cache subsystem + // Auxiliary signals + input logic amo_valid_commit_i, // We have a vaild AMO in the commit stage + input logic no_st_pending_i // there is currently no store pending anymore +); + logic flush_amo_buffer; + + typedef struct packed { + ariane_pkg::amo_t op; + logic [63:0] paddr; + logic [63:0] data; + logic [1:0] size; + } amo_op_t ; + + amo_op_t amo_data_in, amo_data_out; + + // validate this request as soon as all stores have drained and the AMO is in the commit stage + assign amo_req_o.req = no_st_pending_i & amo_valid_commit_i; + assign amo_req_o.amo_op = amo_data_out.op; + assign amo_req_o.size = amo_data_out.size; + assign amo_req_o.operand_a = amo_data_out.paddr; + assign amo_req_o.operand_b = amo_data_out.data; + + assign amo_data_in.op = amo_op_i; + assign amo_data_in.data = data_i; + assign amo_data_in.paddr = paddr_i; + assign amo_data_in.size = data_size_i; + + // only flush if we are currently not committing the AMO + // e.g.: it is not speculative anymore + assign flush_amo_buffer = flush_i & !amo_valid_commit_i; + + fifo_v2 #( + .DEPTH ( 1 ), + .ALM_EMPTY_TH ( 0 ), + .ALM_FULL_TH ( 0 ), + .dtype ( amo_op_t ) + ) i_amo_fifo ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .flush_i ( flush_amo_buffer ), + .testmode_i ( 1'b0 ), + .full_o ( ), // not used as this FIFO has only a single element depth + .empty_o ( ready_o ), + .alm_full_o ( ), // left open + .alm_empty_o ( ), // left open + .data_i ( amo_data_in ), + .push_i ( valid_i ), + .data_o ( amo_data_out ), + .pop_i ( amo_resp_i.ack ) + ); + +endmodule \ No newline at end of file diff --git a/src/ariane.sv b/src/ariane.sv index 4ebbea885..f763370f6 100644 --- a/src/ariane.sv +++ b/src/ariane.sv @@ -129,6 +129,7 @@ module ariane #( logic lsu_commit_commit_ex; logic lsu_commit_ready_ex_commit; logic no_st_pending_ex_commit; + logic amo_valid_commit; // -------------- // ID <-> COMMIT // -------------- @@ -196,6 +197,14 @@ module ariane #( icache_areq_o_t icache_areq_cache_ex; icache_dreq_i_t icache_dreq_if_cache; icache_dreq_o_t icache_dreq_cache_if; + + amo_req_t amo_req; + amo_resp_t amo_resp; + + logic debug_req; + // Disable debug during AMO commit + assign debug_req = debug_req_i & ~amo_valid_commit; + // ---------------- // DCache <-> * // ---------------- @@ -344,6 +353,9 @@ module ariane #( .lsu_commit_ready_o ( lsu_commit_ready_ex_commit ), // to commit .lsu_exception_o ( lsu_exception_ex_id ), .no_st_pending_o ( no_st_pending_ex_commit ), + .amo_valid_commit_i ( amo_valid_commit ), + .amo_req_o ( amo_req ), + .amo_resp_i ( amo_resp ), // CSR .csr_ready_o ( csr_ready_ex_id ), .csr_valid_i ( csr_valid_id_ex ), @@ -389,7 +401,7 @@ module ariane #( .flush_dcache_i ( dcache_flush_ctrl_cache ), .exception_o ( ex_commit ), .debug_mode_i ( debug_mode_csr_id ), - .debug_req_i ( debug_req_i ), + .debug_req_i ( debug_req ), .single_step_i ( single_step_csr_commit ), .commit_instr_i ( commit_instr_id_commit ), .commit_ack_o ( commit_ack ), @@ -397,11 +409,10 @@ module ariane #( .waddr_o ( waddr_commit_id ), .wdata_o ( wdata_commit_id ), .we_o ( we_commit_id ), - .amo_commit_o ( ), - .amo_valid_i ( ), - .amo_sc_succ_i ( ), .commit_lsu_o ( lsu_commit_commit_ex ), .commit_lsu_ready_i ( lsu_commit_ready_ex_commit ), + .amo_valid_commit_o ( amo_valid_commit ), + .amo_resp_i ( amo_resp ), .commit_csr_o ( csr_commit_commit_ex ), .pc_o ( pc_commit ), .csr_op_o ( csr_op_commit_csr ), @@ -422,8 +433,8 @@ module ariane #( ) csr_regfile_i ( .flush_o ( flush_csr_ctrl ), .halt_csr_o ( halt_csr_ctrl ), - .commit_ack_i ( commit_ack ), .commit_instr_i ( commit_instr_id_commit ), + .commit_ack_i ( commit_ack ), .ex_i ( ex_commit ), .csr_op_i ( csr_op_commit_csr ), .csr_addr_i ( csr_addr_ex_csr ), @@ -454,6 +465,10 @@ module ariane #( .perf_data_o ( data_csr_perf ), .perf_data_i ( data_perf_csr ), .perf_we_o ( we_csr_perf ), + .debug_req_i ( debug_req ), + .ipi_i, + .irq_i, + .time_irq_i, .* ); @@ -531,10 +546,8 @@ module ariane #( .dcache_flush_i ( dcache_flush_ctrl_cache ), .dcache_flush_ack_o ( dcache_flush_ack_cache_ctrl ), // to commit stage - .dcache_amo_commit_i ( amo_commit ), - .dcache_amo_valid_o ( amo_valid ), - .dcache_amo_sc_succ_o ( amo_sc_succ ), - .dcache_amo_flush_i ( amo_flush ), + .amo_req_i ( amo_req ), + .amo_resp_o ( amo_resp ), .dcache_miss_o ( dcache_miss_cache_perf ), // from PTW, Load Unit and Store Unit .dcache_req_ports_i ( dcache_req_ports_ex_cache ), diff --git a/src/cache_subsystem/std_nbdcache.sv b/src/cache_subsystem/std_nbdcache.sv index 7ec8376de..caff9d88a 100644 --- a/src/cache_subsystem/std_nbdcache.sv +++ b/src/cache_subsystem/std_nbdcache.sv @@ -36,6 +36,8 @@ module std_nbdcache #( AXI_BUS.Master bypass_if ); + assign amo_resp_o = '0; + // ------------------------------- // Controller <-> Arbiter // ------------------------------- diff --git a/src/commit_stage.sv b/src/commit_stage.sv index 47bc6e565..f0ed83257 100644 --- a/src/commit_stage.sv +++ b/src/commit_stage.sv @@ -45,6 +45,7 @@ module commit_stage #( // commit signals to ex output logic commit_lsu_o, // commit the pending store input logic commit_lsu_ready_i, // commit buffer of LSU is ready + output logic amo_valid_commit_o, // valid AMO in commit stage input logic no_st_pending_i, // there is no store pending output logic commit_csr_o, // commit the pending CSR instruction output logic fence_i_o, // flush I$ and pipeline @@ -52,6 +53,9 @@ module commit_stage #( output logic sfence_vma_o // flush TLBs and pipeline ); + assign waddr_o[0] = commit_instr_i[0].rd[4:0]; + assign waddr_o[1] = commit_instr_i[1].rd[4:0]; + assign pc_o = commit_instr_i[0].pc; // ------------------- @@ -63,6 +67,8 @@ module commit_stage #( commit_ack_o[0] = 1'b0; commit_ack_o[1] = 1'b0; + amo_valid_commit_o = 1'b0; + we_o[0] = 1'b0; we_o[1] = 1'b0; @@ -145,6 +151,14 @@ module commit_stage #( // tell the controller to flush the D$ fence_o = no_st_pending_i; end + // ------------------ + // AMO + // ------------------ + if (is_amo(commit_instr_i[0].op)) begin + // TODO(zarubaf): Flush pipeline + amo_valid_commit_o = 1'b1; + commit_ack_o[0] = amo_resp_i.ack; + end end // ----------------- @@ -210,8 +224,10 @@ module commit_stage #( exception_o.tval = commit_instr_i[0].ex.tval; end end - // If we halted the processor don't take any exceptions - if (halt_i) begin + // Don't take any exceptions iff: + // - If we halted the processor + // - We are committing an AMO + if (halt_i || amo_valid_commit_o) begin exception_o.valid = 1'b0; end end diff --git a/src/controller.sv b/src/controller.sv index 0fbb1e2a8..30efb8173 100644 --- a/src/controller.sv +++ b/src/controller.sv @@ -126,7 +126,6 @@ module controller ( flush_if_o = 1'b1; flush_unissued_instr_o = 1'b1; flush_id_o = 1'b1; - flush_ex_o = 1'b1; end diff --git a/src/csr_regfile.sv b/src/csr_regfile.sv index 45120ee4b..d3159f935 100644 --- a/src/csr_regfile.sv +++ b/src/csr_regfile.sv @@ -105,9 +105,9 @@ module csr_regfile #( riscv::status_rv64_t mstatus_q, mstatus_d; riscv::satp_t satp_q, satp_d; riscv::dcsr_t dcsr_q, dcsr_d; - + logic mtvec_rst_load_q;// used to determine whether we came out of reset - + logic [63:0] dpc_q, dpc_d; logic [63:0] dscratch0_q, dscratch0_d; logic [63:0] mtvec_q, mtvec_d; @@ -245,16 +245,16 @@ module csr_regfile #( dpc_d = dpc_q; dscratch0_d = dscratch0_q; mstatus_d = mstatus_q; - + // check whether we come out of reset - // this is a workaround. some tools have issues - // having boot_addr_i in the asynchronous + // this is a workaround. some tools have issues + // having boot_addr_i in the asynchronous // reset assignment to mtvec_d, even though // boot_addr_i will be assigned a constant - // on the top-level. + // on the top-level. if (mtvec_rst_load_q) begin mtvec_d = boot_addr_i + 'h40; - end else begin + end else begin mtvec_d = mtvec_q; end @@ -525,6 +525,7 @@ module csr_regfile #( end // we've got a debug request (and we have an instruction which we can associate it to) + // don't interrupt the AMO if (debug_req_i && commit_instr_i[0].valid) begin // save the PC dpc_d = pc_i; diff --git a/src/ex_stage.sv b/src/ex_stage.sv index 34ed57fa2..ac14f98ca 100644 --- a/src/ex_stage.sv +++ b/src/ex_stage.sv @@ -58,6 +58,7 @@ module ex_stage #( output logic lsu_commit_ready_o, // commit queue is ready to accept another commit request output exception_t lsu_exception_o, output logic no_st_pending_o, + input logic amo_valid_commit_i, // CSR output logic csr_ready_o, input logic csr_valid_i, @@ -91,7 +92,8 @@ module ex_stage #( // interface to dcache input dcache_req_o_t [2:0] dcache_req_ports_i, output dcache_req_i_t [2:0] dcache_req_ports_o, - + output amo_req_t amo_req_o, // request to cache subsytem + input amo_resp_t amo_resp_i, // response from cache subsystem // Performance counters output logic itlb_miss_o, output logic dtlb_miss_o @@ -131,8 +133,10 @@ module ex_stage #( lsu lsu_i ( .commit_i ( lsu_commit_i ), .commit_ready_o ( lsu_commit_ready_o ), - .dcache_req_ports_i ( dcache_req_ports_i ), - .dcache_req_ports_o ( dcache_req_ports_o ), + .dcache_req_ports_i, + .dcache_req_ports_o, + .amo_req_o, + .amo_resp_i, .* ); diff --git a/src/lsu.sv b/src/lsu.sv index ed5d1190f..66fb3ab78 100644 --- a/src/lsu.sv +++ b/src/lsu.sv @@ -15,12 +15,13 @@ import ariane_pkg::*; module lsu #( - parameter int unsigned ASID_WIDTH = 1 + parameter int unsigned ASID_WIDTH = 1 )( input logic clk_i, input logic rst_ni, input logic flush_i, output logic no_st_pending_o, + input logic amo_valid_commit_i, input fu_t fu_i, input fu_op operator_i, @@ -59,6 +60,7 @@ module lsu #( output dcache_req_i_t [2:0] dcache_req_ports_o, // AMO interface output amo_req_t amo_req_o, + input amo_resp_t amo_resp_i, output exception_t lsu_exception_o // to WB, signal exception status LD/ST exception ); @@ -139,9 +141,17 @@ module lsu #( // Store Unit // ------------------ store_unit i_store_unit ( + .clk_i, + .rst_ni, + .flush_i, + .no_st_pending_o, + .valid_i ( st_valid_i ), .lsu_ctrl_i ( lsu_ctrl ), .pop_st_o ( pop_st ), + .commit_i, + .commit_ready_o, + .amo_valid_commit_i, .valid_o ( st_valid ), .trans_id_o ( st_trans_id ), @@ -156,10 +166,12 @@ module lsu #( // Load Unit .page_offset_i ( page_offset ), .page_offset_matches_o ( page_offset_matches ), + // AMOs + .amo_req_o, + .amo_resp_i, // to memory arbiter .req_port_i ( dcache_req_ports_i [2] ), - .req_port_o ( dcache_req_ports_o [2] ), - .* + .req_port_o ( dcache_req_ports_o [2] ) ); // ------------------ @@ -253,11 +265,7 @@ module lsu #( LD, SD: begin // double word be_i = 8'b1111_1111; end - LW, LWU, SW, - AMO_LRW, AMO_SCW, - AMO_SWAPW, AMO_ADDW, AMO_ANDW, AMO_ORW, - AMO_XORW, AMO_MAXW, AMO_MAXWU, AMO_MINW, - AMO_MINWU: begin// word + LW, LWU, SW: begin// word case (vaddr_i[2:0]) 3'b000: be_i = 8'b0000_1111; 3'b001: be_i = 8'b0001_1110; @@ -348,7 +356,7 @@ module lsu #( if (data_misaligned) begin - if (lsu_ctrl.fu == LOAD || lsu_ctrl.fu == AMO) begin + if (lsu_ctrl.fu == LOAD) begin misaligned_exception = { riscv::LD_ADDR_MISALIGNED, lsu_ctrl.vaddr, @@ -402,15 +410,6 @@ module lsu #( .ready_o ( lsu_ready_o ), .* ); - // ------------ - // Assertions - // ------------ - - `ifndef SYNTHESIS - `ifndef VERILATOR - // TODO - `endif - `endif endmodule // ------------------ diff --git a/src/store_unit.sv b/src/store_unit.sv index 46a687106..1534baaad 100644 --- a/src/store_unit.sv +++ b/src/store_unit.sv @@ -62,9 +62,11 @@ module store_unit ( logic st_valid_without_flush; // keep the data and the byte enable for the second cycle (after address translation) - logic [63:0] st_data_n, st_data_q; - logic [7:0] st_be_n, st_be_q; - logic [1:0] st_data_size_n, st_data_size_q; + logic [63:0] st_data_n, st_data_q; + logic [7:0] st_be_n, st_be_q; + logic [1:0] st_data_size_n, st_data_size_q; + amo_t amo_op_d, amo_op_q; + logic [TRANS_ID_BITS-1:0] trans_id_n, trans_id_q; // output assignments @@ -193,11 +195,14 @@ module store_unit ( end logic store_buffer_valid, amo_buffer_valid; + logic store_buffer_ready, amo_buffer_ready; // multiplex between store unit and amo buffer assign store_buffer_valid = st_valid & (amo_op_q == AMO_NONE); assign amo_buffer_valid = st_valid & (amo_op_q != AMO_NONE); + assign st_ready = store_buffer_ready & amo_buffer_ready; + // --------------- // Store Queue // --------------- @@ -210,7 +215,7 @@ module store_unit ( .page_offset_matches_o, .commit_i, .commit_ready_o, - .ready_o ( st_ready ), + .ready_o ( store_buffer_ready ), .valid_i ( store_buffer_valid ), // the flush signal can be critical and we need this valid // signal to check whether the page_offset matches or not, @@ -229,8 +234,6 @@ module store_unit ( // --------------- // AMO Buffer // --------------- - amo_t amo_op_q, amo_op_q; - always_comb begin amo_op_d = amo_op_q; @@ -250,11 +253,11 @@ module store_unit ( end amo_buffer i_amo_buffer ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .flush_i ( flush_i ), + .clk_i, + .rst_ni, + .flush_i, .valid_i ( amo_buffer_valid ), - .ready_o ( commit_ready_o ), + .ready_o ( amo_buffer_ready ), .paddr_i ( paddr_i ), .amo_op_i ( amo_op_q ), .data_i ( st_data_q ), diff --git a/src/util/instruction_trace_item.svh b/src/util/instruction_trace_item.svh index 632cffb93..ef6ad36ac 100644 --- a/src/util/instruction_trace_item.svh +++ b/src/util/instruction_trace_item.svh @@ -397,7 +397,7 @@ class instruction_trace_item; 5'h14: mnemonic = "amomax.w"; 5'h18: mnemonic = "amominu.w"; 5'h1C: mnemonic = "amomax.w"; - default: printMnemonic("INVALID"); + default: return printMnemonic("INVALID"); endcase end if (instr[14:12] == 3'h3) begin // doubles @@ -413,7 +413,7 @@ class instruction_trace_item; 5'h14: mnemonic = "amomax.d"; 5'h18: mnemonic = "amominu.d"; 5'h1C: mnemonic = "amomax.d"; - default: printMnemonic("INVALID"); + default: return printMnemonic("INVALID"); endcase end else return printMnemonic("INVALID");