mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 04:57:25 -04:00
[rtl] Add support for instruction fetch errors
- Add required signals to top-level - Propagate error through fetch stages - Add new exception type - Update documentation for new exception type - Resolves issue #109
This commit is contained in:
parent
ca97cfb58e
commit
44b033cf8b
15 changed files with 67 additions and 6 deletions
|
@ -70,6 +70,8 @@ Ibex can trigger an exception due to the following exception causes:
|
|||
+----------------+---------------------------------------------------------------+
|
||||
| Exception Code | Description |
|
||||
+----------------+---------------------------------------------------------------+
|
||||
| 1 | Instruction access fault |
|
||||
+----------------+---------------------------------------------------------------+
|
||||
| 2 | Illegal instruction |
|
||||
+----------------+---------------------------------------------------------------+
|
||||
| 3 | Breakpoint |
|
||||
|
@ -81,7 +83,7 @@ Ibex can trigger an exception due to the following exception causes:
|
|||
| 11 | Environment call from M-mode (ECALL) |
|
||||
+----------------+---------------------------------------------------------------+
|
||||
|
||||
The illegal instruction exception, LSU error exceptions and ECALL instruction exceptions cannot be disabled and are always active.
|
||||
The illegal instruction exception, instruction access fault, LSU error exceptions and ECALL instruction exceptions cannot be disabled and are always active.
|
||||
|
||||
|
||||
Handling
|
||||
|
|
|
@ -30,6 +30,8 @@ The main difference is that the instruction interface does not allow for write t
|
|||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``instr_rdata_i[31:0]`` | input | Data read from memory |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
| ``instr_err_i`` | input | Memory access error |
|
||||
+-------------------------+-----------+-----------------------------------------------+
|
||||
|
||||
|
||||
Misaligned Accesses
|
||||
|
|
|
@ -35,6 +35,7 @@ Instantiation Template
|
|||
.instr_rvalid_i (),
|
||||
.instr_addr_o (),
|
||||
.instr_rdata_i (),
|
||||
.instr_err_i (),
|
||||
|
||||
// Data memory interface
|
||||
.data_req_o (),
|
||||
|
|
|
@ -120,6 +120,7 @@ module ibex_riscv_compliance (
|
|||
.instr_rvalid_i (host_rvalid[CoreI]),
|
||||
.instr_addr_o (host_addr[CoreI]),
|
||||
.instr_rdata_i (host_rdata[CoreI]),
|
||||
.instr_err_i (host_err[CoreI]),
|
||||
|
||||
.data_req_o (host_req[CoreD]),
|
||||
.data_gnt_i (host_gnt[CoreD]),
|
||||
|
|
|
@ -64,6 +64,7 @@ module core_ibex_tb_top;
|
|||
force dut.instr_rvalid_i = instr_mem_vif.rvalid;
|
||||
force instr_mem_vif.addr = dut.instr_addr_o;
|
||||
force dut.instr_rdata_i = instr_mem_vif.rdata;
|
||||
force dut.instr_err_i = 0; // TODO(taliu) Support interface error
|
||||
// IRQ interface
|
||||
force irq_vif.clock = clk;
|
||||
force irq_vif.reset = ~rst_n;
|
||||
|
|
|
@ -58,6 +58,7 @@ module top_artya7_100 (
|
|||
.instr_rvalid_i (instr_rvalid),
|
||||
.instr_addr_o (instr_addr),
|
||||
.instr_rdata_i (instr_rdata),
|
||||
.instr_err_i ('b0),
|
||||
|
||||
.data_req_o (data_req),
|
||||
.data_gnt_i (data_gnt),
|
||||
|
|
|
@ -87,6 +87,7 @@ module ibex_tracing_tb;
|
|||
.instr_rvalid_i (instr_rvalid),
|
||||
.instr_addr_o (),
|
||||
.instr_rdata_i (instr_rdata),
|
||||
.instr_err_i (1'b0),
|
||||
|
||||
// Data memory interface
|
||||
.data_req_o (),
|
||||
|
|
|
@ -45,6 +45,8 @@ module ibex_controller (
|
|||
input logic [31:0] instr_i, // instr from IF-ID reg, for mtval
|
||||
input logic [15:0] instr_compressed_i, // instr from IF-ID reg, for mtval
|
||||
input logic instr_is_compressed_i, // instr from IF-ID reg is compressed
|
||||
input logic instr_fetch_err_i, // instr from IF-ID reg has error
|
||||
input logic [31:0] pc_id_i, // instr from IF-ID reg address
|
||||
|
||||
// to IF-ID pipeline stage
|
||||
output logic instr_valid_clear_o, // kill instr in IF-ID reg
|
||||
|
@ -150,7 +152,7 @@ module ibex_controller (
|
|||
assign store_err_d = store_err_i;
|
||||
|
||||
// exception requests
|
||||
assign exc_req = ecall_insn_i | ebrk_insn_i | illegal_insn_i;
|
||||
assign exc_req = ecall_insn_i | ebrk_insn_i | illegal_insn_i | instr_fetch_err_i;
|
||||
|
||||
// LSU exception requests
|
||||
assign exc_req_lsu = store_err_i | load_err_i;
|
||||
|
@ -453,7 +455,11 @@ module ibex_controller (
|
|||
csr_save_cause_o = 1'b1;
|
||||
|
||||
// set exception registers, priorities according to Table 3.7 of Privileged Spec v1.11
|
||||
if (illegal_insn_i) begin
|
||||
if (instr_fetch_err_i) begin
|
||||
exc_cause_o = EXC_CAUSE_INSTR_ACCESS_FAULT;
|
||||
csr_mtval_o = pc_id_i;
|
||||
|
||||
end else if (illegal_insn_i) begin
|
||||
exc_cause_o = EXC_CAUSE_ILLEGAL_INSN;
|
||||
csr_mtval_o = instr_is_compressed_i ? {16'b0, instr_compressed_i} : instr_i;
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ module ibex_core #(
|
|||
input logic instr_rvalid_i,
|
||||
output logic [31:0] instr_addr_o,
|
||||
input logic [31:0] instr_rdata_i,
|
||||
input logic instr_err_i,
|
||||
|
||||
// Data memory interface
|
||||
output logic data_req_o,
|
||||
|
@ -115,6 +116,7 @@ module ibex_core #(
|
|||
logic [31:0] instr_rdata_id; // Instruction sampled inside IF stage
|
||||
logic [15:0] instr_rdata_c_id; // Compressed instruction sampled inside IF stage
|
||||
logic instr_is_compressed_id;
|
||||
logic instr_fetch_err; // Bus error on instr fetch
|
||||
logic illegal_c_insn_id; // Illegal compressed instruction sent to ID stage
|
||||
logic [31:0] pc_if; // Program counter in IF stage
|
||||
logic [31:0] pc_id; // Program counter in ID stage
|
||||
|
@ -309,6 +311,7 @@ module ibex_core #(
|
|||
.instr_gnt_i ( instr_gnt_i ),
|
||||
.instr_rvalid_i ( instr_rvalid_i ),
|
||||
.instr_rdata_i ( instr_rdata_i ),
|
||||
.instr_err_i ( instr_err_i ),
|
||||
|
||||
// outputs to ID stage
|
||||
.instr_valid_id_o ( instr_valid_id ),
|
||||
|
@ -316,6 +319,7 @@ module ibex_core #(
|
|||
.instr_rdata_id_o ( instr_rdata_id ),
|
||||
.instr_rdata_c_id_o ( instr_rdata_c_id ),
|
||||
.instr_is_compressed_id_o ( instr_is_compressed_id ),
|
||||
.instr_fetch_err_o ( instr_fetch_err ),
|
||||
.illegal_c_insn_id_o ( illegal_c_insn_id ),
|
||||
.pc_if_o ( pc_if ),
|
||||
.pc_id_o ( pc_id ),
|
||||
|
@ -382,6 +386,7 @@ module ibex_core #(
|
|||
.exc_pc_mux_o ( exc_pc_mux_id ),
|
||||
.exc_cause_o ( exc_cause ),
|
||||
|
||||
.instr_fetch_err_i ( instr_fetch_err ),
|
||||
.illegal_c_insn_i ( illegal_c_insn_id ),
|
||||
|
||||
.pc_id_i ( pc_id ),
|
||||
|
|
|
@ -31,6 +31,7 @@ module ibex_core_tracing #(
|
|||
input logic instr_rvalid_i,
|
||||
output logic [31:0] instr_addr_o,
|
||||
input logic [31:0] instr_rdata_i,
|
||||
input logic instr_err_i,
|
||||
|
||||
// Data memory interface
|
||||
output logic data_req_o,
|
||||
|
@ -109,6 +110,7 @@ module ibex_core_tracing #(
|
|||
.instr_rvalid_i,
|
||||
.instr_addr_o,
|
||||
.instr_rdata_i,
|
||||
.instr_err_i,
|
||||
|
||||
.data_req_o,
|
||||
.data_gnt_i,
|
||||
|
|
|
@ -30,6 +30,7 @@ module ibex_fetch_fifo (
|
|||
// input port
|
||||
input logic [31:0] in_addr_i,
|
||||
input logic [31:0] in_rdata_i,
|
||||
input logic in_err_i,
|
||||
input logic in_valid_i,
|
||||
output logic in_ready_o,
|
||||
|
||||
|
@ -39,6 +40,7 @@ module ibex_fetch_fifo (
|
|||
input logic out_ready_i,
|
||||
output logic [31:0] out_rdata_o,
|
||||
output logic [31:0] out_addr_o,
|
||||
output logic out_err_o,
|
||||
|
||||
output logic out_valid_stored_o // same as out_valid_o, except that if something is
|
||||
// incoming now it is not included. This signal is
|
||||
|
@ -50,10 +52,12 @@ module ibex_fetch_fifo (
|
|||
// index 0 is used for output
|
||||
logic [DEPTH-1:0] [31:0] addr_n, addr_int, addr_q;
|
||||
logic [DEPTH-1:0] [31:0] rdata_n, rdata_int, rdata_q;
|
||||
logic [DEPTH-1:0] err_n, err_int, err_q;
|
||||
logic [DEPTH-1:0] valid_n, valid_int, valid_q;
|
||||
|
||||
logic [31:2] addr_next;
|
||||
logic [31:0] rdata, rdata_unaligned;
|
||||
logic err, err_unaligned;
|
||||
logic valid, valid_unaligned;
|
||||
|
||||
logic aligned_is_compressed, unaligned_is_compressed;
|
||||
|
@ -65,12 +69,22 @@ module ibex_fetch_fifo (
|
|||
|
||||
|
||||
assign rdata = valid_q[0] ? rdata_q[0] : in_rdata_i;
|
||||
assign err = valid_q[0] ? err_q[0] : in_err_i;
|
||||
assign valid = valid_q[0] | in_valid_i;
|
||||
|
||||
assign rdata_unaligned = valid_q[1] ? {rdata_q[1][15:0], rdata[31:16]} :
|
||||
{in_rdata_i[15:0], rdata[31:16]};
|
||||
// it is implied that rdata_valid_q[0] is set
|
||||
assign valid_unaligned = valid_q[1] | (valid_q[0] & in_valid_i);
|
||||
// If entry[1] is valid, an error can come from entry[0] or entry[1], unless the
|
||||
// instruction in entry[0] is compressed (entry[1] is a new instruction)
|
||||
// If entry[1] is not valid, and entry[0] is, an error can come from entry[0] or the incoming
|
||||
// data, unless the instruction in entry[0] is compressed
|
||||
// If entry[0] is not valid, the error must come from the incoming data
|
||||
assign err_unaligned = valid_q[1] ? ((err_q[1] & ~unaligned_is_compressed) | err_q[0]) :
|
||||
((valid_q[0] & err_q[0]) |
|
||||
(in_err_i & (~valid_q[0] | ~unaligned_is_compressed)));
|
||||
// An uncompressed unaligned instruction is only valid if both parts are available
|
||||
assign valid_unaligned = valid_q[1] ? 1'b1 :
|
||||
(valid_q[0] & in_valid_i);
|
||||
|
||||
assign unaligned_is_compressed = rdata[17:16] != 2'b11;
|
||||
assign aligned_is_compressed = rdata[ 1: 0] != 2'b11;
|
||||
|
@ -87,6 +101,7 @@ module ibex_fetch_fifo (
|
|||
if (out_addr_o[1]) begin
|
||||
// unaligned case
|
||||
out_rdata_o = rdata_unaligned;
|
||||
out_err_o = err_unaligned;
|
||||
|
||||
if (unaligned_is_compressed) begin
|
||||
out_valid_o = valid;
|
||||
|
@ -96,6 +111,7 @@ module ibex_fetch_fifo (
|
|||
end else begin
|
||||
// aligned case
|
||||
out_rdata_o = rdata;
|
||||
out_err_o = err;
|
||||
out_valid_o = valid;
|
||||
end
|
||||
end
|
||||
|
@ -134,12 +150,14 @@ module ibex_fetch_fifo (
|
|||
always_comb begin
|
||||
addr_int = addr_q;
|
||||
rdata_int = rdata_q;
|
||||
err_int = err_q;
|
||||
valid_int = valid_q;
|
||||
if (in_valid_i) begin
|
||||
for (int j = 0; j < DEPTH; j++) begin
|
||||
if (!valid_q[j]) begin
|
||||
addr_int[j] = in_addr_i;
|
||||
rdata_int[j] = in_rdata_i;
|
||||
err_int[j] = in_err_i;
|
||||
valid_int[j] = 1'b1;
|
||||
break;
|
||||
end
|
||||
|
@ -153,6 +171,7 @@ module ibex_fetch_fifo (
|
|||
always_comb begin
|
||||
addr_n = addr_int;
|
||||
rdata_n = rdata_int;
|
||||
err_n = err_int;
|
||||
valid_n = valid_int;
|
||||
|
||||
if (out_ready_i && out_valid_o) begin
|
||||
|
@ -165,6 +184,7 @@ module ibex_fetch_fifo (
|
|||
end
|
||||
|
||||
rdata_n = {32'b0, rdata_int[DEPTH-1:1]};
|
||||
err_n = {1'b0, err_int[DEPTH-1:1]};
|
||||
valid_n = {1'b0, valid_int[DEPTH-1:1]};
|
||||
end else if (aligned_is_compressed) begin
|
||||
// just increase address, do not move to next entry in FIFO
|
||||
|
@ -173,6 +193,7 @@ module ibex_fetch_fifo (
|
|||
// move to next entry in FIFO
|
||||
addr_n[0] = {addr_next[31:2], 2'b00};
|
||||
rdata_n = {32'b0, rdata_int[DEPTH-1:1]};
|
||||
err_n = {1'b0, err_int[DEPTH-1:1]};
|
||||
valid_n = {1'b0, valid_int[DEPTH-1:1]};
|
||||
end
|
||||
end
|
||||
|
@ -186,6 +207,7 @@ module ibex_fetch_fifo (
|
|||
if (!rst_ni) begin
|
||||
addr_q <= '{default: '0};
|
||||
rdata_q <= '{default: '0};
|
||||
err_q <= '0;
|
||||
valid_q <= '0;
|
||||
end else begin
|
||||
// on a clear signal from outside we invalidate the content of the FIFO
|
||||
|
@ -195,6 +217,7 @@ module ibex_fetch_fifo (
|
|||
end else begin
|
||||
addr_q <= addr_n;
|
||||
rdata_q <= rdata_n;
|
||||
err_q <= err_n;
|
||||
valid_q <= valid_n;
|
||||
end
|
||||
end
|
||||
|
|
|
@ -65,6 +65,7 @@ module ibex_id_stage #(
|
|||
output ibex_pkg::exc_cause_e exc_cause_o,
|
||||
|
||||
input logic illegal_c_insn_i,
|
||||
input logic instr_fetch_err_i,
|
||||
|
||||
input logic [31:0] pc_id_i,
|
||||
|
||||
|
@ -419,6 +420,8 @@ module ibex_id_stage #(
|
|||
.instr_i ( instr_rdata_i ),
|
||||
.instr_compressed_i ( instr_rdata_c_i ),
|
||||
.instr_is_compressed_i ( instr_is_compressed_i ),
|
||||
.instr_fetch_err_i ( instr_fetch_err_i ),
|
||||
.pc_id_i ( pc_id_i ),
|
||||
|
||||
// to IF-ID pipeline
|
||||
.instr_valid_clear_o ( instr_valid_clear_o ),
|
||||
|
@ -630,7 +633,8 @@ module ibex_id_stage #(
|
|||
|
||||
// the instruction delivered to the ID stage should always be valid
|
||||
assert property (
|
||||
@(posedge clk_i) (instr_valid_i & (~illegal_c_insn_i)) |-> (!$isunknown(instr_rdata_i)) ) else
|
||||
@(posedge clk_i) (instr_valid_i & ~(illegal_c_insn_i | instr_fetch_err_i)) |->
|
||||
(!$isunknown(instr_rdata_i)) ) else
|
||||
$display("Instruction is valid, but has at least one X");
|
||||
|
||||
// make sure multicycles enable signals are unique
|
||||
|
|
|
@ -42,6 +42,7 @@ module ibex_if_stage #(
|
|||
input logic instr_gnt_i,
|
||||
input logic instr_rvalid_i,
|
||||
input logic [31:0] instr_rdata_i,
|
||||
input logic instr_err_i,
|
||||
|
||||
// output of ID stage
|
||||
output logic instr_valid_id_o, // instr in IF-ID is valid
|
||||
|
@ -52,6 +53,7 @@ module ibex_if_stage #(
|
|||
// instr_is_compressed_id_o = 1'b1
|
||||
output logic instr_is_compressed_id_o, // compressed decoder thinks this
|
||||
// is a compressed instr
|
||||
output logic instr_fetch_err_o, // bus error on fetch
|
||||
output logic illegal_c_insn_id_o, // compressed decoder thinks this
|
||||
// is an invalid instr
|
||||
output logic [31:0] pc_if_o,
|
||||
|
@ -97,6 +99,7 @@ module ibex_if_stage #(
|
|||
logic fetch_ready;
|
||||
logic [31:0] fetch_rdata;
|
||||
logic [31:0] fetch_addr;
|
||||
logic fetch_err;
|
||||
|
||||
logic [31:0] exc_pc;
|
||||
|
||||
|
@ -155,6 +158,7 @@ module ibex_if_stage #(
|
|||
.valid_o ( fetch_valid ),
|
||||
.rdata_o ( fetch_rdata ),
|
||||
.addr_o ( fetch_addr ),
|
||||
.err_o ( fetch_err ),
|
||||
|
||||
// goes to instruction memory / instruction cache
|
||||
.instr_req_o ( instr_req_o ),
|
||||
|
@ -162,6 +166,7 @@ module ibex_if_stage #(
|
|||
.instr_gnt_i ( instr_gnt_i ),
|
||||
.instr_rvalid_i ( instr_rvalid_i ),
|
||||
.instr_rdata_i ( instr_rdata_i ),
|
||||
.instr_err_i ( instr_err_i ),
|
||||
|
||||
// Prefetch Buffer Status
|
||||
.busy_o ( prefetch_busy )
|
||||
|
@ -241,6 +246,7 @@ module ibex_if_stage #(
|
|||
instr_new_id_o <= 1'b0;
|
||||
instr_valid_id_o <= 1'b0;
|
||||
instr_rdata_id_o <= '0;
|
||||
instr_fetch_err_o <= '0;
|
||||
instr_rdata_c_id_o <= '0;
|
||||
instr_is_compressed_id_o <= 1'b0;
|
||||
illegal_c_insn_id_o <= 1'b0;
|
||||
|
@ -250,6 +256,7 @@ module ibex_if_stage #(
|
|||
if (if_id_pipe_reg_we) begin
|
||||
instr_valid_id_o <= 1'b1;
|
||||
instr_rdata_id_o <= instr_decompressed;
|
||||
instr_fetch_err_o <= fetch_err;
|
||||
instr_rdata_c_id_o <= fetch_rdata[15:0];
|
||||
instr_is_compressed_id_o <= instr_is_compressed_int;
|
||||
illegal_c_insn_id_o <= illegal_c_insn;
|
||||
|
|
|
@ -190,6 +190,7 @@ typedef enum logic [5:0] {
|
|||
// EXC_CAUSE_IRQ_FAST_14 = {1'b1, 5'd30},
|
||||
EXC_CAUSE_IRQ_NM = {1'b1, 5'd31}, // == EXC_CAUSE_IRQ_FAST_15
|
||||
EXC_CAUSE_INSN_ADDR_MISA = {1'b0, 5'd00},
|
||||
EXC_CAUSE_INSTR_ACCESS_FAULT = {1'b0, 5'd01},
|
||||
EXC_CAUSE_ILLEGAL_INSN = {1'b0, 5'd02},
|
||||
EXC_CAUSE_BREAKPOINT = {1'b0, 5'd03},
|
||||
EXC_CAUSE_LOAD_ACCESS_FAULT = {1'b0, 5'd05},
|
||||
|
|
|
@ -34,6 +34,7 @@ module ibex_prefetch_buffer (
|
|||
output logic valid_o,
|
||||
output logic [31:0] rdata_o,
|
||||
output logic [31:0] addr_o,
|
||||
output logic err_o,
|
||||
|
||||
|
||||
// goes to instruction memory / instruction cache
|
||||
|
@ -41,6 +42,7 @@ module ibex_prefetch_buffer (
|
|||
input logic instr_gnt_i,
|
||||
output logic [31:0] instr_addr_o,
|
||||
input logic [31:0] instr_rdata_i,
|
||||
input logic instr_err_i,
|
||||
input logic instr_rvalid_i,
|
||||
|
||||
// Prefetch Buffer Status
|
||||
|
@ -79,6 +81,7 @@ module ibex_prefetch_buffer (
|
|||
|
||||
.in_addr_i ( instr_addr_q ),
|
||||
.in_rdata_i ( instr_rdata_i ),
|
||||
.in_err_i ( instr_err_i ),
|
||||
.in_valid_i ( fifo_valid ),
|
||||
.in_ready_o ( fifo_ready ),
|
||||
|
||||
|
@ -87,6 +90,7 @@ module ibex_prefetch_buffer (
|
|||
.out_ready_i ( ready_i ),
|
||||
.out_rdata_o ( rdata_o ),
|
||||
.out_addr_o ( addr_o ),
|
||||
.out_err_o ( err_o ),
|
||||
|
||||
.out_valid_stored_o ( )
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue