Merge stages D and X, and bring all branch resolution into X. Passes RV32I compliance

This commit is contained in:
Luke Wren 2021-05-22 07:54:04 +01:00
parent 844fa8f97f
commit 692abbad8b
16 changed files with 397 additions and 381 deletions

6
.gitmodules vendored
View File

@ -1,3 +1,9 @@
[submodule "test/riscv-compliance/riscv-compliance"] [submodule "test/riscv-compliance/riscv-compliance"]
path = test/riscv-compliance/riscv-compliance path = test/riscv-compliance/riscv-compliance
url = https://github.com/riscv/riscv-compliance.git 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

View File

@ -84,20 +84,20 @@ 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 f_jump_req;
wire [W_ADDR-1:0] f_jump_target = m_jump_req ? m_jump_target : d_jump_target; wire [W_ADDR-1:0] f_jump_target;
wire f_jump_rdy; wire f_jump_rdy;
wire f_jump_now = f_jump_req && f_jump_rdy; wire f_jump_now = f_jump_req && f_jump_rdy;
// 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 [31:0] fd_cir;
wire [1:0] fd_cir_vld; wire [1:0] fd_cir_vld;
wire [1:0] df_cir_use; wire [1:0] df_cir_use;
@ -130,14 +130,17 @@ hazard3_frontend #(
.cir (fd_cir), .cir (fd_cir),
.cir_vld (fd_cir_vld), .cir_vld (fd_cir_vld),
.cir_use (df_cir_use), .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; 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 // X-check on pieces of instruction which frontend claims are valid
//synthesis translate_off //synthesis translate_off
@ -155,33 +158,29 @@ always @ (posedge clk) begin
end end
//synthesis translate_on //synthesis translate_on
wire [W_ADDR-1:0] d_pc; // FIXME only used for riscv-formal // To X
wire d_jump_req;
// To register file 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_rs1;
wire [W_REGADDR-1:0] d_rs2; 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 #( hazard3_decode #(
`include "hazard3_config_inst.vh" `include "hazard3_config_inst.vh"
@ -204,33 +203,30 @@ hazard3_decode #(
.f_jump_now (f_jump_now), .f_jump_now (f_jump_now),
.f_jump_target (f_jump_target), .f_jump_target (f_jump_target),
.d_imm (d_imm),
.d_rs1 (d_rs1), .d_rs1 (d_rs1),
.d_rs2 (d_rs2), .d_rs2 (d_rs2),
.dx_imm (dx_imm), .d_rd (d_rd),
.dx_rs1 (dx_rs1), .d_alusrc_a (d_alusrc_a),
.dx_rs2 (dx_rs2), .d_alusrc_b (d_alusrc_b),
.dx_rd (dx_rd), .d_aluop (d_aluop),
.dx_alusrc_a (dx_alusrc_a), .d_memop (d_memop),
.dx_alusrc_b (dx_alusrc_b), .d_mulop (d_mulop),
.dx_aluop (dx_aluop), .d_csr_ren (d_csr_ren),
.dx_memop (dx_memop), .d_csr_wen (d_csr_wen),
.dx_mulop (dx_mulop), .d_csr_wtype (d_csr_wtype),
.dx_csr_ren (dx_csr_ren), .d_csr_w_imm (d_csr_w_imm),
.dx_csr_wen (dx_csr_wen), .d_branchcond (d_branchcond),
.dx_csr_wtype (dx_csr_wtype), .d_jump_target (d_jump_target),
.dx_csr_w_imm (dx_csr_w_imm), .d_jump_is_regoffs (d_jump_is_regoffs),
.dx_branchcond (dx_branchcond), .d_result_is_linkaddr (d_result_is_linkaddr),
.dx_jump_target (dx_jump_target), .d_pc (d_pc),
.dx_jump_is_regoffs (dx_jump_is_regoffs), .d_mispredict_addr (d_mispredict_addr),
.dx_result_is_linkaddr (dx_result_is_linkaddr), .d_except (d_except)
.dx_pc (dx_pc),
.dx_mispredict_addr (dx_mispredict_addr),
.dx_except (dx_except)
); );
// ============================================================================ // ----------------------------------------------------------------------------
// Pipe Stage X // Pipe Stage X (Execution Logic)
// ============================================================================
// Register the write which took place to the regfile on previous cycle, and bypass. // 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, // 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; reg [W_DATA-1:0] mw_result;
// From register file: // From register file:
wire [W_DATA-1:0] dx_rdata1; wire [W_DATA-1:0] x_rdata1;
wire [W_DATA-1:0] dx_rdata2; wire [W_DATA-1:0] x_rdata2;
// Combinational regs for muxing // Combinational regs for muxing
reg [W_DATA-1:0] x_rs1_bypass; 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_rs2;
reg [W_REGADDR-1:0] xm_rd; reg [W_REGADDR-1:0] xm_rd;
reg [W_DATA-1:0] xm_result; reg [W_DATA-1:0] xm_result;
reg [W_ADDR-1:0] xm_jump_target;
reg [W_DATA-1:0] xm_store_data; reg [W_DATA-1:0] xm_store_data;
reg xm_jump;
reg [W_MEMOP-1:0] xm_memop; 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; reg x_stall_raw;
wire x_stall_muldiv; wire x_stall_muldiv;
@ -287,24 +273,24 @@ always @ (*) begin
x_stall_raw = 1'b0; x_stall_raw = 1'b0;
if (REDUCED_BYPASS) begin if (REDUCED_BYPASS) begin
x_stall_raw = x_stall_raw =
|xm_rd && (xm_rd == dx_rs1 || xm_rd == dx_rs2) || |xm_rd && (xm_rd == d_rs1 || xm_rd == d_rs2) ||
|mw_rd && (mw_rd == dx_rs1 || mw_rd == dx_rs2); |mw_rd && (mw_rd == d_rs1 || mw_rd == d_rs2);
end else if (m_generating_result) begin end else if (m_generating_result) begin
// With the full bypass network, load-use (or fast multiply-use) is the only RAW stall // 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. // Store addresses cannot be bypassed later, so there is no exception here.
x_stall_raw = 1'b1; 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. // 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 end
end end
// AHB transaction request // AHB transaction request
wire x_memop_vld = !dx_memop[3]; wire x_memop_vld = !d_memop[3];
wire x_memop_write = dx_memop == MEMOP_SW || dx_memop == MEMOP_SH || dx_memop == MEMOP_SB; wire x_memop_write = d_memop == MEMOP_SW || d_memop == MEMOP_SH || d_memop == MEMOP_SB;
wire x_unaligned_addr = wire x_unaligned_addr =
bus_hsize_d == HSIZE_WORD && |bus_haddr_d[1:0] || bus_hsize_d == HSIZE_WORD && |bus_haddr_d[1:0] ||
bus_hsize_d == HSIZE_HWORD && bus_haddr_d[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! // Need to be careful not to use anything hready-sourced to gate htrans!
bus_haddr_d = x_alu_add; bus_haddr_d = x_alu_add;
bus_hwrite_d = x_memop_write; bus_hwrite_d = x_memop_write;
case (dx_memop) case (d_memop)
MEMOP_LW: bus_hsize_d = HSIZE_WORD; MEMOP_LW: bus_hsize_d = HSIZE_WORD;
MEMOP_SW: bus_hsize_d = HSIZE_WORD; MEMOP_SW: bus_hsize_d = HSIZE_WORD;
MEMOP_LH: bus_hsize_d = HSIZE_HWORD; MEMOP_LH: bus_hsize_d = HSIZE_HWORD;
@ -332,42 +318,42 @@ end
// ALU operand muxes and bypass // ALU operand muxes and bypass
always @ (*) begin always @ (*) begin
if (~|dx_rs1) begin if (~|d_rs1) begin
x_rs1_bypass = {W_DATA{1'b0}}; 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; 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; x_rs1_bypass = mw_result;
end else begin end else begin
x_rs1_bypass = dx_rdata1; x_rs1_bypass = x_rdata1;
end end
if (~|dx_rs2) begin if (~|d_rs2) begin
x_rs2_bypass = {W_DATA{1'b0}}; 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; 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; x_rs2_bypass = mw_result;
end else begin end else begin
x_rs2_bypass = dx_rdata2; x_rs2_bypass = x_rdata2;
end end
if (|dx_alusrc_a) if (|d_alusrc_a)
x_op_a = dx_pc; x_op_a = d_pc;
else else
x_op_a = x_rs1_bypass; x_op_a = x_rs1_bypass;
if (|dx_alusrc_b) if (|d_alusrc_b)
x_op_b = dx_imm; x_op_b = d_imm;
else else
x_op_b = x_rs2_bypass; x_op_b = x_rs2_bypass;
end end
// CSRs and Trap Handling // CSRs and Trap Handling
wire x_except_ecall = dx_except == EXCEPT_ECALL; wire x_except_ecall = d_except == EXCEPT_ECALL;
wire x_except_breakpoint = dx_except == EXCEPT_EBREAK; wire x_except_breakpoint = d_except == EXCEPT_EBREAK;
wire x_except_invalid_instr = dx_except == EXCEPT_INSTR_ILLEGAL; wire x_except_invalid_instr = d_except == EXCEPT_INSTR_ILLEGAL;
assign x_trap_exit = dx_except == EXCEPT_MRET && !(x_stall || m_jump_req); 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_enter_rdy = !(x_stall || m_jump_req || x_trap_exit);
wire x_trap_is_exception; // diagnostic wire x_trap_is_exception; // diagnostic
@ -380,8 +366,8 @@ always @ (posedge clk) begin
end end
`endif `endif
wire [W_DATA-1:0] x_csr_wdata = dx_csr_w_imm ? wire [W_DATA-1:0] x_csr_wdata = d_csr_w_imm ?
{{W_DATA-5{1'b0}}, dx_rs1} : x_rs1_bypass; {{W_DATA-5{1'b0}}, d_rs1} : x_rs1_bypass;
wire [W_DATA-1:0] x_csr_rdata; wire [W_DATA-1:0] x_csr_rdata;
@ -394,21 +380,21 @@ hazard3_csr #(
// CSR access port // CSR access port
// *en_soon are early access strobes which are not a function of bus stall. // *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. // 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), .wdata (x_csr_wdata),
.wen_soon (dx_csr_wen), .wen_soon (d_csr_wen),
.wen (dx_csr_wen && !(x_stall || flush_d_x)), .wen (d_csr_wen && !(x_stall || flush_d_x)),
.wtype (dx_csr_wtype), .wtype (d_csr_wtype),
.rdata (x_csr_rdata), .rdata (x_csr_rdata),
.ren_soon (dx_csr_ren), .ren_soon (d_csr_ren),
.ren (dx_csr_ren && !(x_stall || flush_d_x)), .ren (d_csr_ren && !(x_stall || flush_d_x)),
// Trap signalling // Trap signalling
.trap_addr (x_trap_addr), .trap_addr (x_trap_addr),
.trap_enter_vld (x_trap_enter), .trap_enter_vld (x_trap_enter),
.trap_enter_rdy (x_trap_enter_rdy), .trap_enter_rdy (x_trap_enter_rdy),
.trap_exit (x_trap_exit), .trap_exit (x_trap_exit),
.trap_is_exception (x_trap_is_exception), .trap_is_exception (x_trap_is_exception),
.mepc_in (dx_pc), .mepc_in (d_pc),
.mepc_out (x_mepc), .mepc_out (x_mepc),
// IRQ and exception requests // IRQ and exception requests
.irq (irq), .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_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); && !(x_muldiv_posted || x_stall_raw || x_muldiv_kill);
hazard3_muldiv_seq #( hazard3_muldiv_seq #(
@ -458,7 +444,7 @@ if (EXTENSION_M) begin: has_muldiv
) muldiv ( ) muldiv (
.clk (clk), .clk (clk),
.rst_n (rst_n), .rst_n (rst_n),
.op (dx_mulop), .op (d_mulop),
.op_vld (x_muldiv_op_vld), .op_vld (x_muldiv_op_vld),
.op_rdy (x_muldiv_op_rdy), .op_rdy (x_muldiv_op_rdy),
.op_kill (x_muldiv_kill), .op_kill (x_muldiv_kill),
@ -472,17 +458,17 @@ if (EXTENSION_M) begin: has_muldiv
// TODO fusion of MULHx->MUL and DIVy->REMy sequences // TODO fusion of MULHx->MUL and DIVy->REMy sequences
wire x_muldiv_result_is_high = wire x_muldiv_result_is_high =
dx_mulop == M_OP_MULH || d_mulop == M_OP_MULH ||
dx_mulop == M_OP_MULHSU || d_mulop == M_OP_MULHSU ||
dx_mulop == M_OP_MULHU || d_mulop == M_OP_MULHU ||
dx_mulop == M_OP_REM || d_mulop == M_OP_REM ||
dx_mulop == M_OP_REMU; d_mulop == M_OP_REMU;
assign x_muldiv_result = x_muldiv_result_is_high ? x_muldiv_result_h : x_muldiv_result_l; 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; assign x_stall_muldiv = x_muldiv_op_vld || !x_muldiv_result_vld;
if (MUL_FAST) begin: has_fast_mul 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 #( hazard3_mul_fast #(
.XLEN(W_DATA) .XLEN(W_DATA)
@ -506,7 +492,7 @@ if (EXTENSION_M) begin: has_muldiv
end end
`ifdef FORMAL `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 `endif
end else begin: no_muldiv end else begin: no_muldiv
@ -519,37 +505,23 @@ end else begin: no_muldiv
end end
endgenerate endgenerate
// State machine and branch detection // State machine
always @ (posedge clk or negedge rst_n) begin always @ (posedge clk or negedge rst_n) begin
if (!rst_n) begin if (!rst_n) begin
xm_jump <= 1'b0;
xm_memop <= MEMOP_NONE; xm_memop <= MEMOP_NONE;
{xm_rs1, xm_rs2, xm_rd} <= {3 * W_REGADDR{1'b0}}; {xm_rs1, xm_rs2, xm_rd} <= {3 * W_REGADDR{1'b0}};
end else begin end else begin
// TODO: this assertion may become untrue depending on how we handle exceptions/IRQs when stalled? // 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 //`ASSERT(!(m_stall && flush_d_x));// bubble insertion logic below is broken otherwise
if (!m_stall) begin 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 // 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 if (x_stall || flush_d_x || x_trap_enter) begin
// Insert bubble // Insert bubble
xm_rd <= {W_REGADDR{1'b0}}; xm_rd <= {W_REGADDR{1'b0}};
xm_jump <= 1'b0;
xm_memop <= MEMOP_NONE; xm_memop <= MEMOP_NONE;
end 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 end
end end
@ -558,16 +530,34 @@ end
always @ (posedge clk) always @ (posedge clk)
if (!m_stall) begin if (!m_stall) begin
xm_result <= xm_result <=
dx_result_is_linkaddr ? dx_mispredict_addr : d_result_is_linkaddr ? d_mispredict_addr :
dx_csr_ren ? x_csr_rdata : d_csr_ren ? x_csr_rdata :
EXTENSION_M && dx_aluop == ALUOP_MULDIV ? x_muldiv_result : EXTENSION_M && d_aluop == ALUOP_MULDIV ? x_muldiv_result :
x_alu_result; x_alu_result;
xm_store_data <= x_rs2_bypass; xm_store_data <= x_rs2_bypass;
xm_jump_target <= x_jump_target;
end 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 ( hazard3_alu alu (
.aluop (dx_aluop), .aluop (d_aluop),
.op_a (x_op_a), .op_a (x_op_a),
.op_b (x_op_b), .op_b (x_op_b),
.result (x_alu_result), .result (x_alu_result),
@ -575,15 +565,12 @@ hazard3_alu alu (
.cmp (x_alu_cmp) .cmp (x_alu_cmp)
); );
// ============================================================================ // ----------------------------------------------------------------------------
// Pipe Stage M // Pipe Stage M
// ============================================================================
reg [W_DATA-1:0] m_rdata_shift; reg [W_DATA-1:0] m_rdata_shift;
reg [W_DATA-1:0] m_wdata; reg [W_DATA-1:0] m_wdata;
reg [W_DATA-1:0] m_result; 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); 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) if (!m_stall)
mw_result <= m_result; mw_result <= m_result;
// ============================================================================ // ----------------------------------------------------------------------------
// Pipe Stage W // Pipe Stage W
// ============================================================================
// mw_result and mw_rd register the most recent write to the register file, // mw_result and mw_rd register the most recent write to the register file,
// so that X can bypass them in. // so that X can bypass them in.
@ -686,12 +672,12 @@ hazard3_regfile_1w2r #(
) inst_regfile_1w2r ( ) inst_regfile_1w2r (
.clk (clk), .clk (clk),
.rst_n (rst_n), .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. // so that output does not change.
.raddr1 (x_stall ? dx_rs1 : d_rs1), .raddr1 (x_stall ? d_rs1 : f_rs1),
.rdata1 (dx_rdata1), .rdata1 (x_rdata1),
.raddr2 (x_stall ? dx_rs2 : d_rs2), .raddr2 (x_stall ? d_rs2 : f_rs2),
.rdata2 (dx_rdata2), .rdata2 (x_rdata2),
.waddr (xm_rd), .waddr (xm_rd),
.wdata (m_result), .wdata (m_result),

View File

@ -29,7 +29,7 @@ module hazard3_decode #(
output wire df_cir_lock, output wire df_cir_lock,
output reg d_jump_req, output reg d_jump_req,
output reg [W_ADDR-1:0] d_jump_target, 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, output wire d_stall,
input wire x_stall, input wire x_stall,
@ -38,29 +38,26 @@ module hazard3_decode #(
input wire f_jump_now, input wire f_jump_now,
input wire [W_ADDR-1:0] f_jump_target, input wire [W_ADDR-1:0] f_jump_target,
output reg [W_REGADDR-1:0] d_rs1, // combinatorial output reg [W_DATA-1:0] d_imm,
output reg [W_REGADDR-1:0] d_rs2, // combinatorial output reg [W_REGADDR-1:0] d_rs1,
output reg [W_REGADDR-1:0] d_rs2,
output reg [W_DATA-1:0] dx_imm, output reg [W_REGADDR-1:0] d_rd,
output reg [W_REGADDR-1:0] dx_rs1, output reg [W_ALUSRC-1:0] d_alusrc_a,
output reg [W_REGADDR-1:0] dx_rs2, output reg [W_ALUSRC-1:0] d_alusrc_b,
output reg [W_REGADDR-1:0] dx_rd, output reg [W_ALUOP-1:0] d_aluop,
output reg [W_ALUSRC-1:0] dx_alusrc_a, output reg [W_MEMOP-1:0] d_memop,
output reg [W_ALUSRC-1:0] dx_alusrc_b, output reg [W_MULOP-1:0] d_mulop,
output reg [W_ALUOP-1:0] dx_aluop, output reg d_csr_ren,
output reg [W_MEMOP-1:0] dx_memop, output reg d_csr_wen,
output reg [W_MULOP-1:0] dx_mulop, output reg [1:0] d_csr_wtype,
output reg dx_csr_ren, output reg d_csr_w_imm,
output reg dx_csr_wen, output reg [W_BCOND-1:0] d_branchcond,
output reg [1:0] dx_csr_wtype, output reg [W_ADDR-1:0] d_jump_target,
output reg dx_csr_w_imm, output reg d_jump_is_regoffs,
output reg [W_BCOND-1:0] dx_branchcond, output reg d_result_is_linkaddr,
output reg [W_ADDR-1:0] dx_jump_target, output reg [W_ADDR-1:0] d_pc,
output reg dx_jump_is_regoffs, output reg [W_ADDR-1:0] d_mispredict_addr,
output reg dx_result_is_linkaddr, output reg [2:0] d_except
output reg [W_ADDR-1:0] dx_pc,
output reg [W_ADDR-1:0] dx_mispredict_addr,
output reg [2:0] dx_except
); );
`include "rv_opcodes.vh" `include "rv_opcodes.vh"
@ -165,39 +162,17 @@ always @ (*) begin
d_jump_target = pc + d_jump_offs; d_jump_target = pc + d_jump_offs;
casez ({d_instr[31], d_instr}) casez (d_instr)
{1'b1, RV_BEQ }: d_jump_req = jump_enable; RV_JAL: 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;
default: d_jump_req = 1'b0; default: d_jump_req = 1'b0;
endcase endcase
d_mispredict_addr = pc_next;
end end
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Decode X controls // 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}}; localparam X0 = {W_REGADDR{1'b0}};
always @ (*) begin always @ (*) begin
@ -206,7 +181,6 @@ always @ (*) begin
d_rs2 = d_instr[24:20]; d_rs2 = d_instr[24:20];
d_rd = d_instr[11: 7]; d_rd = d_instr[11: 7];
d_imm = d_imm_i; d_imm = d_imm_i;
d_branchoffs = d_imm_i;
d_alusrc_a = ALUSRCA_RS1; d_alusrc_a = ALUSRCA_RS1;
d_alusrc_b = ALUSRCB_RS2; d_alusrc_b = ALUSRCB_RS2;
d_aluop = ALUOP_ADD; 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 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 default: begin d_invalid_32bit = 1'b1; end
endcase endcase
end
if (d_invalid || d_starved) begin
always @ (posedge clk or negedge rst_n) begin d_rs1 = {W_REGADDR{1'b0}};
if (!rst_n) begin d_rs2 = {W_REGADDR{1'b0}};
{dx_rs1, dx_rs2, dx_rd} <= {(3 * W_REGADDR){1'b0}}; d_rd = {W_REGADDR{1'b0}};
dx_alusrc_a <= ALUSRCA_RS1; d_memop = MEMOP_NONE;
dx_alusrc_b <= ALUSRCB_RS2; d_branchcond = BCOND_NEVER;
dx_aluop <= ALUOP_ADD; d_csr_ren = 1'b0;
dx_memop <= MEMOP_NONE; d_csr_wen = 1'b0;
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 (EXTENSION_M) if (EXTENSION_M)
dx_aluop <= ALUOP_ADD; d_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;
// These can't if (d_invalid && !d_starved)
dx_alusrc_a <= d_alusrc_a; d_except = EXCEPT_INSTR_ILLEGAL;
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
end end
end end

View File

@ -36,11 +36,17 @@ module hazard3_frontend #(
output reg [1:0] cir_vld, // number of valid halfwords in CIR 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 input wire [1:0] cir_use, // number of halfwords D intends to consume
// *may* be a function of hready // *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, // Assert simultaneously with a jump request,
// if decode is going to stall. This stops the CIR // if decode is going to stall. This stops the CIR
// from being trashed by incoming fetch data; // from being trashed by incoming fetch data;
// jump instructions have other side effects besides jumping! // 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 `undef ASSERT
@ -50,19 +56,12 @@ module hazard3_frontend #(
`define ASSERT(x) `define ASSERT(x)
`endif `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; localparam W_BUNDLE = W_DATA / 2;
parameter W_FIFO_LEVEL = $clog2(FIFO_DEPTH + 1); parameter W_FIFO_LEVEL = $clog2(FIFO_DEPTH + 1);
// ============================================================================ // ----------------------------------------------------------------------------
// Fetch Queue (FIFO) // Fetch Queue (FIFO)
// ============================================================================ //
// This is a little different from either a normal sync fifo or sync fwft fifo // This is a little different from either a normal sync fifo or sync fwft fifo
// so it's worth implementing from scratch // so it's worth implementing from scratch
@ -105,9 +104,8 @@ always @ (posedge clk) begin: fifo_data_shift
end end
end end
// ============================================================================ // ----------------------------------------------------------------------------
// Fetch Request + State Logic // Fetch Request + State Logic
// ============================================================================
// Keep track of some useful state of the memory interface // Keep track of some useful state of the memory interface
@ -230,10 +228,8 @@ end
assign jump_target_rdy = !mem_addr_hold; assign jump_target_rdy = !mem_addr_hold;
// ----------------------------------------------------------------------------
// ============================================================================
// Instruction assembly yard // Instruction assembly yard
// ============================================================================
// buf_level is the number of valid halfwords in {hwbuf, cir}. // buf_level is the number of valid halfwords in {hwbuf, cir}.
// cir_vld and hwbuf_vld are functions of this. // cir_vld and hwbuf_vld are functions of this.
@ -298,4 +294,21 @@ end
always @ (posedge clk) always @ (posedge clk)
{hwbuf, cir} <= instr_data_plus_fetch; {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 endmodule

1
scripts Submodule

@ -0,0 +1 @@
Subproject commit 24f0f32b1d91e7bb873ebefb997c324dbe90a325

1
sourceme Normal file
View File

@ -0,0 +1 @@
export PATH="$PATH:$PWD/scripts"

View File

@ -1,19 +1,67 @@
TEST = I-ADD-01 TEST_ARCH = I
TEST_ARCH = rv32i
BIN_ARCH = rv32i BIN_ARCH = rv32i
SIM_EXEC = ../tb_cxxrtl/tb SIM_EXEC = ../tb_cxxrtl/tb
CROSS_PREFIX = /opt/riscv/bin/riscv32-unknown-elf- CROSS_PREFIX = /opt/riscv/bin/riscv32-unknown-elf-
TEST_BIN_NAME := $(TEST_ARCH)-$(TEST)-on-$(BIN_ARCH) TESTLIST= \
TEST_SRC := riscv-compliance/riscv-test-suite/$(TEST_ARCH)/src/$(TEST).S add-01 \
TEST_VEC := riscv-compliance/riscv-test-suite/$(TEST_ARCH)/references/$(TEST).reference_output 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 .PHONY: all testlist clean $(addprefix test-,$(TESTLIST))
all: 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 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)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 -d tmp/$(TEST_BIN_NAME).elf > tmp/$(TEST_BIN_NAME).dis $(CROSS_PREFIX)objdump -h tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).elf > tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).dis
$(CROSS_PREFIX)objcopy -O binary tmp/$(TEST_BIN_NAME).elf tmp/$(TEST_BIN_NAME).bin $(CROSS_PREFIX)objdump -d tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).elf >> tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).dis
$(SIM_EXEC) tmp/$(TEST_BIN_NAME).bin --dump 0x10000 0x10100 | tee tmp/$(TEST_BIN_NAME).log $(CROSS_PREFIX)objcopy -O binary tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).elf tmp/$(TEST_ARCH)-$1-on-$(BIN_ARCH).bin
./compare_testvec tmp/$(TEST_BIN_NAME).log $(TEST_VEC) $(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/

View File

@ -37,4 +37,4 @@ for i, g in enumerate(gold):
if all_match: if all_match:
print("Test PASSED.") print("Test PASSED.")
else: else:
print("Test FAILED.") sys.exit("Test FAILED.")

View File

@ -0,0 +1 @@
../riscv-arch-test/riscv-test-env/arch_test.h

View File

@ -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_

View File

@ -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_

View File

@ -0,0 +1 @@
../riscv-arch-test/riscv-test-env/encoding.h

View File

@ -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

View File

@ -1 +0,0 @@
../riscv-compliance/riscv-test-env/riscv_test_macros.h

View File

@ -1,6 +1,6 @@
MEMORY MEMORY
{ {
RAM (wx) : ORIGIN = 0x0, LENGTH = 64k RAM (wx) : ORIGIN = 0x0, LENGTH = 4M
RESULT (w) : ORIGIN = ORIGIN(RAM) + LENGTH(RAM), LENGTH = 64k RESULT (w) : ORIGIN = ORIGIN(RAM) + LENGTH(RAM), LENGTH = 64k
} }
@ -11,9 +11,6 @@ ENTRY(_start)
SECTIONS SECTIONS
{ {
.text : { .text : {
/* Padding in place of vector table (by default CPU reset vector points to
immediately after vector table */
. = ORIGIN(RAM) + 0xc0;
PROVIDE (_start = .); PROVIDE (_start = .);
*(.text*) *(.text*)
. = ALIGN(4); . = ALIGN(4);

@ -0,0 +1 @@
Subproject commit b436dd0939c968f2c3da86bb9b63bb2dfe03b134