mirror of
https://github.com/lowRISC/ibex.git
synced 2025-06-28 01:12:02 -04:00
[rtl] Remove X assignments, add SVAs for selector signals
This commit replaces all X assignments in the RTL with defined values. In addition, SystemVerilog Assertions are added to catch invalid signal values in simulation. A new file containing the corresponding assertion macros is added as well. Signed-off-by: Pirmin Vogel <vogelpi@lowrisc.org>
This commit is contained in:
parent
b10039c4ef
commit
0778008f33
15 changed files with 366 additions and 33 deletions
|
@ -10,6 +10,7 @@ ${PRJ_DIR}/ibex/shared/rtl/prim_clock_gating.sv
|
||||||
|
|
||||||
// ibex CORE RTL files
|
// ibex CORE RTL files
|
||||||
+incdir+${PRJ_DIR}/ibex/rtl
|
+incdir+${PRJ_DIR}/ibex/rtl
|
||||||
|
${PRJ_DIR}/ibex/shared/rtl/prim_assert.sv
|
||||||
${PRJ_DIR}/ibex/rtl/ibex_pkg.sv
|
${PRJ_DIR}/ibex/rtl/ibex_pkg.sv
|
||||||
${PRJ_DIR}/ibex/rtl/ibex_tracer_pkg.sv
|
${PRJ_DIR}/ibex/rtl/ibex_tracer_pkg.sv
|
||||||
${PRJ_DIR}/ibex/rtl/ibex_tracer.sv
|
${PRJ_DIR}/ibex/rtl/ibex_tracer.sv
|
||||||
|
|
|
@ -6,6 +6,8 @@ name: "lowrisc:ibex:ibex_core:0.1"
|
||||||
description: "CPU core with 2 stage pipeline implementing the RV32IMC_Zicsr ISA"
|
description: "CPU core with 2 stage pipeline implementing the RV32IMC_Zicsr ISA"
|
||||||
filesets:
|
filesets:
|
||||||
files_rtl:
|
files_rtl:
|
||||||
|
depend:
|
||||||
|
- lowrisc:prim:assert
|
||||||
files:
|
files:
|
||||||
- rtl/ibex_pkg.sv
|
- rtl/ibex_pkg.sv
|
||||||
- rtl/ibex_alu.sv
|
- rtl/ibex_alu.sv
|
||||||
|
|
|
@ -6,6 +6,8 @@ name: "lowrisc:ibex:ibex_tracer:0.1"
|
||||||
description: "Tracer for use with Ibex using the RVFI interface"
|
description: "Tracer for use with Ibex using the RVFI interface"
|
||||||
filesets:
|
filesets:
|
||||||
files_rtl:
|
files_rtl:
|
||||||
|
depend:
|
||||||
|
- lowrisc:prim:assert
|
||||||
files:
|
files:
|
||||||
- rtl/ibex_tracer_pkg.sv
|
- rtl/ibex_tracer_pkg.sv
|
||||||
- rtl/ibex_tracer.sv
|
- rtl/ibex_tracer.sv
|
||||||
|
|
|
@ -49,10 +49,14 @@ lint_off -msg UNUSED -file "*/rtl/ibex_register_file_ff.sv" -lines 21
|
||||||
// Signal is not used: clk_i
|
// Signal is not used: clk_i
|
||||||
// leaving clk and reset connected in-case we want to add assertions
|
// leaving clk and reset connected in-case we want to add assertions
|
||||||
lint_off -msg UNUSED -file "*/rtl/ibex_pmp.sv" -lines 15
|
lint_off -msg UNUSED -file "*/rtl/ibex_pmp.sv" -lines 15
|
||||||
|
lint_off -msg UNUSED -file "*/rtl/ibex_compressed_decoder.sv" -lines 14
|
||||||
|
lint_off -msg UNUSED -file "*/rtl/ibex_decoder.sv" -lines 21
|
||||||
|
|
||||||
// Signal is not used: rst_ni
|
// Signal is not used: rst_ni
|
||||||
// leaving clk and reset connected in-case we want to add assertions
|
// leaving clk and reset connected in-case we want to add assertions
|
||||||
lint_off -msg UNUSED -file "*/rtl/ibex_pmp.sv" -lines 16
|
lint_off -msg UNUSED -file "*/rtl/ibex_pmp.sv" -lines 16
|
||||||
|
lint_off -msg UNUSED -file "*/rtl/ibex_compressed_decoder.sv" -lines 15
|
||||||
|
lint_off -msg UNUSED -file "*/rtl/ibex_decoder.sv" -lines 22
|
||||||
|
|
||||||
// Signal unoptimizable: Feedback to clock or circular logic:
|
// Signal unoptimizable: Feedback to clock or circular logic:
|
||||||
// ibex_core.cs_registers_i.mie_q
|
// ibex_core.cs_registers_i.mie_q
|
||||||
|
|
|
@ -7,9 +7,12 @@
|
||||||
* Compressed instruction decoder
|
* Compressed instruction decoder
|
||||||
*
|
*
|
||||||
* Decodes RISC-V compressed instructions into their RV32 equivalent.
|
* Decodes RISC-V compressed instructions into their RV32 equivalent.
|
||||||
* This module is fully combinatorial.
|
* This module is fully combinatorial, clock and reset are used for
|
||||||
|
* assertions only.
|
||||||
*/
|
*/
|
||||||
module ibex_compressed_decoder (
|
module ibex_compressed_decoder (
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_ni,
|
||||||
input logic [31:0] instr_i,
|
input logic [31:0] instr_i,
|
||||||
output logic [31:0] instr_o,
|
output logic [31:0] instr_o,
|
||||||
output logic is_compressed_o,
|
output logic is_compressed_o,
|
||||||
|
@ -23,7 +26,8 @@ module ibex_compressed_decoder (
|
||||||
|
|
||||||
always_comb begin
|
always_comb begin
|
||||||
illegal_instr_o = 1'b0;
|
illegal_instr_o = 1'b0;
|
||||||
instr_o = 'X;
|
// Default instruction is NOP (ADDI x0, x0, 0)
|
||||||
|
instr_o = {12'd0, 5'd0, 3'd0, 5'd0, OPCODE_OP_IMM};
|
||||||
|
|
||||||
unique case (instr_i[1:0])
|
unique case (instr_i[1:0])
|
||||||
// C0
|
// C0
|
||||||
|
@ -152,13 +156,13 @@ module ibex_compressed_decoder (
|
||||||
end
|
end
|
||||||
|
|
||||||
default: begin
|
default: begin
|
||||||
illegal_instr_o = 1'bX;
|
illegal_instr_o = 1'b1;
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
default: begin
|
default: begin
|
||||||
illegal_instr_o = 1'bX;
|
illegal_instr_o = 1'b1;
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
@ -172,7 +176,7 @@ module ibex_compressed_decoder (
|
||||||
end
|
end
|
||||||
|
|
||||||
default: begin
|
default: begin
|
||||||
illegal_instr_o = 1'bX;
|
illegal_instr_o = 1'b1;
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
@ -240,7 +244,7 @@ module ibex_compressed_decoder (
|
||||||
end
|
end
|
||||||
|
|
||||||
default: begin
|
default: begin
|
||||||
illegal_instr_o = 1'bX;
|
illegal_instr_o = 1'b1;
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
@ -254,4 +258,18 @@ module ibex_compressed_decoder (
|
||||||
|
|
||||||
assign is_compressed_o = (instr_i[1:0] != 2'b11);
|
assign is_compressed_o = (instr_i[1:0] != 2'b11);
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// Assertions //
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
// Selectors must be known/valid.
|
||||||
|
`ASSERT(IbexC1Known1, (instr_i[1:0] == 2'b01) |-> !$isunknown(instr_i[15:13]), clk_i, !rst_ni)
|
||||||
|
`ASSERT(IbexC1Known2,
|
||||||
|
((instr_i[1:0] == 2'b01) && (instr_i[15:13] == 3'b100)) |->
|
||||||
|
!$isunknown(instr_i[11:10]), clk_i, !rst_ni)
|
||||||
|
`ASSERT(IbexC1Known3,
|
||||||
|
((instr_i[1:0] == 2'b01) && (instr_i[15:13] == 3'b100) && (instr_i[11:10] == 2'b11)) |->
|
||||||
|
!$isunknown({instr_i[12], instr_i[6:5]}), clk_i, !rst_ni)
|
||||||
|
`ASSERT(IbexC2Known1, (instr_i[1:0] == 2'b10) |-> !$isunknown(instr_i[15:13]), clk_i, !rst_ni)
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -585,7 +585,7 @@ module ibex_controller (
|
||||||
|
|
||||||
default: begin
|
default: begin
|
||||||
instr_req_o = 1'b0;
|
instr_req_o = 1'b0;
|
||||||
ctrl_fsm_ns = ctrl_fsm_e'(1'bX);
|
ctrl_fsm_ns = RESET;
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
@ -636,4 +636,14 @@ module ibex_controller (
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// Assertions //
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
// Selectors must be known/valid.
|
||||||
|
`ASSERT(IbexCtrlStateValid, ctrl_fsm_cs inside {
|
||||||
|
RESET, BOOT_SET, WAIT_SLEEP, SLEEP, FIRST_FETCH, DECODE, FLUSH,
|
||||||
|
IRQ_TAKEN, DBG_TAKEN_IF, DBG_TAKEN_ID
|
||||||
|
}, clk_i, !rst_ni)
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -613,8 +613,8 @@ module ibex_cs_registers #(
|
||||||
csr_wreq = 1'b0;
|
csr_wreq = 1'b0;
|
||||||
end
|
end
|
||||||
default: begin
|
default: begin
|
||||||
csr_wdata_int = 'X;
|
csr_wdata_int = csr_wdata_i;
|
||||||
csr_wreq = 1'bX;
|
csr_wreq = 1'b0;
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
@ -777,7 +777,7 @@ module ibex_cs_registers #(
|
||||||
2'b10 : pmp_cfg_wdata[i].mode = (PMPGranularity == 0) ? PMP_MODE_NA4:
|
2'b10 : pmp_cfg_wdata[i].mode = (PMPGranularity == 0) ? PMP_MODE_NA4:
|
||||||
PMP_MODE_OFF;
|
PMP_MODE_OFF;
|
||||||
2'b11 : pmp_cfg_wdata[i].mode = PMP_MODE_NAPOT;
|
2'b11 : pmp_cfg_wdata[i].mode = PMP_MODE_NAPOT;
|
||||||
default : pmp_cfg_wdata[i].mode = pmp_cfg_mode_e'('X);
|
default : pmp_cfg_wdata[i].mode = PMP_MODE_OFF;
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
assign pmp_cfg_wdata[i].exec = csr_wdata_int[(i%4)*PMP_CFG_W+2];
|
assign pmp_cfg_wdata[i].exec = csr_wdata_int[(i%4)*PMP_CFG_W+2];
|
||||||
|
@ -1013,4 +1013,17 @@ module ibex_cs_registers #(
|
||||||
assign trigger_match_o = 'b0;
|
assign trigger_match_o = 'b0;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// Assertions //
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
// Selectors must be known/valid.
|
||||||
|
`ASSERT(IbexCsrOpValid, csr_op_i inside {
|
||||||
|
CSR_OP_READ,
|
||||||
|
CSR_OP_WRITE,
|
||||||
|
CSR_OP_SET,
|
||||||
|
CSR_OP_CLEAR
|
||||||
|
}, clk_i, !rst_ni)
|
||||||
|
`ASSERT_KNOWN(IbexCsrWdataIntKnown, csr_wdata_int, clk_i, !rst_ni)
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -10,11 +10,17 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instruction decoder
|
* Instruction decoder
|
||||||
|
*
|
||||||
|
* This module is fully combinatorial, clock and reset are used for
|
||||||
|
* assertions only.
|
||||||
*/
|
*/
|
||||||
module ibex_decoder #(
|
module ibex_decoder #(
|
||||||
parameter bit RV32E = 0,
|
parameter bit RV32E = 0,
|
||||||
parameter bit RV32M = 1
|
parameter bit RV32M = 1
|
||||||
) (
|
) (
|
||||||
|
input logic clk_i,
|
||||||
|
input logic rst_ni,
|
||||||
|
|
||||||
// to/from controller
|
// to/from controller
|
||||||
output logic illegal_insn_o, // illegal instr encountered
|
output logic illegal_insn_o, // illegal instr encountered
|
||||||
output logic ebrk_insn_o, // trap instr encountered
|
output logic ebrk_insn_o, // trap instr encountered
|
||||||
|
@ -395,7 +401,7 @@ module ibex_decoder #(
|
||||||
end
|
end
|
||||||
|
|
||||||
default: begin
|
default: begin
|
||||||
alu_operator_o = alu_op_e'({$bits(alu_op_e){1'bX}});
|
alu_operator_o = ALU_SLTU;
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
@ -615,4 +621,12 @@ module ibex_decoder #(
|
||||||
// do not propgate regfile write enable if non-available registers are accessed in RV32E
|
// do not propgate regfile write enable if non-available registers are accessed in RV32E
|
||||||
assign regfile_we_o = regfile_we & ~illegal_reg_rv32e;
|
assign regfile_we_o = regfile_we & ~illegal_reg_rv32e;
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
// Assertions //
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
// Selectors must be known/valid.
|
||||||
|
`ASSERT(IbexRegImmAluOpKnown, (opcode == OPCODE_OP_IMM) |->
|
||||||
|
!$isunknown(instr[14:12]), clk_i, !rst_ni)
|
||||||
|
|
||||||
endmodule // controller
|
endmodule // controller
|
||||||
|
|
|
@ -233,7 +233,7 @@ module ibex_id_stage #(
|
||||||
OP_A_FWD: alu_operand_a = lsu_addr_last_i;
|
OP_A_FWD: alu_operand_a = lsu_addr_last_i;
|
||||||
OP_A_CURRPC: alu_operand_a = pc_id_i;
|
OP_A_CURRPC: alu_operand_a = pc_id_i;
|
||||||
OP_A_IMM: alu_operand_a = imm_a;
|
OP_A_IMM: alu_operand_a = imm_a;
|
||||||
default: alu_operand_a = 'X;
|
default: alu_operand_a = pc_id_i;
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -251,7 +251,7 @@ module ibex_id_stage #(
|
||||||
IMM_B_J: imm_b = imm_j_type;
|
IMM_B_J: imm_b = imm_j_type;
|
||||||
IMM_B_INCR_PC: imm_b = instr_is_compressed_i ? 32'h2 : 32'h4;
|
IMM_B_INCR_PC: imm_b = instr_is_compressed_i ? 32'h2 : 32'h4;
|
||||||
IMM_B_INCR_ADDR: imm_b = 32'h4;
|
IMM_B_INCR_ADDR: imm_b = 32'h4;
|
||||||
default: imm_b = 'X;
|
default: imm_b = 32'h4;
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -273,8 +273,8 @@ module ibex_id_stage #(
|
||||||
RF_WD_EX: regfile_wdata = regfile_wdata_ex_i;
|
RF_WD_EX: regfile_wdata = regfile_wdata_ex_i;
|
||||||
RF_WD_LSU: regfile_wdata = regfile_wdata_lsu_i;
|
RF_WD_LSU: regfile_wdata = regfile_wdata_lsu_i;
|
||||||
RF_WD_CSR: regfile_wdata = csr_rdata_i;
|
RF_WD_CSR: regfile_wdata = csr_rdata_i;
|
||||||
default: regfile_wdata = 'X;
|
default: regfile_wdata = regfile_wdata_ex_i;
|
||||||
endcase;
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
///////////////////
|
///////////////////
|
||||||
|
@ -317,6 +317,9 @@ module ibex_id_stage #(
|
||||||
.RV32E ( RV32E ),
|
.RV32E ( RV32E ),
|
||||||
.RV32M ( RV32M )
|
.RV32M ( RV32M )
|
||||||
) decoder_i (
|
) decoder_i (
|
||||||
|
.clk_i ( clk_i ),
|
||||||
|
.rst_ni ( rst_ni ),
|
||||||
|
|
||||||
// controller
|
// controller
|
||||||
.illegal_insn_o ( illegal_insn_dec ),
|
.illegal_insn_o ( illegal_insn_dec ),
|
||||||
.ebrk_insn_o ( ebrk_insn ),
|
.ebrk_insn_o ( ebrk_insn ),
|
||||||
|
@ -600,7 +603,7 @@ module ibex_id_stage #(
|
||||||
end
|
end
|
||||||
|
|
||||||
default: begin
|
default: begin
|
||||||
id_wb_fsm_ns = id_fsm_e'(1'bX);
|
id_wb_fsm_ns = IDLE;
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
@ -611,6 +614,24 @@ module ibex_id_stage #(
|
||||||
// Assertions //
|
// Assertions //
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
|
// Selectors must be known/valid.
|
||||||
|
`ASSERT_KNOWN(IbexAluOpMuxSelKnown, alu_op_a_mux_sel, clk_i, !rst_ni)
|
||||||
|
`ASSERT(IbexImmBMuxSelValid, imm_b_mux_sel inside {
|
||||||
|
IMM_B_I,
|
||||||
|
IMM_B_S,
|
||||||
|
IMM_B_B,
|
||||||
|
IMM_B_U,
|
||||||
|
IMM_B_J,
|
||||||
|
IMM_B_INCR_PC,
|
||||||
|
IMM_B_INCR_ADDR
|
||||||
|
}, clk_i, !rst_ni)
|
||||||
|
`ASSERT(IbexRegfileWdataSelValid, regfile_wdata_sel inside {
|
||||||
|
RF_WD_LSU,
|
||||||
|
RF_WD_EX,
|
||||||
|
RF_WD_CSR
|
||||||
|
}, clk_i, !rst_ni)
|
||||||
|
`ASSERT_KNOWN(IbexWbStateKnown, id_wb_fsm_cs, clk_i, !rst_ni)
|
||||||
|
|
||||||
`ifndef VERILATOR
|
`ifndef VERILATOR
|
||||||
// branch decision must be valid when jumping
|
// branch decision must be valid when jumping
|
||||||
assert property (@(posedge clk_i) disable iff (!rst_ni)
|
assert property (@(posedge clk_i) disable iff (!rst_ni)
|
||||||
|
|
|
@ -109,7 +109,7 @@ module ibex_if_stage #(
|
||||||
EXC_PC_IRQ: exc_pc = { csr_mtvec_i[31:8], 1'b0, irq_id[4:0], 2'b00 };
|
EXC_PC_IRQ: exc_pc = { csr_mtvec_i[31:8], 1'b0, irq_id[4:0], 2'b00 };
|
||||||
EXC_PC_DBD: exc_pc = DmHaltAddr;
|
EXC_PC_DBD: exc_pc = DmHaltAddr;
|
||||||
EXC_PC_DBG_EXC: exc_pc = DmExceptionAddr;
|
EXC_PC_DBG_EXC: exc_pc = DmExceptionAddr;
|
||||||
default: exc_pc = 'X;
|
default: exc_pc = { csr_mtvec_i[31:8], 8'h00 };
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ module ibex_if_stage #(
|
||||||
PC_EXC: fetch_addr_n = exc_pc; // set PC to exception handler
|
PC_EXC: fetch_addr_n = exc_pc; // set PC to exception handler
|
||||||
PC_ERET: fetch_addr_n = csr_mepc_i; // restore PC when returning from EXC
|
PC_ERET: fetch_addr_n = csr_mepc_i; // restore PC when returning from EXC
|
||||||
PC_DRET: fetch_addr_n = csr_depc_i;
|
PC_DRET: fetch_addr_n = csr_depc_i;
|
||||||
default: fetch_addr_n = 'X;
|
default: fetch_addr_n = { boot_addr_i[31:8], 8'h80 };
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -217,6 +217,8 @@ module ibex_if_stage #(
|
||||||
logic instr_is_compressed_int;
|
logic instr_is_compressed_int;
|
||||||
|
|
||||||
ibex_compressed_decoder compressed_decoder_i (
|
ibex_compressed_decoder compressed_decoder_i (
|
||||||
|
.clk_i ( clk_i ),
|
||||||
|
.rst_ni ( rst_ni ),
|
||||||
.instr_i ( fetch_rdata ),
|
.instr_i ( fetch_rdata ),
|
||||||
.instr_o ( instr_decompressed ),
|
.instr_o ( instr_decompressed ),
|
||||||
.is_compressed_o ( instr_is_compressed_int ),
|
.is_compressed_o ( instr_is_compressed_int ),
|
||||||
|
@ -255,6 +257,17 @@ module ibex_if_stage #(
|
||||||
////////////////
|
////////////////
|
||||||
// Assertions //
|
// Assertions //
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
|
// Selectors must be known/valid.
|
||||||
|
`ASSERT_KNOWN(IbexExcPcMuxKnown, exc_pc_mux_i, clk_i, !rst_ni)
|
||||||
|
`ASSERT(IbexPcMuxValid, pc_mux_i inside {
|
||||||
|
PC_BOOT,
|
||||||
|
PC_JUMP,
|
||||||
|
PC_EXC,
|
||||||
|
PC_ERET,
|
||||||
|
PC_DRET
|
||||||
|
}, clk_i, !rst_ni)
|
||||||
|
|
||||||
`ifndef VERILATOR
|
`ifndef VERILATOR
|
||||||
// boot address must be aligned to 256 bytes
|
// boot address must be aligned to 256 bytes
|
||||||
assert property (@(posedge clk_i) disable iff (!rst_ni)
|
assert property (@(posedge clk_i) disable iff (!rst_ni)
|
||||||
|
|
|
@ -105,7 +105,7 @@ module ibex_load_store_unit (
|
||||||
2'b01: data_be = 4'b1110;
|
2'b01: data_be = 4'b1110;
|
||||||
2'b10: data_be = 4'b1100;
|
2'b10: data_be = 4'b1100;
|
||||||
2'b11: data_be = 4'b1000;
|
2'b11: data_be = 4'b1000;
|
||||||
default: data_be = 'X;
|
default: data_be = 4'b1111;
|
||||||
endcase // case (data_offset)
|
endcase // case (data_offset)
|
||||||
end else begin // second part of misaligned transaction
|
end else begin // second part of misaligned transaction
|
||||||
unique case (data_offset)
|
unique case (data_offset)
|
||||||
|
@ -113,7 +113,7 @@ module ibex_load_store_unit (
|
||||||
2'b01: data_be = 4'b0001;
|
2'b01: data_be = 4'b0001;
|
||||||
2'b10: data_be = 4'b0011;
|
2'b10: data_be = 4'b0011;
|
||||||
2'b11: data_be = 4'b0111;
|
2'b11: data_be = 4'b0111;
|
||||||
default: data_be = 'X;
|
default: data_be = 4'b1111;
|
||||||
endcase // case (data_offset)
|
endcase // case (data_offset)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -125,7 +125,7 @@ module ibex_load_store_unit (
|
||||||
2'b01: data_be = 4'b0110;
|
2'b01: data_be = 4'b0110;
|
||||||
2'b10: data_be = 4'b1100;
|
2'b10: data_be = 4'b1100;
|
||||||
2'b11: data_be = 4'b1000;
|
2'b11: data_be = 4'b1000;
|
||||||
default: data_be = 'X;
|
default: data_be = 4'b1111;
|
||||||
endcase // case (data_offset)
|
endcase // case (data_offset)
|
||||||
end else begin // second part of misaligned transaction
|
end else begin // second part of misaligned transaction
|
||||||
data_be = 4'b0001;
|
data_be = 4'b0001;
|
||||||
|
@ -139,11 +139,11 @@ module ibex_load_store_unit (
|
||||||
2'b01: data_be = 4'b0010;
|
2'b01: data_be = 4'b0010;
|
||||||
2'b10: data_be = 4'b0100;
|
2'b10: data_be = 4'b0100;
|
||||||
2'b11: data_be = 4'b1000;
|
2'b11: data_be = 4'b1000;
|
||||||
default: data_be = 'X;
|
default: data_be = 4'b1111;
|
||||||
endcase // case (data_offset)
|
endcase // case (data_offset)
|
||||||
end
|
end
|
||||||
|
|
||||||
default: data_be = 'X;
|
default: data_be = 4'b1111;
|
||||||
endcase // case (data_type_ex_i)
|
endcase // case (data_type_ex_i)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ module ibex_load_store_unit (
|
||||||
2'b01: data_wdata = {data_wdata_ex_i[23:0], data_wdata_ex_i[31:24]};
|
2'b01: data_wdata = {data_wdata_ex_i[23:0], data_wdata_ex_i[31:24]};
|
||||||
2'b10: data_wdata = {data_wdata_ex_i[15:0], data_wdata_ex_i[31:16]};
|
2'b10: data_wdata = {data_wdata_ex_i[15:0], data_wdata_ex_i[31:16]};
|
||||||
2'b11: data_wdata = {data_wdata_ex_i[ 7:0], data_wdata_ex_i[31: 8]};
|
2'b11: data_wdata = {data_wdata_ex_i[ 7:0], data_wdata_ex_i[31: 8]};
|
||||||
default: data_wdata = 'X;
|
default: data_wdata = data_wdata_ex_i[31:0];
|
||||||
endcase // case (data_offset)
|
endcase // case (data_offset)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ module ibex_load_store_unit (
|
||||||
2'b01: rdata_w_ext = {data_rdata_i[ 7:0], rdata_q[31:8]};
|
2'b01: rdata_w_ext = {data_rdata_i[ 7:0], rdata_q[31:8]};
|
||||||
2'b10: rdata_w_ext = {data_rdata_i[15:0], rdata_q[31:16]};
|
2'b10: rdata_w_ext = {data_rdata_i[15:0], rdata_q[31:16]};
|
||||||
2'b11: rdata_w_ext = {data_rdata_i[23:0], rdata_q[31:24]};
|
2'b11: rdata_w_ext = {data_rdata_i[23:0], rdata_q[31:24]};
|
||||||
default: rdata_w_ext = 'X;
|
default: rdata_w_ext = data_rdata_i[31:0];
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -251,7 +251,7 @@ module ibex_load_store_unit (
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
default: rdata_h_ext = 'X;
|
default: rdata_h_ext = {16'h0000, data_rdata_i[15:0]};
|
||||||
endcase // case (rdata_offset_q)
|
endcase // case (rdata_offset_q)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -290,7 +290,7 @@ module ibex_load_store_unit (
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
default: rdata_b_ext = 'X;
|
default: rdata_b_ext = {24'h00_0000, data_rdata_i[7:0]};
|
||||||
endcase // case (rdata_offset_q)
|
endcase // case (rdata_offset_q)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -300,8 +300,8 @@ module ibex_load_store_unit (
|
||||||
2'b00: data_rdata_ext = rdata_w_ext;
|
2'b00: data_rdata_ext = rdata_w_ext;
|
||||||
2'b01: data_rdata_ext = rdata_h_ext;
|
2'b01: data_rdata_ext = rdata_h_ext;
|
||||||
2'b10,2'b11: data_rdata_ext = rdata_b_ext;
|
2'b10,2'b11: data_rdata_ext = rdata_b_ext;
|
||||||
default: data_rdata_ext = 'X;
|
default: data_rdata_ext = rdata_w_ext;
|
||||||
endcase //~case(rdata_type_q)
|
endcase // case (data_type_q)
|
||||||
end
|
end
|
||||||
|
|
||||||
/////////////
|
/////////////
|
||||||
|
@ -433,7 +433,7 @@ module ibex_load_store_unit (
|
||||||
end
|
end
|
||||||
|
|
||||||
default: begin
|
default: begin
|
||||||
ls_fsm_ns = ls_fsm_e'(1'bX);
|
ls_fsm_ns = IDLE;
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
@ -482,6 +482,16 @@ module ibex_load_store_unit (
|
||||||
// Assertions //
|
// Assertions //
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
|
// Selectors must be known/valid.
|
||||||
|
`ASSERT_KNOWN(IbexDataTypeKnown, data_type_ex_i, clk_i, !rst_ni)
|
||||||
|
`ASSERT_KNOWN(IbexDataOffsetKnown, data_offset, clk_i, !rst_ni)
|
||||||
|
`ASSERT_KNOWN(IbexRDataOffsetQKnown, rdata_offset_q, clk_i, !rst_ni)
|
||||||
|
`ASSERT_KNOWN(IbexDataTypeQKnown, data_type_q, clk_i, !rst_ni)
|
||||||
|
`ASSERT(IbexLsuStateValid, ls_fsm_cs inside {
|
||||||
|
IDLE, WAIT_GNT_MIS, WAIT_RVALID_MIS, WAIT_GNT, WAIT_RVALID,
|
||||||
|
WAIT_RVALID_DONE
|
||||||
|
}, clk_i, !rst_ni)
|
||||||
|
|
||||||
`ifndef VERILATOR
|
`ifndef VERILATOR
|
||||||
// there must not be an rvalid unless the FSM is handlling it
|
// there must not be an rvalid unless the FSM is handlling it
|
||||||
assert property (@(posedge clk_i) disable iff (!rst_ni)
|
assert property (@(posedge clk_i) disable iff (!rst_ni)
|
||||||
|
|
|
@ -238,7 +238,7 @@ module ibex_multdiv_fast (
|
||||||
end
|
end
|
||||||
|
|
||||||
default: begin
|
default: begin
|
||||||
md_state_n = md_fsm_e'(1'bX);
|
md_state_n = MD_IDLE;
|
||||||
end
|
end
|
||||||
endcase // md_state_q
|
endcase // md_state_q
|
||||||
end
|
end
|
||||||
|
@ -318,9 +318,15 @@ module ibex_multdiv_fast (
|
||||||
mult_valid = 1'b1;
|
mult_valid = 1'b1;
|
||||||
end
|
end
|
||||||
default: begin
|
default: begin
|
||||||
mult_state_n = mult_fsm_e'(1'bX);
|
mult_state_n = ALBL;
|
||||||
end
|
end
|
||||||
endcase // mult_state_q
|
endcase // mult_state_q
|
||||||
end
|
end
|
||||||
|
|
||||||
|
// States must be knwon/valid.
|
||||||
|
`ASSERT(IbexMultDivStateValid, md_state_q inside {
|
||||||
|
MD_IDLE, MD_ABS_A, MD_ABS_B, MD_COMP, MD_LAST, MD_CHANGE_SIGN, MD_FINISH
|
||||||
|
}, clk_i, !rst_ni)
|
||||||
|
`ASSERT_KNOWN(IbexMultStateKnown, mult_state_q, clk_i, !rst_ni)
|
||||||
|
|
||||||
endmodule // ibex_mult
|
endmodule // ibex_mult
|
||||||
|
|
|
@ -272,7 +272,7 @@ module ibex_multdiv_slow (
|
||||||
end
|
end
|
||||||
|
|
||||||
default: begin
|
default: begin
|
||||||
md_state_d = md_fsm_e'(1'bX);
|
md_state_d = MD_IDLE;
|
||||||
end
|
end
|
||||||
endcase // md_state_q
|
endcase // md_state_q
|
||||||
end
|
end
|
||||||
|
@ -283,4 +283,9 @@ module ibex_multdiv_slow (
|
||||||
(operator_i == MD_OP_MULL |
|
(operator_i == MD_OP_MULL |
|
||||||
operator_i == MD_OP_MULH));
|
operator_i == MD_OP_MULH));
|
||||||
|
|
||||||
|
// State must be valid.
|
||||||
|
`ASSERT(IbexMultDivStateValid, md_state_q inside {
|
||||||
|
MD_IDLE, MD_ABS_A, MD_ABS_B, MD_COMP, MD_LAST, MD_CHANGE_SIGN, MD_FINISH
|
||||||
|
}, clk_i, !rst_ni)
|
||||||
|
|
||||||
endmodule // ibex_mult
|
endmodule // ibex_mult
|
||||||
|
|
17
shared/prim_assert.core
Normal file
17
shared/prim_assert.core
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
CAPI=2:
|
||||||
|
# Copyright lowRISC contributors.
|
||||||
|
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
name: "lowrisc:prim:assert:0.1"
|
||||||
|
description: "Assertion primitives"
|
||||||
|
filesets:
|
||||||
|
files_rtl:
|
||||||
|
files:
|
||||||
|
- rtl/prim_assert.sv
|
||||||
|
file_type: systemVerilogSource
|
||||||
|
|
||||||
|
targets:
|
||||||
|
default:
|
||||||
|
filesets:
|
||||||
|
- files_rtl
|
197
shared/rtl/prim_assert.sv
Normal file
197
shared/rtl/prim_assert.sv
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
// Copyright lowRISC contributors.
|
||||||
|
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Macros and helper code for using assertions.
|
||||||
|
// - Provides default clk and rst options to simplify code
|
||||||
|
// - Provides boiler plate template for common assertions
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// - check if ASSERT_FINAL needs an `ifndef SYNTHESIS
|
||||||
|
// - should we add ASSERT_INIT_DISABLE?
|
||||||
|
// - can we remove pragma translate_off and ifndef VERILATOR?
|
||||||
|
// - should we add "pragma coverage off" and "VCS coverage off"?
|
||||||
|
|
||||||
|
`ifdef UVM_PKG_SV
|
||||||
|
// report assertion error with UVM if compiled
|
||||||
|
package assert_rpt_pkg;
|
||||||
|
import uvm_pkg::*;
|
||||||
|
`include "uvm_macros.svh"
|
||||||
|
function void assert_rpt(string msg);
|
||||||
|
`uvm_error("ASSERT FAILED", msg)
|
||||||
|
endfunction
|
||||||
|
endpackage
|
||||||
|
`endif
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////
|
||||||
|
// Helper macros //
|
||||||
|
///////////////////
|
||||||
|
|
||||||
|
|
||||||
|
// Converts an arbitrary block of code into a Verilog string
|
||||||
|
`define PRIM_STRINGIFY(__x) `"__x`"
|
||||||
|
|
||||||
|
// ASSERT_RPT is available to change the reporting mechanism when an assert fails
|
||||||
|
`define ASSERT_RPT(__name, __msg) \
|
||||||
|
`ifdef UVM_PKG_SV \
|
||||||
|
assert_rpt_pkg::assert_rpt($sformatf("[%m] %s: %s (%s:%0d)", \
|
||||||
|
__name, __msg, `__FILE__, `__LINE__)); \
|
||||||
|
`else \
|
||||||
|
$error("[ASSERT FAILED] [%m] %s: %s", __name, __msg); \
|
||||||
|
`endif
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
// Simple assertion and cover macros //
|
||||||
|
///////////////////////////////////////
|
||||||
|
|
||||||
|
// Immediate assertion
|
||||||
|
// Note that immediate assertions are sensitive to simulation glitches.
|
||||||
|
`define ASSERT_I(__name, __prop) \
|
||||||
|
`ifndef VERILATOR \
|
||||||
|
//pragma translate_off \
|
||||||
|
__name: assert (__prop) \
|
||||||
|
else `ASSERT_RPT(`PRIM_STRINGIFY(__name), `PRIM_STRINGIFY(__prop)) \
|
||||||
|
//pragma translate_on \
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// Assertion in initial block. Can be used for things like parameter checking.
|
||||||
|
`define ASSERT_INIT(__name, __prop) \
|
||||||
|
`ifndef VERILATOR \
|
||||||
|
//pragma translate_off \
|
||||||
|
initial \
|
||||||
|
__name: assert (__prop) \
|
||||||
|
else `ASSERT_RPT(`PRIM_STRINGIFY(__name), `PRIM_STRINGIFY(__prop)) \
|
||||||
|
//pragma translate_on \
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// Assertion in final block. Can be used for things like queues being empty
|
||||||
|
// at end of sim, all credits returned at end of sim, state machines in idle
|
||||||
|
// at end of sim.
|
||||||
|
`define ASSERT_FINAL(__name, __prop) \
|
||||||
|
`ifndef VERILATOR \
|
||||||
|
//pragma translate_off \
|
||||||
|
final \
|
||||||
|
__name: assert (__prop || $test$plusargs("disable_assert_final_checks")) \
|
||||||
|
else `ASSERT_RPT(`PRIM_STRINGIFY(__name), `PRIM_STRINGIFY(__prop)) \
|
||||||
|
//pragma translate_on \
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// Assert a concurrent property directly.
|
||||||
|
// It can be called as a module (or interface) body item.
|
||||||
|
`define ASSERT(__name, __prop, __clk, __rst) \
|
||||||
|
`ifndef VERILATOR \
|
||||||
|
//pragma translate_off \
|
||||||
|
__name: assert property (@(posedge __clk) disable iff (__rst !== '0) (__prop)) \
|
||||||
|
else `ASSERT_RPT(`PRIM_STRINGIFY(__name), `PRIM_STRINGIFY(__prop)) \
|
||||||
|
//pragma translate_on \
|
||||||
|
`endif
|
||||||
|
// Note: Above we use (__rst !== '0) in the disable iff statements instead of
|
||||||
|
// (__rst == '1). This properly disables the assertion in cases when reset is X at
|
||||||
|
// the beginning of a simulation. For that case, (reset == '1) does not disable the
|
||||||
|
// assertion.
|
||||||
|
|
||||||
|
// Assert a concurrent property NEVER happens
|
||||||
|
`define ASSERT_NEVER(__name, __prop, __clk, __rst) \
|
||||||
|
`ifndef VERILATOR \
|
||||||
|
//pragma translate_off \
|
||||||
|
__name: assert property (@(posedge __clk) disable iff (__rst !== '0) not (__prop)) \
|
||||||
|
else `ASSERT_RPT(`PRIM_STRINGIFY(__name), `PRIM_STRINGIFY(__prop)) \
|
||||||
|
//pragma translate_on \
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// Assert that signal has a known value (each bit is either '0' or '1') after reset.
|
||||||
|
// It can be called as a module (or interface) body item.
|
||||||
|
`define ASSERT_KNOWN(__name, __sig, __clk, __rst) \
|
||||||
|
`ifndef VERILATOR \
|
||||||
|
//pragma translate_off \
|
||||||
|
`ASSERT(__name, !$isunknown(__sig), __clk, __rst) \
|
||||||
|
//pragma translate_on \
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// Cover a concurrent property
|
||||||
|
`define COVER(__name, __prop, __clk, __rst) \
|
||||||
|
`ifndef VERILATOR \
|
||||||
|
//pragma translate_off \
|
||||||
|
__name: cover property (@(posedge __clk) disable iff (__rst !== '0) (__prop)); \
|
||||||
|
//pragma translate_on \
|
||||||
|
`endif
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
// Complex assertion macros //
|
||||||
|
//////////////////////////////
|
||||||
|
|
||||||
|
// Assert that signal is an active-high pulse with pulse length of 1 clock cycle
|
||||||
|
`define ASSERT_PULSE(__name, __sig, __clk, __rst) \
|
||||||
|
`ifndef VERILATOR \
|
||||||
|
//pragma translate_off \
|
||||||
|
`ASSERT(__name, $rose(__sig) |=> !(__sig), __clk, __rst) \
|
||||||
|
//pragma translate_on \
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// Assert that valid is known after reset and data is known when valid == 1
|
||||||
|
`define ASSERT_VALID_DATA(__name, __valid, __dat, __clk, __rst) \
|
||||||
|
`ifndef VERILATOR \
|
||||||
|
//pragma translate_off \
|
||||||
|
`ASSERT_KNOWN(__name``KnownValid, __valid, __clk, __rst) \
|
||||||
|
`ASSERT_NEVER(__name``KnownData, (__valid) && $isunknown(__dat), __clk, __rst) \
|
||||||
|
//pragma translate_on \
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// Same as ASSERT_VALID_DATA, but also assert that ready is known after reset
|
||||||
|
`define ASSERT_VALID_READY_DATA(__name, __valid, __ready, __dat, __clk, __rst) \
|
||||||
|
`ifndef VERILATOR \
|
||||||
|
//pragma translate_off \
|
||||||
|
`ASSERT_KNOWN(__name``KnownValid, __valid, __clk, __rst) \
|
||||||
|
`ASSERT_KNOWN(__name``KnownReady, __ready, __clk, __rst) \
|
||||||
|
`ASSERT_NEVER(__name``KnownData, (__valid) && $isunknown(__dat), __clk, __rst) \
|
||||||
|
//pragma translate_on \
|
||||||
|
`endif
|
||||||
|
|
||||||
|
///////////////////////
|
||||||
|
// Assumption macros //
|
||||||
|
///////////////////////
|
||||||
|
|
||||||
|
// Assume a concurrent property
|
||||||
|
`define ASSUME(__name, __prop, __clk, __rst) \
|
||||||
|
`ifndef VERILATOR \
|
||||||
|
__name: assume property (@(posedge __clk) disable iff (__rst !== '0) (__prop)) \
|
||||||
|
else begin `ASSERT_RPT(`PRIM_STRINGIFY(__name), `PRIM_STRINGIFY(__prop)) end \
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// Assume an immediate property
|
||||||
|
`define ASSUME_I(__name, __prop) \
|
||||||
|
`ifndef VERILATOR \
|
||||||
|
//pragma translate_off \
|
||||||
|
__name: assume (__prop) \
|
||||||
|
else `ASSERT_RPT(`PRIM_STRINGIFY(__name), `PRIM_STRINGIFY(__prop)) \
|
||||||
|
//pragma translate_on \
|
||||||
|
`endif
|
||||||
|
|
||||||
|
//////////////////////////////////
|
||||||
|
// For formal verification only //
|
||||||
|
//////////////////////////////////
|
||||||
|
|
||||||
|
// Note that the existing set of ASSERT macros specified above shall be used for FPV,
|
||||||
|
// thereby ensuring that the assertions are evaluated during DV simulations as well.
|
||||||
|
|
||||||
|
// ASSUME_FPV
|
||||||
|
// Assume a concurrent property during formal verification only.
|
||||||
|
`define ASSUME_FPV(__name, __prop, __clk, __rst) \
|
||||||
|
`ifdef FPV_ON \
|
||||||
|
`ASSUME(__name, __prop, __clk, __rst) \
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// ASSUME_I_FPV
|
||||||
|
// Assume a concurrent property during formal verification only.
|
||||||
|
`define ASSUME_I_FPV(__name, __prop) \
|
||||||
|
`ifdef FPV_ON \
|
||||||
|
`ASSUME_I(__name, __prop) \
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// COVER_FPV
|
||||||
|
// Cover a concurrent property during formal verification
|
||||||
|
`define COVER_FPV(__name, __prop, __clk, __rst) \
|
||||||
|
`ifdef FPV_ON \
|
||||||
|
`COVER(__name, __prop, __clk, __rst) \
|
||||||
|
`endif
|
Loading…
Add table
Add a link
Reference in a new issue