Add basic support for lr/sc instructions from the A extension
This commit is contained in:
parent
c5d6be24f3
commit
5e17bb805e
|
@ -4,6 +4,7 @@ Hazard3 is a 3-stage RISC-V processor, implementing the `RV32I` instruction set
|
|||
|
||||
* `M`: integer multiply/divide/modulo
|
||||
* `C`: compressed instructions
|
||||
* `A` _(partial)_: load reserved/store conditional instructions, with AHB5 HEXCL/HEXOKAY signalling for global monitor queries
|
||||
* `Zicsr`: CSR access
|
||||
* `Zba`: address generation
|
||||
* `Zbb`: basic bit manipulation
|
||||
|
@ -23,7 +24,8 @@ _Note: the bit manipulation instructions don't have upstream compliance tests at
|
|||
|
||||
The following are planned for future implementation:
|
||||
|
||||
* `A` extension: atomic memory access
|
||||
* Complete support for the `A` extension: atomic memory operations
|
||||
* Debug trigger unit (breakpoint-only)
|
||||
|
||||
Hazard3 is still under development.
|
||||
|
||||
|
|
8674
doc/hazard3.pdf
8674
doc/hazard3.pdf
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
== Instruction Cycle Counts
|
||||
|
||||
All timings are given assuming perfect bus behaviour (no stalls). Stalling of the `I` bus can delay execution indefinitely, as can stalling of the `D` bus during a load or store.
|
||||
All timings are given assuming perfect bus behaviour (no downstream bus stalls).
|
||||
|
||||
=== RV32I
|
||||
|
||||
|
@ -72,6 +72,17 @@ Timings assume the core is configured with `MULDIV_UNROLL = 2` and `MUL_FAST = 1
|
|||
| `remu rd, rs1, rs2` | 18 |
|
||||
|===
|
||||
|
||||
=== A Extension
|
||||
|
||||
[%autowidth.stretch, options="header"]
|
||||
|===
|
||||
| Instruction | Cycles | Note
|
||||
| `lr.w rd, (rs1)` | 1 or 2 | 1 if next instruction is independent, 2 if dependent.footnote:data_dependency[]
|
||||
| `sc.w rd, rs2, (rs1)` | 1 | `lr.w` followed by `sc.w` always inserts a dependency stall.footnote:lr_to_sc[A 1-cycle pipeline bubble is inserted in between an `lr.w` and an immediately-following `sc.w`, so that the store can be suppressed by a reservation failure on the load. It does not matter whether the `lr.w` and `sc.w` use the same registers. Load reservation may fail if the memory region does not support exclusive transfers.]
|
||||
|===
|
||||
|
||||
AMOs are currently not supported.
|
||||
|
||||
=== C Extension
|
||||
|
||||
All C extension 16-bit instructions on Hazard3 are aliases of base RV32I instructions. They perform identically to their 32-bit counterparts.
|
||||
|
|
|
@ -221,8 +221,10 @@ wire [2:0] proc_hsize;
|
|||
wire [2:0] proc_hburst;
|
||||
wire [3:0] proc_hprot;
|
||||
wire proc_hmastlock;
|
||||
wire proc_hexcl;
|
||||
wire proc_hready;
|
||||
wire proc_hresp;
|
||||
wire proc_hexokay = 1'b1; // No global monitor
|
||||
wire [W_DATA-1:0] proc_hwdata;
|
||||
wire [W_DATA-1:0] proc_hrdata;
|
||||
|
||||
|
@ -264,8 +266,10 @@ hazard3_cpu_1port #(
|
|||
.ahblm_hburst (proc_hburst),
|
||||
.ahblm_hprot (proc_hprot),
|
||||
.ahblm_hmastlock (proc_hmastlock),
|
||||
.ahblm_hexcl (proc_hexcl),
|
||||
.ahblm_hready (proc_hready),
|
||||
.ahblm_hresp (proc_hresp),
|
||||
.ahblm_hexokay (proc_hexokay),
|
||||
.ahblm_hwdata (proc_hwdata),
|
||||
.ahblm_hrdata (proc_hrdata),
|
||||
|
||||
|
|
|
@ -31,6 +31,10 @@ parameter MTVEC_INIT = 32'h00000000,
|
|||
// ----------------------------------------------------------------------------
|
||||
// RISC-V ISA and CSR support
|
||||
|
||||
// EXTENSION_A: Support for atomic read/modify/write instructions
|
||||
// (currently, only lr.w/sc.w are supported)
|
||||
parameter EXTENSION_A = 1,
|
||||
|
||||
// EXTENSION_C: Support for compressed (variable-width) instructions
|
||||
parameter EXTENSION_C = 1,
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
.RESET_VECTOR (RESET_VECTOR),
|
||||
.MTVEC_INIT (MTVEC_INIT),
|
||||
.EXTENSION_A (EXTENSION_A),
|
||||
.EXTENSION_C (EXTENSION_C),
|
||||
.EXTENSION_M (EXTENSION_M),
|
||||
.EXTENSION_ZBA (EXTENSION_ZBA),
|
||||
|
|
|
@ -43,9 +43,11 @@ module hazard3_core #(
|
|||
|
||||
// Load/store port
|
||||
output reg bus_aph_req_d,
|
||||
output wire bus_aph_excl_d,
|
||||
input wire bus_aph_ready_d,
|
||||
input wire bus_dph_ready_d,
|
||||
input wire bus_dph_err_d,
|
||||
input wire bus_dph_exokay_d,
|
||||
|
||||
output reg [W_ADDR-1:0] bus_haddr_d,
|
||||
output reg [2:0] bus_hsize_d,
|
||||
|
@ -300,6 +302,9 @@ always @ (*) begin
|
|||
x_stall_raw =
|
||||
|xm_rd && (xm_rd == d_rs1 || xm_rd == d_rs2) ||
|
||||
|mw_rd && (mw_rd == d_rs1 || mw_rd == d_rs2);
|
||||
end else if (|EXTENSION_A && xm_memop == MEMOP_LR_W && d_memop == MEMOP_SC_W) begin
|
||||
// Conditional-store address phase depends on data-phase update of local monitor bit
|
||||
x_stall_raw = 1'b1;
|
||||
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 == d_rs1) begin
|
||||
|
@ -358,13 +363,24 @@ hazard3_alu #(
|
|||
|
||||
// AHB transaction request
|
||||
|
||||
wire x_memop_vld = !d_memop[3];
|
||||
wire x_memop_write = d_memop == MEMOP_SW || d_memop == MEMOP_SH || d_memop == MEMOP_SB;
|
||||
reg mw_local_exclusive_reserved;
|
||||
|
||||
wire x_memop_vld = d_memop != MEMOP_NONE && !(
|
||||
|EXTENSION_A && d_memop == MEMOP_SC_W && !mw_local_exclusive_reserved
|
||||
);
|
||||
|
||||
wire x_memop_write =
|
||||
d_memop == MEMOP_SW || d_memop == MEMOP_SH || d_memop == MEMOP_SB ||
|
||||
|EXTENSION_A && d_memop == MEMOP_SC_W;
|
||||
|
||||
wire x_unaligned_addr = d_memop != MEMOP_NONE && (
|
||||
bus_hsize_d == HSIZE_WORD && |bus_haddr_d[1:0] ||
|
||||
bus_hsize_d == HSIZE_HWORD && bus_haddr_d[0]
|
||||
);
|
||||
|
||||
// Always query the global monitor, except for store-conditional suppressed by local monitor.
|
||||
assign bus_aph_excl_d = |EXTENSION_A && (d_memop == MEMOP_LR_W || d_memop == MEMOP_SC_W);
|
||||
|
||||
always @ (*) begin
|
||||
// Need to be careful not to use anything hready-sourced to gate htrans!
|
||||
bus_haddr_d = x_alu_add;
|
||||
|
@ -609,7 +625,9 @@ always @ (posedge clk or negedge rst_n) begin
|
|||
`ifdef FORMAL
|
||||
assert(xm_memop != MEMOP_NONE);
|
||||
`endif
|
||||
xm_except <= xm_memop <= MEMOP_LBU ? EXCEPT_LOAD_FAULT : EXCEPT_STORE_FAULT;
|
||||
xm_except <=
|
||||
|EXTENSION_A && xm_memop == MEMOP_LR_W ? EXCEPT_LOAD_FAULT :
|
||||
xm_memop <= MEMOP_LBU ? EXCEPT_LOAD_FAULT : EXCEPT_STORE_FAULT;
|
||||
xm_wfi <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
@ -648,7 +666,10 @@ assign f_jump_req = x_jump_req || m_trap_enter_vld;
|
|||
assign f_jump_target = m_trap_enter_vld ? m_trap_addr : x_jump_target;
|
||||
assign x_jump_not_except = !m_trap_enter_vld;
|
||||
|
||||
wire m_bus_stall = xm_memop != MEMOP_NONE && !bus_dph_ready_d;
|
||||
wire m_bus_stall = xm_memop != MEMOP_NONE && !bus_dph_ready_d && !(
|
||||
|EXTENSION_A && xm_memop == MEMOP_SC_W && !mw_local_exclusive_reserved
|
||||
);
|
||||
|
||||
assign m_stall = m_bus_stall ||
|
||||
(m_trap_enter_vld && !m_trap_enter_rdy && !m_trap_is_irq) ||
|
||||
(xm_wfi && !m_wfi_stall_clear);
|
||||
|
@ -672,10 +693,9 @@ always @ (*) begin
|
|||
end
|
||||
// Replicate store data to ensure appropriate byte lane is driven
|
||||
case (xm_memop)
|
||||
MEMOP_SW: bus_wdata_d = m_wdata;
|
||||
MEMOP_SH: bus_wdata_d = {2{m_wdata[15:0]}};
|
||||
MEMOP_SB: bus_wdata_d = {4{m_wdata[7:0]}};
|
||||
default: bus_wdata_d = 32'h0;
|
||||
default: bus_wdata_d = m_wdata; // TODO worth it to mask when not writing? Costs LUTs, saves energy
|
||||
endcase
|
||||
|
||||
casez ({xm_memop, xm_result[1:0]})
|
||||
|
@ -694,7 +714,10 @@ always @ (*) begin
|
|||
default: m_rdata_pick_sext = bus_rdata_d;
|
||||
endcase
|
||||
|
||||
if (xm_memop != MEMOP_NONE) begin
|
||||
if (|EXTENSION_A && xm_memop == MEMOP_SC_W) begin
|
||||
// sc.w may fail due to negative response from either local or global monitor.
|
||||
m_result = {31'h0, mw_local_exclusive_reserved && bus_dph_exokay_d};
|
||||
end else if (xm_memop != MEMOP_NONE) begin
|
||||
m_result = m_rdata_pick_sext;
|
||||
end else if (MUL_FAST && m_fast_mul_result_vld) begin
|
||||
m_result = m_fast_mul_result;
|
||||
|
@ -703,11 +726,28 @@ always @ (*) begin
|
|||
end
|
||||
end
|
||||
|
||||
// Local monitor update.
|
||||
// - Set on a load-reserved with good response from global monitor
|
||||
// - Cleared by any store-conditional
|
||||
// - Not affected by trap entry (permitted by RISC-V spec)
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
mw_local_exclusive_reserved <= 1'b0;
|
||||
end else if (|EXTENSION_A && !m_stall) begin
|
||||
if (xm_memop == MEMOP_SC_W) begin
|
||||
mw_local_exclusive_reserved <= 1'b0;
|
||||
end else if (xm_memop == MEMOP_LR_W) begin
|
||||
mw_local_exclusive_reserved <= bus_dph_exokay_d;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Note that exception entry prevents writeback, because the exception entry
|
||||
// replaces the instruction in M. Interrupt entry does not prevent writeback,
|
||||
// because the interrupt is notionally inserted in between the instruction in
|
||||
// M and the instruction in X.
|
||||
|
||||
wire m_reg_wen_if_nonzero = !m_bus_stall && xm_except == EXCEPT_NONE;
|
||||
wire m_reg_wen = |xm_rd && m_reg_wen_if_nonzero;
|
||||
|
||||
|
|
|
@ -40,8 +40,10 @@ module hazard3_cpu_1port #(
|
|||
output wire [2:0] ahblm_hburst,
|
||||
output reg [3:0] ahblm_hprot,
|
||||
output wire ahblm_hmastlock,
|
||||
output reg ahblm_hexcl,
|
||||
input wire ahblm_hready,
|
||||
input wire ahblm_hresp,
|
||||
input wire ahblm_hexokay,
|
||||
output wire [W_DATA-1:0] ahblm_hwdata,
|
||||
input wire [W_DATA-1:0] ahblm_hrdata,
|
||||
|
||||
|
@ -85,9 +87,11 @@ wire [W_DATA-1:0] core_rdata_i;
|
|||
|
||||
// Load/store signals
|
||||
wire core_aph_req_d;
|
||||
wire core_aph_excl_d;
|
||||
wire core_aph_ready_d;
|
||||
wire core_dph_ready_d;
|
||||
wire core_dph_err_d;
|
||||
wire core_dph_exokay_d;
|
||||
|
||||
wire [W_ADDR-1:0] core_haddr_d;
|
||||
wire [2:0] core_hsize_d;
|
||||
|
@ -116,9 +120,11 @@ hazard3_core #(
|
|||
.bus_rdata_i (core_rdata_i),
|
||||
|
||||
.bus_aph_req_d (core_aph_req_d),
|
||||
.bus_aph_excl_d (core_aph_excl_d),
|
||||
.bus_aph_ready_d (core_aph_ready_d),
|
||||
.bus_dph_ready_d (core_dph_ready_d),
|
||||
.bus_dph_err_d (core_dph_err_d),
|
||||
.bus_dph_exokay_d (core_dph_exokay_d),
|
||||
.bus_haddr_d (core_haddr_d),
|
||||
.bus_hsize_d (core_hsize_d),
|
||||
.bus_hwrite_d (core_hwrite_d),
|
||||
|
@ -144,7 +150,6 @@ hazard3_core #(
|
|||
.timer_irq (timer_irq)
|
||||
);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Arbitration state machine
|
||||
|
||||
|
@ -201,18 +206,21 @@ assign ahblm_hmastlock = 1'b0;
|
|||
always @ (*) begin
|
||||
if (bus_gnt_d) begin
|
||||
ahblm_htrans = HTRANS_NSEQ;
|
||||
ahblm_hexcl = core_aph_excl_d;
|
||||
ahblm_haddr = core_haddr_d;
|
||||
ahblm_hsize = core_hsize_d;
|
||||
ahblm_hwrite = core_hwrite_d;
|
||||
ahblm_hprot = HPROT_DATA;
|
||||
end else if (bus_gnt_i) begin
|
||||
ahblm_htrans = HTRANS_NSEQ;
|
||||
ahblm_hexcl = 1'b0;
|
||||
ahblm_haddr = core_haddr_i;
|
||||
ahblm_hsize = core_hsize_i;
|
||||
ahblm_hwrite = 1'b0;
|
||||
ahblm_hprot = HPROT_INSTR;
|
||||
end else begin
|
||||
ahblm_htrans = HTRANS_IDLE;
|
||||
ahblm_hexcl = 1'b0;
|
||||
ahblm_haddr = {W_ADDR{1'b0}};
|
||||
ahblm_hsize = 3'h0;
|
||||
ahblm_hwrite = 1'b0;
|
||||
|
@ -239,6 +247,7 @@ assign core_dph_err_i = bus_active_dph_i && ahblm_hresp;
|
|||
assign core_aph_ready_d = ahblm_hready && bus_gnt_d;
|
||||
assign core_dph_ready_d = ahblm_hready && bus_active_dph_d;
|
||||
assign core_dph_err_d = bus_active_dph_d && ahblm_hresp;
|
||||
assign core_dph_exokay_d = bus_active_dph_d && ahblm_hexokay;
|
||||
|
||||
endmodule
|
||||
|
||||
|
|
|
@ -53,8 +53,10 @@ module hazard3_cpu_2port #(
|
|||
output wire [2:0] d_hburst,
|
||||
output wire [3:0] d_hprot,
|
||||
output wire d_hmastlock,
|
||||
output wire d_hexcl,
|
||||
input wire d_hready,
|
||||
input wire d_hresp,
|
||||
input wire d_hexokay,
|
||||
output wire [W_DATA-1:0] d_hwdata,
|
||||
input wire [W_DATA-1:0] d_hrdata,
|
||||
|
||||
|
@ -98,9 +100,11 @@ wire [W_DATA-1:0] core_rdata_i;
|
|||
|
||||
// Load/store signals
|
||||
wire core_aph_req_d;
|
||||
wire core_aph_excl_d;
|
||||
wire core_aph_ready_d;
|
||||
wire core_dph_ready_d;
|
||||
wire core_dph_err_d;
|
||||
wire core_dph_exokay_d;
|
||||
|
||||
wire [W_ADDR-1:0] core_haddr_d;
|
||||
wire [2:0] core_hsize_d;
|
||||
|
@ -112,8 +116,8 @@ wire [W_DATA-1:0] core_rdata_d;
|
|||
hazard3_core #(
|
||||
`include "hazard3_config_inst.vh"
|
||||
) core (
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
|
||||
`ifdef RISCV_FORMAL
|
||||
`RVFI_CONN ,
|
||||
|
@ -129,9 +133,11 @@ hazard3_core #(
|
|||
.bus_rdata_i (core_rdata_i),
|
||||
|
||||
.bus_aph_req_d (core_aph_req_d),
|
||||
.bus_aph_excl_d (core_aph_excl_d),
|
||||
.bus_aph_ready_d (core_aph_ready_d),
|
||||
.bus_dph_ready_d (core_dph_ready_d),
|
||||
.bus_dph_err_d (core_dph_err_d),
|
||||
.bus_dph_exokay_d (core_dph_exokay_d),
|
||||
.bus_haddr_d (core_haddr_d),
|
||||
.bus_hsize_d (core_hsize_d),
|
||||
.bus_hwrite_d (core_hwrite_d),
|
||||
|
@ -193,6 +199,7 @@ assign d_haddr = core_haddr_d;
|
|||
assign d_htrans = core_aph_req_d ? HTRANS_NSEQ : HTRANS_IDLE;
|
||||
assign d_hwrite = core_hwrite_d;
|
||||
assign d_hsize = core_hsize_d;
|
||||
assign d_hexcl = core_aph_excl_d;
|
||||
|
||||
reg dphase_active_d;
|
||||
always @ (posedge clk or negedge rst_n)
|
||||
|
@ -207,6 +214,7 @@ always @ (posedge clk or negedge rst_n)
|
|||
assign core_aph_ready_d = d_hready && core_aph_req_d;
|
||||
assign core_dph_ready_d = d_hready && dphase_active_d;
|
||||
assign core_dph_err_d = dphase_active_d && d_hresp;
|
||||
assign core_dph_exokay_d = dphase_active_d && d_hexokay;
|
||||
|
||||
assign core_rdata_d = d_hrdata;
|
||||
assign d_hwdata = core_wdata_d;
|
||||
|
|
|
@ -234,6 +234,7 @@ always @ (*) begin
|
|||
RV_SB: begin d_aluop = ALUOP_ADD; d_imm = d_imm_s; d_alusrc_b = ALUSRCB_IMM; d_memop = MEMOP_SB; d_rd = X0; end
|
||||
RV_SH: begin d_aluop = ALUOP_ADD; d_imm = d_imm_s; d_alusrc_b = ALUSRCB_IMM; d_memop = MEMOP_SH; d_rd = X0; end
|
||||
RV_SW: begin d_aluop = ALUOP_ADD; d_imm = d_imm_s; d_alusrc_b = ALUSRCB_IMM; d_memop = MEMOP_SW; d_rd = X0; end
|
||||
|
||||
RV_MUL: if (EXTENSION_M) begin d_aluop = ALUOP_MULDIV; d_mulop = M_OP_MUL; end else begin d_invalid_32bit = 1'b1; end
|
||||
RV_MULH: if (EXTENSION_M) begin d_aluop = ALUOP_MULDIV; d_mulop = M_OP_MULH; end else begin d_invalid_32bit = 1'b1; end
|
||||
RV_MULHSU: if (EXTENSION_M) begin d_aluop = ALUOP_MULDIV; d_mulop = M_OP_MULHSU; end else begin d_invalid_32bit = 1'b1; end
|
||||
|
@ -242,9 +243,14 @@ always @ (*) begin
|
|||
RV_DIVU: if (EXTENSION_M) begin d_aluop = ALUOP_MULDIV; d_mulop = M_OP_DIVU; end else begin d_invalid_32bit = 1'b1; end
|
||||
RV_REM: if (EXTENSION_M) begin d_aluop = ALUOP_MULDIV; d_mulop = M_OP_REM; end else begin d_invalid_32bit = 1'b1; end
|
||||
RV_REMU: if (EXTENSION_M) begin d_aluop = ALUOP_MULDIV; d_mulop = M_OP_REMU; end else begin d_invalid_32bit = 1'b1; end
|
||||
|
||||
RV_LR_W: if (EXTENSION_A) begin d_imm = X0; d_alusrc_b = ALUSRCB_IMM; d_rs2 = X0; d_memop = MEMOP_LR_W; end
|
||||
RV_SC_W: if (EXTENSION_A) begin d_imm = X0; d_alusrc_b = ALUSRCB_IMM; d_memop = MEMOP_SC_W; end
|
||||
|
||||
RV_SH1ADD: if (EXTENSION_ZBA) begin d_aluop = ALUOP_SH1ADD; end else begin d_invalid_32bit = 1'b1; end
|
||||
RV_SH2ADD: if (EXTENSION_ZBA) begin d_aluop = ALUOP_SH2ADD; end else begin d_invalid_32bit = 1'b1; end
|
||||
RV_SH3ADD: if (EXTENSION_ZBA) begin d_aluop = ALUOP_SH3ADD; end else begin d_invalid_32bit = 1'b1; end
|
||||
|
||||
RV_ANDN: if (EXTENSION_ZBB) begin d_aluop = ALUOP_ANDN; end else begin d_invalid_32bit = 1'b1; end
|
||||
RV_CLZ: if (EXTENSION_ZBB) begin d_aluop = ALUOP_CLZ; d_rs2 = X0; end else begin d_invalid_32bit = 1'b1; end
|
||||
RV_CPOP: if (EXTENSION_ZBB) begin d_aluop = ALUOP_CPOP; d_rs2 = X0; end else begin d_invalid_32bit = 1'b1; end
|
||||
|
@ -263,6 +269,7 @@ always @ (*) begin
|
|||
RV_SEXT_H: if (EXTENSION_ZBB) begin d_aluop = ALUOP_SEXT_H; d_rs2 = X0; end else begin d_invalid_32bit = 1'b1; end
|
||||
RV_XNOR: if (EXTENSION_ZBB) begin d_aluop = ALUOP_XNOR; end else begin d_invalid_32bit = 1'b1; end
|
||||
RV_ZEXT_H: if (EXTENSION_ZBB) begin d_aluop = ALUOP_ZEXT_H; d_rs2 = X0; end else begin d_invalid_32bit = 1'b1; end
|
||||
|
||||
RV_CLMUL: if (EXTENSION_ZBC) begin d_aluop = ALUOP_CLMUL; end else begin d_invalid_32bit = 1'b1; end
|
||||
RV_CLMULH: if (EXTENSION_ZBC) begin d_aluop = ALUOP_CLMULH; end else begin d_invalid_32bit = 1'b1; end
|
||||
RV_CLMULR: if (EXTENSION_ZBC) begin d_aluop = ALUOP_CLMULR; end else begin d_invalid_32bit = 1'b1; end
|
||||
|
@ -274,6 +281,7 @@ always @ (*) begin
|
|||
RV_BINVI: if (EXTENSION_ZBC) begin d_aluop = ALUOP_BINV; d_rs2 = X0; d_imm = d_imm_i; d_alusrc_b = ALUSRCB_IMM; end else begin d_invalid_32bit = 1'b1; end
|
||||
RV_BSET: if (EXTENSION_ZBC) begin d_aluop = ALUOP_BSET; end else begin d_invalid_32bit = 1'b1; end
|
||||
RV_BSETI: if (EXTENSION_ZBC) begin d_aluop = ALUOP_BSET; d_rs2 = X0; d_imm = d_imm_i; d_alusrc_b = ALUSRCB_IMM; end else begin d_invalid_32bit = 1'b1; end
|
||||
|
||||
RV_FENCE: begin d_rd = X0; end // NOP
|
||||
RV_FENCE_I: begin d_invalid_32bit = DEBUG_SUPPORT && debug_mode; d_rd = X0; d_rs1 = X0; d_rs2 = X0; d_branchcond = BCOND_NZERO; d_imm[31] = 1'b1; end // FIXME this is probably busted now. Maybe implement as an exception?
|
||||
RV_CSRRW: if (HAVE_CSR) begin d_imm = d_imm_i; d_csr_wen = 1'b1 ; d_csr_ren = |d_rd; d_csr_wtype = CSR_WTYPE_W; end else begin d_invalid_32bit = 1'b1; end
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
SRCS := ../common/init.S main.c
|
||||
APP := lr_sc_smoke
|
||||
CCFLAGS = -march=rv32imac -Os
|
||||
|
||||
include ../common/src_only_app.mk
|
|
@ -0,0 +1,43 @@
|
|||
[*]
|
||||
[*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI
|
||||
[*] Sat Dec 4 14:31:51 2021
|
||||
[*]
|
||||
[dumpfile] "/home/luke/proj/hazard3/test/sim/lr_sc_smoke/lr_sc_smoke_run.vcd"
|
||||
[dumpfile_mtime] "Sat Dec 4 14:20:04 2021"
|
||||
[dumpfile_size] 2577335
|
||||
[savefile] "/home/luke/proj/hazard3/test/sim/lr_sc_smoke/lr_sc_smoke.gtkw"
|
||||
[timestart] 842
|
||||
[size] 1975 1095
|
||||
[pos] -1 -1
|
||||
*-2.000000 856 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
|
||||
[sst_width] 233
|
||||
[signals_width] 246
|
||||
[sst_expanded] 1
|
||||
[sst_vpaned_height] 317
|
||||
@22
|
||||
core.d_pc[31:0]
|
||||
@28
|
||||
core.mw_local_exclusive_reserved
|
||||
core.m_stall
|
||||
core.x_stall
|
||||
core.x_stall_raw
|
||||
@200
|
||||
-
|
||||
@22
|
||||
d_haddr[31:0]
|
||||
@28
|
||||
d_htrans[1:0]
|
||||
d_hsize[2:0]
|
||||
d_hexcl
|
||||
d_hwrite
|
||||
d_hready
|
||||
@22
|
||||
d_hwdata[31:0]
|
||||
d_hrdata[31:0]
|
||||
@200
|
||||
-
|
||||
@22
|
||||
core.x_rs2_bypass[31:0]
|
||||
core.xm_store_data[31:0]
|
||||
[pattern_trace] 1
|
||||
[pattern_trace] 0
|
|
@ -0,0 +1,65 @@
|
|||
#include "tb_cxxrtl_io.h"
|
||||
#include <stdint.h>
|
||||
|
||||
volatile uint32_t scratch[2];
|
||||
|
||||
#define test_assert(cond, ...) if (!(cond)) {tb_printf(__VA_ARGS__); return -1;}
|
||||
|
||||
int main() {
|
||||
uint32_t load_result, success;
|
||||
tb_puts("Test 1: lr.w -> nop -> sc.w\n");
|
||||
scratch[0] = 0x1234;
|
||||
asm volatile (
|
||||
"lr.w %0, (%2)\n"
|
||||
"nop\n"
|
||||
"sc.w %1, %3, (%2)\n"
|
||||
: "=r" (load_result), "=r" (success)
|
||||
: "r" (&scratch[0]), "r" (0x5678)
|
||||
);
|
||||
test_assert(load_result == 0x1234, "Bad load result %08x\n", load_result);
|
||||
test_assert(scratch[0] == 0x5678, "Store didn't write memory\n");
|
||||
test_assert(success == 1, "Should report success\n");
|
||||
tb_puts("OK\n");
|
||||
|
||||
tb_puts("Test 2: lr.w -> sc.w\n");
|
||||
scratch[0] = 0xabcd;
|
||||
asm volatile (
|
||||
"lr.w %0, (%2)\n"
|
||||
"sc.w %1, %3, (%2)\n"
|
||||
: "=r" (load_result), "=r" (success)
|
||||
: "r" (&scratch[0]), "r" (0xa5a5)
|
||||
);
|
||||
test_assert(load_result == 0xabcd, "Bad load result %08x\n", load_result);
|
||||
test_assert(scratch[0] == 0xa5a5, "Store didn't write memory\n");
|
||||
test_assert(success == 1, "Should report success\n");
|
||||
tb_puts("OK\n");
|
||||
|
||||
tb_puts("Test 3: sc.w with no preceding lr.w\n");
|
||||
scratch[0] = 0x1234;
|
||||
asm volatile (
|
||||
"sc.w %0, %2, (%1)\n"
|
||||
: "=r" (success)
|
||||
: "r" (&scratch[0]), "r" (0x5678)
|
||||
);
|
||||
test_assert(scratch[0] == 0x1234, "Store shouldn't write memory\n");
|
||||
test_assert(success == 0, "Should report failure\n");
|
||||
tb_puts("OK\n");
|
||||
|
||||
// Reservation is only cleared by other harts' stores.
|
||||
tb_puts("Test 4: lr.w -> sw -> sc.w\n");
|
||||
scratch[0] = 0x1234;
|
||||
scratch[1] = 0;
|
||||
asm volatile (
|
||||
"lr.w %0, (%2)\n"
|
||||
"sw %3, 4(%2)\n"
|
||||
"sc.w %1, %4, (%2)\n"
|
||||
: "=r" (load_result), "=r" (success)
|
||||
: "r" (&scratch[0]), "r" (0xabcd), "r" (0x5678)
|
||||
);
|
||||
test_assert(scratch[1] == 0xabcd, "Regular store should succeed\n");
|
||||
test_assert(scratch[0] == 0x5678, "sc didn't write memory\n");
|
||||
test_assert(success == 1, "Should report success\n");
|
||||
tb_puts("OK\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -153,6 +153,7 @@ int main(int argc, char **argv) {
|
|||
// Never generate bus stalls
|
||||
top.p_i__hready.set<bool>(true);
|
||||
top.p_d__hready.set<bool>(true);
|
||||
top.p_d__hexokay.set<bool>(true);
|
||||
|
||||
uint64_t mtime = 0;
|
||||
uint64_t mtimecmp = 0;
|
||||
|
|
|
@ -36,12 +36,14 @@ module tb #(
|
|||
output wire [W_ADDR-1:0] d_haddr,
|
||||
output wire d_hwrite,
|
||||
output wire [1:0] d_htrans,
|
||||
output wire d_hexcl,
|
||||
output wire [2:0] d_hsize,
|
||||
output wire [2:0] d_hburst,
|
||||
output wire [3:0] d_hprot,
|
||||
output wire d_hmastlock,
|
||||
input wire d_hready,
|
||||
input wire d_hresp,
|
||||
input wire d_hexokay,
|
||||
output wire [W_DATA-1:0] d_hwdata,
|
||||
input wire [W_DATA-1:0] d_hrdata,
|
||||
|
||||
|
@ -213,6 +215,7 @@ hazard3_cpu_2port #(
|
|||
.i_hrdata (i_hrdata),
|
||||
|
||||
.d_haddr (d_haddr),
|
||||
.d_hexcl (d_hexcl),
|
||||
.d_hwrite (d_hwrite),
|
||||
.d_htrans (d_htrans),
|
||||
.d_hsize (d_hsize),
|
||||
|
@ -221,6 +224,7 @@ hazard3_cpu_2port #(
|
|||
.d_hmastlock (d_hmastlock),
|
||||
.d_hready (d_hready),
|
||||
.d_hresp (d_hresp),
|
||||
.d_hexokay (d_hexokay),
|
||||
.d_hwdata (d_hwdata),
|
||||
.d_hrdata (d_hrdata),
|
||||
|
||||
|
|
|
@ -115,8 +115,10 @@ int main(int argc, char **argv) {
|
|||
#ifdef DUAL_PORT
|
||||
top.p_i__hready.set<bool>(true);
|
||||
top.p_d__hready.set<bool>(true);
|
||||
top.p_d__hexokay.set<bool>(true);
|
||||
#else
|
||||
top.p_ahblm__hready.set<bool>(true);
|
||||
top.p_ahblm__hexokay.set<bool>(true);
|
||||
#endif
|
||||
|
||||
uint64_t mtime = 0;
|
||||
|
|
Loading…
Reference in New Issue