diff --git a/.gitmodules b/.gitmodules index 181e772..e26ff47 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,9 @@ [submodule "test/riscv-compliance/riscv-compliance"] path = test/riscv-compliance/riscv-compliance url = https://github.com/riscv/riscv-compliance.git +[submodule "test/riscv-compliance/riscv-arch-test"] + path = test/riscv-compliance/riscv-arch-test + url = https://github.com/riscv/riscv-arch-test.git +[submodule "scripts"] + path = scripts + url = https://github.com/Wren6991/fpgascripts diff --git a/hdl/hazard3_core.v b/hdl/hazard3_core.v index 9653ab9..0454138 100644 --- a/hdl/hazard3_core.v +++ b/hdl/hazard3_core.v @@ -84,24 +84,24 @@ localparam HSIZE_BYTE = 3'd0; -// ============================================================================ -// Pipe Stage F -// ============================================================================ +// ---------------------------------------------------------------------------- +// Pipe Stage F -wire m_jump_req; -wire [W_ADDR-1:0] m_jump_target; -wire d_jump_req; -wire [W_ADDR-1:0] d_jump_target; -wire f_jump_req = d_jump_req || m_jump_req; -wire [W_ADDR-1:0] f_jump_target = m_jump_req ? m_jump_target : d_jump_target; -wire f_jump_rdy; -wire f_jump_now = f_jump_req && f_jump_rdy; +wire f_jump_req; +wire [W_ADDR-1:0] f_jump_target; +wire f_jump_rdy; +wire f_jump_now = f_jump_req && f_jump_rdy; -wire [31:0] fd_cir; -wire [1:0] fd_cir_vld; -wire [1:0] df_cir_use; -wire df_cir_lock; +// Predecoded register numbers, for register file access +wire f_regnum_vld; +wire [W_REGADDR-1:0] f_rs1; +wire [W_REGADDR-1:0] f_rs2; + +wire [31:0] fd_cir; +wire [1:0] fd_cir_vld; +wire [1:0] df_cir_use; +wire df_cir_lock; assign bus_aph_panic_i = m_jump_req; @@ -130,14 +130,17 @@ hazard3_frontend #( .cir (fd_cir), .cir_vld (fd_cir_vld), .cir_use (df_cir_use), - .cir_lock (df_cir_lock) + .cir_lock (df_cir_lock), + + .next_regs_rs1 (f_rs1), + .next_regs_rs2 (f_rs2), + .next_regs_vld (f_regnum_vld) ); assign flush_d_x = m_jump_req && f_jump_rdy; -// ============================================================================ -// Pipe Stage D -// ============================================================================ +// ---------------------------------------------------------------------------- +// Pipe Stage X (Decode Logic) // X-check on pieces of instruction which frontend claims are valid //synthesis translate_off @@ -155,82 +158,75 @@ always @ (posedge clk) begin end //synthesis translate_on -wire [W_ADDR-1:0] d_pc; // FIXME only used for riscv-formal - -// To register file +// To X +wire d_jump_req; +wire [W_ADDR-1:0] d_jump_target; +wire [W_DATA-1:0] d_imm; wire [W_REGADDR-1:0] d_rs1; wire [W_REGADDR-1:0] d_rs2; +wire [W_REGADDR-1:0] d_rd; +wire [W_ALUSRC-1:0] d_alusrc_a; +wire [W_ALUSRC-1:0] d_alusrc_b; +wire [W_ALUOP-1:0] d_aluop; +wire [W_MEMOP-1:0] d_memop; +wire [W_MULOP-1:0] d_mulop; +wire [W_BCOND-1:0] d_branchcond; +wire d_jump_is_regoffs; +wire d_result_is_linkaddr; +wire [W_ADDR-1:0] d_pc; +wire [W_ADDR-1:0] d_mispredict_addr; +wire [W_EXCEPT-1:0] d_except; +wire d_csr_ren; +wire d_csr_wen; +wire [1:0] d_csr_wtype; +wire d_csr_w_imm; -// To X -wire [W_DATA-1:0] dx_imm; -wire [W_REGADDR-1:0] dx_rs1; -wire [W_REGADDR-1:0] dx_rs2; -wire [W_REGADDR-1:0] dx_rd; -wire [W_ALUSRC-1:0] dx_alusrc_a; -wire [W_ALUSRC-1:0] dx_alusrc_b; -wire [W_ALUOP-1:0] dx_aluop; -wire [W_MEMOP-1:0] dx_memop; -wire [W_MULOP-1:0] dx_mulop; -wire [W_BCOND-1:0] dx_branchcond; -wire [W_ADDR-1:0] dx_jump_target; -wire dx_jump_is_regoffs; -wire dx_result_is_linkaddr; -wire [W_ADDR-1:0] dx_pc; -wire [W_ADDR-1:0] dx_mispredict_addr; -wire [W_EXCEPT-1:0] dx_except; -wire dx_csr_ren; -wire dx_csr_wen; -wire [1:0] dx_csr_wtype; -wire dx_csr_w_imm; hazard3_decode #( `include "hazard3_config_inst.vh" ) inst_hazard3_decode ( - .clk (clk), - .rst_n (rst_n), + .clk (clk), + .rst_n (rst_n), - .fd_cir (fd_cir), - .fd_cir_vld (fd_cir_vld), - .df_cir_use (df_cir_use), - .df_cir_lock (df_cir_lock), - .d_jump_req (d_jump_req), - .d_jump_target (d_jump_target), - .d_pc (d_pc), + .fd_cir (fd_cir), + .fd_cir_vld (fd_cir_vld), + .df_cir_use (df_cir_use), + .df_cir_lock (df_cir_lock), + .d_jump_req (d_jump_req), + .d_jump_target (d_jump_target), + .d_pc (d_pc), - .d_stall (d_stall), - .x_stall (x_stall), - .flush_d_x (flush_d_x), - .f_jump_rdy (f_jump_rdy), - .f_jump_now (f_jump_now), - .f_jump_target (f_jump_target), + .d_stall (d_stall), + .x_stall (x_stall), + .flush_d_x (flush_d_x), + .f_jump_rdy (f_jump_rdy), + .f_jump_now (f_jump_now), + .f_jump_target (f_jump_target), - .d_rs1 (d_rs1), - .d_rs2 (d_rs2), - .dx_imm (dx_imm), - .dx_rs1 (dx_rs1), - .dx_rs2 (dx_rs2), - .dx_rd (dx_rd), - .dx_alusrc_a (dx_alusrc_a), - .dx_alusrc_b (dx_alusrc_b), - .dx_aluop (dx_aluop), - .dx_memop (dx_memop), - .dx_mulop (dx_mulop), - .dx_csr_ren (dx_csr_ren), - .dx_csr_wen (dx_csr_wen), - .dx_csr_wtype (dx_csr_wtype), - .dx_csr_w_imm (dx_csr_w_imm), - .dx_branchcond (dx_branchcond), - .dx_jump_target (dx_jump_target), - .dx_jump_is_regoffs (dx_jump_is_regoffs), - .dx_result_is_linkaddr (dx_result_is_linkaddr), - .dx_pc (dx_pc), - .dx_mispredict_addr (dx_mispredict_addr), - .dx_except (dx_except) + .d_imm (d_imm), + .d_rs1 (d_rs1), + .d_rs2 (d_rs2), + .d_rd (d_rd), + .d_alusrc_a (d_alusrc_a), + .d_alusrc_b (d_alusrc_b), + .d_aluop (d_aluop), + .d_memop (d_memop), + .d_mulop (d_mulop), + .d_csr_ren (d_csr_ren), + .d_csr_wen (d_csr_wen), + .d_csr_wtype (d_csr_wtype), + .d_csr_w_imm (d_csr_w_imm), + .d_branchcond (d_branchcond), + .d_jump_target (d_jump_target), + .d_jump_is_regoffs (d_jump_is_regoffs), + .d_result_is_linkaddr (d_result_is_linkaddr), + .d_pc (d_pc), + .d_mispredict_addr (d_mispredict_addr), + .d_except (d_except) ); -// ============================================================================ -// Pipe Stage X -// ============================================================================ +// ---------------------------------------------------------------------------- +// Pipe Stage X (Execution Logic) // Register the write which took place to the regfile on previous cycle, and bypass. // This is an alternative to a write -> read bypass in the regfile, @@ -239,8 +235,8 @@ reg [W_REGADDR-1:0] mw_rd; reg [W_DATA-1:0] mw_result; // From register file: -wire [W_DATA-1:0] dx_rdata1; -wire [W_DATA-1:0] dx_rdata2; +wire [W_DATA-1:0] x_rdata1; +wire [W_DATA-1:0] x_rdata2; // Combinational regs for muxing reg [W_DATA-1:0] x_rs1_bypass; @@ -260,19 +256,9 @@ reg [W_REGADDR-1:0] xm_rs1; reg [W_REGADDR-1:0] xm_rs2; reg [W_REGADDR-1:0] xm_rd; reg [W_DATA-1:0] xm_result; -reg [W_ADDR-1:0] xm_jump_target; reg [W_DATA-1:0] xm_store_data; -reg xm_jump; reg [W_MEMOP-1:0] xm_memop; -// For JALR, the LSB of the result must be cleared by hardware -wire [W_ADDR-1:0] x_taken_jump_target = dx_jump_is_regoffs ? x_alu_add & ~32'h1 : dx_jump_target; -wire [W_ADDR-1:0] x_jump_target = - x_trap_exit ? x_mepc : // Note precedence -- it's possible to have enter && exit, but in this case enter_rdy is false. - x_trap_enter ? x_trap_addr : - dx_imm[31] && dx_branchcond != BCOND_ALWAYS ? dx_mispredict_addr : - x_taken_jump_target; - reg x_stall_raw; wire x_stall_muldiv; @@ -287,24 +273,24 @@ always @ (*) begin x_stall_raw = 1'b0; if (REDUCED_BYPASS) begin x_stall_raw = - |xm_rd && (xm_rd == dx_rs1 || xm_rd == dx_rs2) || - |mw_rd && (mw_rd == dx_rs1 || mw_rd == dx_rs2); + |xm_rd && (xm_rd == d_rs1 || xm_rd == d_rs2) || + |mw_rd && (mw_rd == d_rs1 || mw_rd == d_rs2); end else if (m_generating_result) begin // With the full bypass network, load-use (or fast multiply-use) is the only RAW stall - if (|xm_rd && xm_rd == dx_rs1) begin + if (|xm_rd && xm_rd == d_rs1) begin // Store addresses cannot be bypassed later, so there is no exception here. x_stall_raw = 1'b1; - end else if (|xm_rd && xm_rd == dx_rs2) begin + end else if (|xm_rd && xm_rd == d_rs2) begin // Store data can be bypassed in M. Any other instructions must stall. - x_stall_raw = !(dx_memop == MEMOP_SW || dx_memop == MEMOP_SH || dx_memop == MEMOP_SB); + x_stall_raw = !(d_memop == MEMOP_SW || d_memop == MEMOP_SH || d_memop == MEMOP_SB); end end end // AHB transaction request -wire x_memop_vld = !dx_memop[3]; -wire x_memop_write = dx_memop == MEMOP_SW || dx_memop == MEMOP_SH || dx_memop == MEMOP_SB; +wire x_memop_vld = !d_memop[3]; +wire x_memop_write = d_memop == MEMOP_SW || d_memop == MEMOP_SH || d_memop == MEMOP_SB; wire x_unaligned_addr = bus_hsize_d == HSIZE_WORD && |bus_haddr_d[1:0] || bus_hsize_d == HSIZE_HWORD && bus_haddr_d[0]; @@ -316,7 +302,7 @@ always @ (*) begin // Need to be careful not to use anything hready-sourced to gate htrans! bus_haddr_d = x_alu_add; bus_hwrite_d = x_memop_write; - case (dx_memop) + case (d_memop) MEMOP_LW: bus_hsize_d = HSIZE_WORD; MEMOP_SW: bus_hsize_d = HSIZE_WORD; MEMOP_LH: bus_hsize_d = HSIZE_HWORD; @@ -332,42 +318,42 @@ end // ALU operand muxes and bypass always @ (*) begin - if (~|dx_rs1) begin + if (~|d_rs1) begin x_rs1_bypass = {W_DATA{1'b0}}; - end else if (xm_rd == dx_rs1) begin + end else if (xm_rd == d_rs1) begin x_rs1_bypass = xm_result; - end else if (mw_rd == dx_rs1 && !REDUCED_BYPASS) begin + end else if (mw_rd == d_rs1 && !REDUCED_BYPASS) begin x_rs1_bypass = mw_result; end else begin - x_rs1_bypass = dx_rdata1; + x_rs1_bypass = x_rdata1; end - if (~|dx_rs2) begin + if (~|d_rs2) begin x_rs2_bypass = {W_DATA{1'b0}}; - end else if (xm_rd == dx_rs2) begin + end else if (xm_rd == d_rs2) begin x_rs2_bypass = xm_result; - end else if (mw_rd == dx_rs2 && !REDUCED_BYPASS) begin + end else if (mw_rd == d_rs2 && !REDUCED_BYPASS) begin x_rs2_bypass = mw_result; end else begin - x_rs2_bypass = dx_rdata2; + x_rs2_bypass = x_rdata2; end - if (|dx_alusrc_a) - x_op_a = dx_pc; + if (|d_alusrc_a) + x_op_a = d_pc; else x_op_a = x_rs1_bypass; - if (|dx_alusrc_b) - x_op_b = dx_imm; + if (|d_alusrc_b) + x_op_b = d_imm; else x_op_b = x_rs2_bypass; end // CSRs and Trap Handling -wire x_except_ecall = dx_except == EXCEPT_ECALL; -wire x_except_breakpoint = dx_except == EXCEPT_EBREAK; -wire x_except_invalid_instr = dx_except == EXCEPT_INSTR_ILLEGAL; -assign x_trap_exit = dx_except == EXCEPT_MRET && !(x_stall || m_jump_req); +wire x_except_ecall = d_except == EXCEPT_ECALL; +wire x_except_breakpoint = d_except == EXCEPT_EBREAK; +wire x_except_invalid_instr = d_except == EXCEPT_INSTR_ILLEGAL; +assign x_trap_exit = d_except == EXCEPT_MRET && !(x_stall || m_jump_req); wire x_trap_enter_rdy = !(x_stall || m_jump_req || x_trap_exit); wire x_trap_is_exception; // diagnostic @@ -380,8 +366,8 @@ always @ (posedge clk) begin end `endif -wire [W_DATA-1:0] x_csr_wdata = dx_csr_w_imm ? - {{W_DATA-5{1'b0}}, dx_rs1} : x_rs1_bypass; +wire [W_DATA-1:0] x_csr_wdata = d_csr_w_imm ? + {{W_DATA-5{1'b0}}, d_rs1} : x_rs1_bypass; wire [W_DATA-1:0] x_csr_rdata; @@ -394,21 +380,21 @@ hazard3_csr #( // CSR access port // *en_soon are early access strobes which are not a function of bus stall. // Can generate access faults (hence traps), but do not actually perform access. - .addr (dx_imm[11:0]), + .addr (d_imm[11:0]), // todo could just connect this to the instruction bits .wdata (x_csr_wdata), - .wen_soon (dx_csr_wen), - .wen (dx_csr_wen && !(x_stall || flush_d_x)), - .wtype (dx_csr_wtype), + .wen_soon (d_csr_wen), + .wen (d_csr_wen && !(x_stall || flush_d_x)), + .wtype (d_csr_wtype), .rdata (x_csr_rdata), - .ren_soon (dx_csr_ren), - .ren (dx_csr_ren && !(x_stall || flush_d_x)), + .ren_soon (d_csr_ren), + .ren (d_csr_ren && !(x_stall || flush_d_x)), // Trap signalling .trap_addr (x_trap_addr), .trap_enter_vld (x_trap_enter), .trap_enter_rdy (x_trap_enter_rdy), .trap_exit (x_trap_exit), .trap_is_exception (x_trap_is_exception), - .mepc_in (dx_pc), + .mepc_in (d_pc), .mepc_out (x_mepc), // IRQ and exception requests .irq (irq), @@ -447,9 +433,9 @@ if (EXTENSION_M) begin: has_muldiv wire x_muldiv_kill = flush_d_x || x_trap_enter; // TODO this takes an extra cycle to kill muldiv before trap entry - wire x_use_fast_mul = MUL_FAST && dx_aluop == ALUOP_MULDIV && dx_mulop == M_OP_MUL; + wire x_use_fast_mul = MUL_FAST && d_aluop == ALUOP_MULDIV && d_mulop == M_OP_MUL; - assign x_muldiv_op_vld = (dx_aluop == ALUOP_MULDIV && !x_use_fast_mul) + assign x_muldiv_op_vld = (d_aluop == ALUOP_MULDIV && !x_use_fast_mul) && !(x_muldiv_posted || x_stall_raw || x_muldiv_kill); hazard3_muldiv_seq #( @@ -458,7 +444,7 @@ if (EXTENSION_M) begin: has_muldiv ) muldiv ( .clk (clk), .rst_n (rst_n), - .op (dx_mulop), + .op (d_mulop), .op_vld (x_muldiv_op_vld), .op_rdy (x_muldiv_op_rdy), .op_kill (x_muldiv_kill), @@ -472,17 +458,17 @@ if (EXTENSION_M) begin: has_muldiv // TODO fusion of MULHx->MUL and DIVy->REMy sequences wire x_muldiv_result_is_high = - dx_mulop == M_OP_MULH || - dx_mulop == M_OP_MULHSU || - dx_mulop == M_OP_MULHU || - dx_mulop == M_OP_REM || - dx_mulop == M_OP_REMU; + d_mulop == M_OP_MULH || + d_mulop == M_OP_MULHSU || + d_mulop == M_OP_MULHU || + d_mulop == M_OP_REM || + d_mulop == M_OP_REMU; assign x_muldiv_result = x_muldiv_result_is_high ? x_muldiv_result_h : x_muldiv_result_l; assign x_stall_muldiv = x_muldiv_op_vld || !x_muldiv_result_vld; if (MUL_FAST) begin: has_fast_mul - wire x_issue_fast_mul = x_use_fast_mul && |dx_rd && !(x_stall || flush_d_x); + wire x_issue_fast_mul = x_use_fast_mul && |d_rd && !(x_stall || flush_d_x); hazard3_mul_fast #( .XLEN(W_DATA) @@ -506,7 +492,7 @@ if (EXTENSION_M) begin: has_muldiv end `ifdef FORMAL - always @ (posedge clk) if (dx_aluop != ALUOP_MULDIV) assert(!x_stall_muldiv); + always @ (posedge clk) if (d_aluop != ALUOP_MULDIV) assert(!x_stall_muldiv); `endif end else begin: no_muldiv @@ -519,37 +505,23 @@ end else begin: no_muldiv end endgenerate -// State machine and branch detection +// State machine always @ (posedge clk or negedge rst_n) begin if (!rst_n) begin - xm_jump <= 1'b0; xm_memop <= MEMOP_NONE; {xm_rs1, xm_rs2, xm_rd} <= {3 * W_REGADDR{1'b0}}; end else begin // TODO: this assertion may become untrue depending on how we handle exceptions/IRQs when stalled? //`ASSERT(!(m_stall && flush_d_x));// bubble insertion logic below is broken otherwise if (!m_stall) begin - {xm_rs1, xm_rs2, xm_rd} <= {dx_rs1, dx_rs2, dx_rd}; + {xm_rs1, xm_rs2, xm_rd} <= {d_rs1, d_rs2, d_rd}; // If the transfer is unaligned, make sure it is completely NOP'd on the bus - xm_memop <= dx_memop | {x_unaligned_addr, 3'h0}; + xm_memop <= d_memop | {x_unaligned_addr, 3'h0}; if (x_stall || flush_d_x || x_trap_enter) begin // Insert bubble xm_rd <= {W_REGADDR{1'b0}}; - xm_jump <= 1'b0; xm_memop <= MEMOP_NONE; end - if (!(x_stall || flush_d_x)) begin - case (dx_branchcond) - BCOND_ALWAYS: xm_jump <= 1'b1; - // For branches, we are either taking a branch late, or recovering from - // an incorrectly taken branch, depending on sign of branch offset. - BCOND_ZERO: xm_jump <= !x_alu_cmp ^ dx_imm[31]; - BCOND_NZERO: xm_jump <= x_alu_cmp ^ dx_imm[31]; - default xm_jump <= 1'b0; - endcase - if (x_trap_enter || x_trap_exit) - xm_jump <= 1'b1; - end end end end @@ -558,16 +530,34 @@ end always @ (posedge clk) if (!m_stall) begin xm_result <= - dx_result_is_linkaddr ? dx_mispredict_addr : - dx_csr_ren ? x_csr_rdata : - EXTENSION_M && dx_aluop == ALUOP_MULDIV ? x_muldiv_result : - x_alu_result; + d_result_is_linkaddr ? d_mispredict_addr : + d_csr_ren ? x_csr_rdata : + EXTENSION_M && d_aluop == ALUOP_MULDIV ? x_muldiv_result : + x_alu_result; xm_store_data <= x_rs2_bypass; - xm_jump_target <= x_jump_target; end +// Branch handling + +// For JALR, the LSB of the result must be cleared by hardware +wire [W_ADDR-1:0] x_taken_jump_target = d_jump_is_regoffs ? x_alu_add & ~32'h1 : d_jump_target; +wire [W_ADDR-1:0] x_jump_target = + x_trap_exit ? x_mepc : // Note precedence -- it's possible to have enter && exit, but in this case enter_rdy is false. + x_trap_enter ? x_trap_addr : + x_taken_jump_target; + +wire x_jump_req = + x_trap_enter || x_trap_exit || + d_branchcond == BCOND_ALWAYS || + d_branchcond == BCOND_ZERO && !x_alu_cmp || + d_branchcond == BCOND_NZERO && x_alu_cmp; + +assign f_jump_req = d_jump_req || x_jump_req; +assign f_jump_target = x_jump_target; + + hazard3_alu alu ( - .aluop (dx_aluop), + .aluop (d_aluop), .op_a (x_op_a), .op_b (x_op_b), .result (x_alu_result), @@ -575,15 +565,12 @@ hazard3_alu alu ( .cmp (x_alu_cmp) ); -// ============================================================================ +// ---------------------------------------------------------------------------- // Pipe Stage M -// ============================================================================ reg [W_DATA-1:0] m_rdata_shift; reg [W_DATA-1:0] m_wdata; reg [W_DATA-1:0] m_result; -assign m_jump_req = xm_jump; -assign m_jump_target = xm_jump_target; assign m_stall = (!xm_memop[3] && !bus_dph_ready_d) || (m_jump_req && !f_jump_rdy); @@ -652,9 +639,8 @@ always @ (posedge clk) if (!m_stall) mw_result <= m_result; -// ============================================================================ +// ---------------------------------------------------------------------------- // Pipe Stage W -// ============================================================================ // mw_result and mw_rd register the most recent write to the register file, // so that X can bypass them in. @@ -686,12 +672,12 @@ hazard3_regfile_1w2r #( ) inst_regfile_1w2r ( .clk (clk), .rst_n (rst_n), - // On stall, we feed X's addresses back into regfile + // On downstream stall, we feed D's addresses back into regfile // so that output does not change. - .raddr1 (x_stall ? dx_rs1 : d_rs1), - .rdata1 (dx_rdata1), - .raddr2 (x_stall ? dx_rs2 : d_rs2), - .rdata2 (dx_rdata2), + .raddr1 (x_stall ? d_rs1 : f_rs1), + .rdata1 (x_rdata1), + .raddr2 (x_stall ? d_rs2 : f_rs2), + .rdata2 (x_rdata2), .waddr (xm_rd), .wdata (m_result), diff --git a/hdl/hazard3_decode.v b/hdl/hazard3_decode.v index 8cc2cbe..361a6a0 100644 --- a/hdl/hazard3_decode.v +++ b/hdl/hazard3_decode.v @@ -29,7 +29,7 @@ module hazard3_decode #( output wire df_cir_lock, output reg d_jump_req, output reg [W_ADDR-1:0] d_jump_target, - output wire [W_ADDR-1:0] d_pc, // FIXME only added for riscv-formal + output wire [W_ADDR-1:0] d_pc, output wire d_stall, input wire x_stall, @@ -38,29 +38,26 @@ module hazard3_decode #( input wire f_jump_now, input wire [W_ADDR-1:0] f_jump_target, - output reg [W_REGADDR-1:0] d_rs1, // combinatorial - output reg [W_REGADDR-1:0] d_rs2, // combinatorial - - output reg [W_DATA-1:0] dx_imm, - output reg [W_REGADDR-1:0] dx_rs1, - output reg [W_REGADDR-1:0] dx_rs2, - output reg [W_REGADDR-1:0] dx_rd, - output reg [W_ALUSRC-1:0] dx_alusrc_a, - output reg [W_ALUSRC-1:0] dx_alusrc_b, - output reg [W_ALUOP-1:0] dx_aluop, - output reg [W_MEMOP-1:0] dx_memop, - output reg [W_MULOP-1:0] dx_mulop, - output reg dx_csr_ren, - output reg dx_csr_wen, - output reg [1:0] dx_csr_wtype, - output reg dx_csr_w_imm, - output reg [W_BCOND-1:0] dx_branchcond, - output reg [W_ADDR-1:0] dx_jump_target, - output reg dx_jump_is_regoffs, - output reg dx_result_is_linkaddr, - output reg [W_ADDR-1:0] dx_pc, - output reg [W_ADDR-1:0] dx_mispredict_addr, - output reg [2:0] dx_except + output reg [W_DATA-1:0] d_imm, + output reg [W_REGADDR-1:0] d_rs1, + output reg [W_REGADDR-1:0] d_rs2, + output reg [W_REGADDR-1:0] d_rd, + output reg [W_ALUSRC-1:0] d_alusrc_a, + output reg [W_ALUSRC-1:0] d_alusrc_b, + output reg [W_ALUOP-1:0] d_aluop, + output reg [W_MEMOP-1:0] d_memop, + output reg [W_MULOP-1:0] d_mulop, + output reg d_csr_ren, + output reg d_csr_wen, + output reg [1:0] d_csr_wtype, + output reg d_csr_w_imm, + output reg [W_BCOND-1:0] d_branchcond, + output reg [W_ADDR-1:0] d_jump_target, + output reg d_jump_is_regoffs, + output reg d_result_is_linkaddr, + output reg [W_ADDR-1:0] d_pc, + output reg [W_ADDR-1:0] d_mispredict_addr, + output reg [2:0] d_except ); `include "rv_opcodes.vh" @@ -165,39 +162,17 @@ always @ (*) begin d_jump_target = pc + d_jump_offs; - casez ({d_instr[31], d_instr}) - {1'b1, RV_BEQ }: d_jump_req = jump_enable; - {1'b1, RV_BNE }: d_jump_req = jump_enable; - {1'b1, RV_BLT }: d_jump_req = jump_enable; - {1'b1, RV_BGE }: d_jump_req = jump_enable; - {1'b1, RV_BLTU}: d_jump_req = jump_enable; - {1'b1, RV_BGEU}: d_jump_req = jump_enable; - {1'bz, RV_JAL }: d_jump_req = jump_enable; + casez (d_instr) + RV_JAL: d_jump_req = jump_enable; default: d_jump_req = 1'b0; endcase + + d_mispredict_addr = pc_next; end // ---------------------------------------------------------------------------- // Decode X controls -// Combinatorials: -reg [W_REGADDR-1:0] d_rd; -reg [W_DATA-1:0] d_imm; -reg [W_DATA-1:0] d_branchoffs; -reg [W_ALUSRC-1:0] d_alusrc_a; -reg [W_ALUSRC-1:0] d_alusrc_b; -reg [W_ALUOP-1:0] d_aluop; -reg [W_MEMOP-1:0] d_memop; -reg [W_MULOP-1:0] d_mulop; -reg [W_BCOND-1:0] d_branchcond; -reg d_jump_is_regoffs; -reg d_result_is_linkaddr; -reg d_csr_ren; -reg d_csr_wen; -reg [1:0] d_csr_wtype; -reg d_csr_w_imm; -reg [W_EXCEPT-1:0] d_except; - localparam X0 = {W_REGADDR{1'b0}}; always @ (*) begin @@ -206,7 +181,6 @@ always @ (*) begin d_rs2 = d_instr[24:20]; d_rd = d_instr[11: 7]; d_imm = d_imm_i; - d_branchoffs = d_imm_i; d_alusrc_a = ALUSRCA_RS1; d_alusrc_b = ALUSRCB_RS2; d_aluop = ALUOP_ADD; @@ -281,87 +255,20 @@ always @ (*) begin RV_MRET: if (HAVE_CSR) begin d_except = EXCEPT_MRET; d_rs2 = X0; d_rs1 = X0; d_rd = X0; end else begin d_invalid_32bit = 1'b1; end default: begin d_invalid_32bit = 1'b1; end endcase -end - -always @ (posedge clk or negedge rst_n) begin - if (!rst_n) begin - {dx_rs1, dx_rs2, dx_rd} <= {(3 * W_REGADDR){1'b0}}; - dx_alusrc_a <= ALUSRCA_RS1; - dx_alusrc_b <= ALUSRCB_RS2; - dx_aluop <= ALUOP_ADD; - dx_memop <= MEMOP_NONE; - dx_mulop <= M_OP_MUL; - dx_csr_ren <= 1'b0; - dx_csr_wen <= 1'b0; - dx_csr_wtype <= CSR_WTYPE_W; - dx_csr_w_imm <= 1'b0; - dx_branchcond <= BCOND_NEVER; - dx_jump_is_regoffs <= 1'b0; - dx_result_is_linkaddr <= 1'b0; - dx_except <= EXCEPT_NONE; - end else if (flush_d_x || (d_stall && !x_stall)) begin - // Bubble insertion - dx_branchcond <= BCOND_NEVER; - dx_memop <= MEMOP_NONE; - dx_rd <= 5'h0; - dx_except <= EXCEPT_NONE; - dx_csr_ren <= 1'b0; - dx_csr_wen <= 1'b0; - // Don't start a multiply in a pipe bubble + if (d_invalid || d_starved) begin + d_rs1 = {W_REGADDR{1'b0}}; + d_rs2 = {W_REGADDR{1'b0}}; + d_rd = {W_REGADDR{1'b0}}; + d_memop = MEMOP_NONE; + d_branchcond = BCOND_NEVER; + d_csr_ren = 1'b0; + d_csr_wen = 1'b0; if (EXTENSION_M) - dx_aluop <= ALUOP_ADD; - // Also need to clear rs1, rs2, due to a nasty sequence of events: - // Suppose we have a load, followed by a dependent branch, which is predicted taken - // - branch will stall in D until AHB master becomes free - // - on next cycle, prediction causes jump, and bubble is in X - // - if X gets branch's rs1, rs2, it will cause spurious RAW stall - // - on next cycle, branch will not progress into X due to RAW stall, but *will* be replaced in D due to jump - // - branch mispredict now cannot be corrected - dx_rs1 <= 5'h0; - dx_rs2 <= 5'h0; - end else if (!x_stall) begin - // These ones can have side effects - dx_rs1 <= d_invalid ? {W_REGADDR{1'b0}} : d_rs1; - dx_rs2 <= d_invalid ? {W_REGADDR{1'b0}} : d_rs2; - dx_rd <= d_invalid ? {W_REGADDR{1'b0}} : d_rd; - dx_memop <= d_invalid ? MEMOP_NONE : d_memop; - dx_branchcond <= d_invalid ? BCOND_NEVER : d_branchcond; - dx_csr_ren <= d_invalid ? 1'b0 : d_csr_ren; - dx_csr_wen <= d_invalid ? 1'b0 : d_csr_wen; - dx_except <= d_invalid ? EXCEPT_INSTR_ILLEGAL : d_except; - dx_aluop <= d_invalid && EXTENSION_M ? ALUOP_ADD : d_aluop; + d_aluop = ALUOP_ADD; - // These can't - dx_alusrc_a <= d_alusrc_a; - dx_alusrc_b <= d_alusrc_b; - dx_mulop <= d_mulop; - dx_jump_is_regoffs <= d_jump_is_regoffs; - dx_result_is_linkaddr <= d_result_is_linkaddr; - dx_csr_wtype <= d_csr_wtype; - dx_csr_w_imm <= d_csr_w_imm; - end -end - -// No reset required on these; will be masked by the resettable pipeline controls until they're valid -always @ (posedge clk) begin - if (!x_stall) begin - dx_imm <= d_imm; - dx_jump_target <= d_jump_target; - dx_mispredict_addr <= pc_next; - dx_pc <= pc; - end - if (flush_d_x) begin - // The target of a late jump must be propagated *immediately* to X PC, as - // mepc may sample X PC at any time due to IRQ, and must not capture - // misprediction. - // Also required for flush while X stalled (e.g. if a muldiv enters X while - // a 1 cycle bus stall holds off the jump request in M) - dx_pc <= f_jump_target; - `ifdef FORMAL - // This should only be caused by late jumps - assert(f_jump_now); - `endif + if (d_invalid && !d_starved) + d_except = EXCEPT_INSTR_ILLEGAL; end end diff --git a/hdl/hazard3_frontend.v b/hdl/hazard3_frontend.v index bf8fc5d..4ec010a 100644 --- a/hdl/hazard3_frontend.v +++ b/hdl/hazard3_frontend.v @@ -36,11 +36,17 @@ module hazard3_frontend #( output reg [1:0] cir_vld, // number of valid halfwords in CIR input wire [1:0] cir_use, // number of halfwords D intends to consume // *may* be a function of hready - input wire cir_lock // Lock-in current contents and level of CIR. + input wire cir_lock,// Lock-in current contents and level of CIR. // Assert simultaneously with a jump request, // if decode is going to stall. This stops the CIR // from being trashed by incoming fetch data; // jump instructions have other side effects besides jumping! + + // Provide the rs1/rs2 register numbers which will be in CIR on the next + // cycle. These go straight to the register file read ports. + output wire [4:0] next_regs_rs1, + output wire [4:0] next_regs_rs2, + output wire next_regs_vld ); `undef ASSERT @@ -50,19 +56,12 @@ module hazard3_frontend #( `define ASSERT(x) `endif -// ISIM doesn't support some of this: -// //synthesis translate_off -// initial if (W_DATA != 32) begin $error("Frontend requires 32-bit databus"); end -// initial if ((1 << $clog2(FIFO_DEPTH)) != FIFO_DEPTH) begin $error("Frontend FIFO depth must be power of 2"); end -// initial if (~|FIFO_DEPTH) begin $error("Frontend FIFO depth must be > 0"); end -// //synthesis translate_on - localparam W_BUNDLE = W_DATA / 2; parameter W_FIFO_LEVEL = $clog2(FIFO_DEPTH + 1); -// ============================================================================ +// ---------------------------------------------------------------------------- // Fetch Queue (FIFO) -// ============================================================================ +// // This is a little different from either a normal sync fifo or sync fwft fifo // so it's worth implementing from scratch @@ -105,9 +104,8 @@ always @ (posedge clk) begin: fifo_data_shift end end -// ============================================================================ +// ---------------------------------------------------------------------------- // Fetch Request + State Logic -// ============================================================================ // Keep track of some useful state of the memory interface @@ -230,10 +228,8 @@ end assign jump_target_rdy = !mem_addr_hold; - -// ============================================================================ +// ---------------------------------------------------------------------------- // Instruction assembly yard -// ============================================================================ // buf_level is the number of valid halfwords in {hwbuf, cir}. // cir_vld and hwbuf_vld are functions of this. @@ -298,4 +294,21 @@ end always @ (posedge clk) {hwbuf, cir} <= instr_data_plus_fetch; + +// ---------------------------------------------------------------------------- +// Register number predecode + +wire [31:0] next_instr = instr_data_plus_fetch[31:0]; +wire next_instr_is_32bit = next_instr[1:0] == 2'b11; + +assign next_regs_vld = next_instr_is_32bit ? buf_level_next[1] : |buf_level_next; + +assign next_regs_rs1 = + next_instr_is_32bit ? next_instr[19:15] : + next_instr[1:0] == 2'b10 ? next_instr[11:7] : {2'b01, next_instr[9:7]}; + +assign next_regs_rs2 = + next_instr_is_32bit ? next_instr[24:20] : + next_instr[1:0] == 2'b10 ? next_instr[6:2] : {2'b01, next_instr[4:2]}; + endmodule diff --git a/scripts b/scripts new file mode 160000 index 0000000..24f0f32 --- /dev/null +++ b/scripts @@ -0,0 +1 @@ +Subproject commit 24f0f32b1d91e7bb873ebefb997c324dbe90a325 diff --git a/sourceme b/sourceme new file mode 100644 index 0000000..dc87120 --- /dev/null +++ b/sourceme @@ -0,0 +1 @@ +export PATH="$PATH:$PWD/scripts" diff --git a/test/riscv-compliance/Makefile b/test/riscv-compliance/Makefile index f215a7a..3c620cb 100644 --- a/test/riscv-compliance/Makefile +++ b/test/riscv-compliance/Makefile @@ -1,19 +1,67 @@ -TEST = I-ADD-01 -TEST_ARCH = rv32i +TEST_ARCH = I BIN_ARCH = rv32i SIM_EXEC = ../tb_cxxrtl/tb CROSS_PREFIX = /opt/riscv/bin/riscv32-unknown-elf- -TEST_BIN_NAME := $(TEST_ARCH)-$(TEST)-on-$(BIN_ARCH) -TEST_SRC := riscv-compliance/riscv-test-suite/$(TEST_ARCH)/src/$(TEST).S -TEST_VEC := riscv-compliance/riscv-test-suite/$(TEST_ARCH)/references/$(TEST).reference_output +TESTLIST= \ + add-01 \ + addi-01 \ + and-01 \ + andi-01 \ + auipc-01 \ + beq-01 \ + bge-01 \ + bgeu-01 \ + blt-01 \ + bltu-01 \ + bne-01 \ + fence-01 \ + jal-01 \ + jalr-01 \ + lb-align-01 \ + lbu-align-01 \ + lh-align-01 \ + lhu-align-01 \ + lui-01 \ + lw-align-01 \ + or-01 \ + ori-01 \ + sb-align-01 \ + sh-align-01 \ + sll-01 \ + slli-01 \ + slt-01 \ + slti-01 \ + sltiu-01 \ + sltu-01 \ + sra-01 \ + srai-01 \ + srl-01 \ + srli-01 \ + sub-01 \ + sw-align-01 \ + xor-01 \ + xori-01 -.PHONY: all -all: +.PHONY: all testlist clean $(addprefix test-,$(TESTLIST)) +all: testlist + +define make-test-target + # Turns out variable expansions inside functions don't work like I thought they did. Oh well this will do + test-$1: mkdir -p tmp - $(CROSS_PREFIX)gcc -I include -T memmap.ld -nostartfiles -march=$(BIN_ARCH) $(TEST_SRC) -o tmp/$(TEST_BIN_NAME).elf - $(CROSS_PREFIX)objdump -d tmp/$(TEST_BIN_NAME).elf > tmp/$(TEST_BIN_NAME).dis - $(CROSS_PREFIX)objcopy -O binary tmp/$(TEST_BIN_NAME).elf tmp/$(TEST_BIN_NAME).bin - $(SIM_EXEC) tmp/$(TEST_BIN_NAME).bin --dump 0x10000 0x10100 | tee tmp/$(TEST_BIN_NAME).log - ./compare_testvec tmp/$(TEST_BIN_NAME).log $(TEST_VEC) + $(CROSS_PREFIX)gcc -I include -T memmap.ld -nostartfiles -march=$(BIN_ARCH) riscv-arch-test/riscv-test-suite/rv32i_m/$(TEST_ARCH)/src/$1.S -DXLEN=32 -o tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).elf + $(CROSS_PREFIX)objdump -h tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).elf > tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).dis + $(CROSS_PREFIX)objdump -d tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).elf >> tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).dis + $(CROSS_PREFIX)objcopy -O binary tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).elf tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).bin + $(SIM_EXEC) tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).bin tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).vcd --dump 0x400000 0x401000 > tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).log + ./compare_testvec tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).log riscv-arch-test/riscv-test-suite/rv32i_m/$(TEST_ARCH)/references/$1.reference_output +endef + +$(foreach test,$(TESTLIST),$(eval $(call make-test-target,$(test)))) + +testlist: $(addprefix test-,$(TESTLIST)) + +clean: + rm -rf tmp/ diff --git a/test/riscv-compliance/compare_testvec b/test/riscv-compliance/compare_testvec index 863cbb3..520ce63 100755 --- a/test/riscv-compliance/compare_testvec +++ b/test/riscv-compliance/compare_testvec @@ -37,4 +37,4 @@ for i, g in enumerate(gold): if all_match: print("Test PASSED.") else: - print("Test FAILED.") + sys.exit("Test FAILED.") diff --git a/test/riscv-compliance/include/arch_test.h b/test/riscv-compliance/include/arch_test.h new file mode 120000 index 0000000..6406897 --- /dev/null +++ b/test/riscv-compliance/include/arch_test.h @@ -0,0 +1 @@ +../riscv-arch-test/riscv-test-env/arch_test.h \ No newline at end of file diff --git a/test/riscv-compliance/include/compliance_io.h b/test/riscv-compliance/include/compliance_io.h deleted file mode 100644 index 059b6e2..0000000 --- a/test/riscv-compliance/include/compliance_io.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _COMPLIANCE_IO_H_ -#define _COMPLIANCE_IO_H_ - -#define RVTEST_IO_INIT -#define RVTEST_IO_WRITE_STR(_SP, _STR) -#define RVTEST_IO_CHECK() - - -// Put this info into a label name so that it can be seen in the disassembly (holy hack batman) -#define LABEL_ASSERT_(reg, val, line) assert_ ## reg ## _ ## val ## _l ## line: -#define LABEL_ASSERT(reg, val, line) LABEL_ASSERT_(reg, val, line) - -#define RVTEST_IO_ASSERT_GPR_EQ(_SP, _R, _I) LABEL_ASSERT(_R, xxx, __LINE__) nop -#define RVTEST_IO_ASSERT_SFPR_EQ(_F, _R, _I) -#define RVTEST_IO_ASSERT_DFPR_EQ(_D, _R, _I) - -#endif // _COMPLIANCE_IO_H_ \ No newline at end of file diff --git a/test/riscv-compliance/include/compliance_test.h b/test/riscv-compliance/include/compliance_test.h deleted file mode 100644 index b606484..0000000 --- a/test/riscv-compliance/include/compliance_test.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _COMPLIANCE_TEST_H_ -#define _COMPLIANCE_TEST_H_ - -#define RV_COMPLIANCE_RV32M - -#define RV_COMPLIANCE_CODE_BEGIN - -#define RV_COMPLIANCE_CODE_END - -#define MM_IO_EXIT 0x80000008 - -.macro RV_COMPLIANCE_HALT -.option push -.option norelax -_write_io_exit: - li a0, MM_IO_EXIT - sw zero, 0(a0) - // Note we should never reach this next instruction (assuming the - // processor is working correctly!) -_end_of_test: - j _end_of_test -.option pop -.endm - -#define RV_COMPLIANCE_DATA_BEGIN .section .testdata, "a" - -#define RV_COMPLIANCE_DATA_END - - -#endif // _COMPLIANCE_TEST_H_ diff --git a/test/riscv-compliance/include/encoding.h b/test/riscv-compliance/include/encoding.h new file mode 120000 index 0000000..6f818e9 --- /dev/null +++ b/test/riscv-compliance/include/encoding.h @@ -0,0 +1 @@ +../riscv-arch-test/riscv-test-env/encoding.h \ No newline at end of file diff --git a/test/riscv-compliance/include/model_test.h b/test/riscv-compliance/include/model_test.h new file mode 100644 index 0000000..027c5c0 --- /dev/null +++ b/test/riscv-compliance/include/model_test.h @@ -0,0 +1,102 @@ +#ifndef _COMPLIANCE_MODEL_H +#define _COMPLIANCE_MODEL_H + +// Modified version of riscv-arch-test/riscv-target/example-target/model_test.h + +#define IO_BASE 0x80000000 +#define IO_PRINT_CHAR (IO_BASE + 0x0) +#define IO_PRINT_U32 (IO_BASE + 0x4) +#define IO_EXIT (IO_BASE + 0x8) + +#define RVMODEL_DATA_SECTION \ + .pushsection .testdata,"aw",@progbits; \ + .align 8; .global tohost; tohost: .dword 0; \ + .align 8; .global fromhost; fromhost: .dword 0; \ + .popsection; \ + .align 8; .global begin_regstate; begin_regstate: \ + .word 128; \ + .align 8; .global end_regstate; end_regstate: \ + .word 4; + + +#define RVMODEL_HALT ; \ + li a0, IO_EXIT ; \ + li a1, 0 ; \ + sw a1, (a0) ; \ + 1: j 1b \ + +//TODO: declare the start of your signature region here. Nothing else to be used here. +// The .align 4 ensures that the signature ends at a 16-byte boundary +#define RVMODEL_DATA_BEGIN \ + .section .testdata, "aw"; \ + .align 4; .global begin_signature; begin_signature: + +//TODO: declare the end of the signature region here. Add other target specific contents here. +#define RVMODEL_DATA_END \ + .align 4; .global end_signature; end_signature: \ + RVMODEL_DATA_SECTION + + +#define RVMODEL_BOOT + +// _SP = (volatile register) +//TODO: Macro to output a string to IO +#define LOCAL_IO_WRITE_STR(_STR) RVMODEL_IO_WRITE_STR(x31, _STR) + +// Shut up +#define RVMODEL_IO_WRITE_STR(_STR) + +// #define RVMODEL_IO_WRITE_STR(_SP, _STR) \ +// .section .data.string; \ +// 20001: \ +// .string _STR; \ +// .section .text.init; \ +// la a0, 20001b; \ +// jal FN_WriteStr; + +#define RSIZE 4 +// _SP = (volatile register) +#define LOCAL_IO_PUSH(_SP) \ + la _SP, begin_regstate; \ + sw ra, (1*RSIZE)(_SP); \ + sw t0, (2*RSIZE)(_SP); \ + sw t1, (3*RSIZE)(_SP); \ + sw t2, (4*RSIZE)(_SP); \ + sw t3, (5*RSIZE)(_SP); \ + sw t4, (6*RSIZE)(_SP); \ + sw s0, (7*RSIZE)(_SP); \ + sw a0, (8*RSIZE)(_SP); + +// _SP = (volatile register) +#define LOCAL_IO_POP(_SP) \ + la _SP, begin_regstate; \ + lw ra, (1*RSIZE)(_SP); \ + lw t0, (2*RSIZE)(_SP); \ + lw t1, (3*RSIZE)(_SP); \ + lw t2, (4*RSIZE)(_SP); \ + lw t3, (5*RSIZE)(_SP); \ + lw t4, (6*RSIZE)(_SP); \ + lw s0, (7*RSIZE)(_SP); \ + lw a0, (8*RSIZE)(_SP); + +#define RVMODEL_IO_ASSERT_GPR_EQ(_SP, _R, _I) + +//RVTEST_IO_ASSERT_SFPR_EQ +#define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I) +//RVTEST_IO_ASSERT_DFPR_EQ +#define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I) + +// TODO: specify the routine for setting machine software interrupt +#define RVMODEL_SET_MSW_INT + +// TODO: specify the routine for clearing machine software interrupt +#define RVMODEL_CLEAR_MSW_INT + +// TODO: specify the routine for clearing machine timer interrupt +#define RVMODEL_CLEAR_MTIMER_INT + +// TODO: specify the routine for clearing machine external interrupt +#define RVMODEL_CLEAR_MEXT_INT + +#endif // _COMPLIANCE_MODEL_H + diff --git a/test/riscv-compliance/include/riscv_test_macros.h b/test/riscv-compliance/include/riscv_test_macros.h deleted file mode 120000 index 7fc0f1e..0000000 --- a/test/riscv-compliance/include/riscv_test_macros.h +++ /dev/null @@ -1 +0,0 @@ -../riscv-compliance/riscv-test-env/riscv_test_macros.h \ No newline at end of file diff --git a/test/riscv-compliance/memmap.ld b/test/riscv-compliance/memmap.ld index 9369175..a35ad9c 100644 --- a/test/riscv-compliance/memmap.ld +++ b/test/riscv-compliance/memmap.ld @@ -1,6 +1,6 @@ MEMORY { - RAM (wx) : ORIGIN = 0x0, LENGTH = 64k + RAM (wx) : ORIGIN = 0x0, LENGTH = 4M RESULT (w) : ORIGIN = ORIGIN(RAM) + LENGTH(RAM), LENGTH = 64k } @@ -11,9 +11,6 @@ ENTRY(_start) SECTIONS { .text : { - /* Padding in place of vector table (by default CPU reset vector points to - immediately after vector table */ - . = ORIGIN(RAM) + 0xc0; PROVIDE (_start = .); *(.text*) . = ALIGN(4); diff --git a/test/riscv-compliance/riscv-arch-test b/test/riscv-compliance/riscv-arch-test new file mode 160000 index 0000000..b436dd0 --- /dev/null +++ b/test/riscv-compliance/riscv-arch-test @@ -0,0 +1 @@ +Subproject commit b436dd0939c968f2c3da86bb9b63bb2dfe03b134