[rtl] Implement FENCE.I

Fixes #391
This commit is contained in:
Greg Chadwick 2019-11-26 09:57:27 +00:00
parent e5ee5fa81a
commit 11749c7e4d
5 changed files with 43 additions and 16 deletions

View file

@ -114,7 +114,7 @@ jobs:
export RISCV_TARGET=ibex
export RISCV_DEVICE=rv32imc
fail=0
for isa in rv32i rv32im rv32imc rv32Zicsr; do
for isa in rv32i rv32im rv32imc rv32Zicsr rv32Zifencei; do
make -C build/riscv-compliance RISCV_ISA=$isa 2>&1 | tee run.log
if [ ${PIPESTATUS[0]} != 0 ]; then
echo -n "##vso[task.logissue type=error]"

View file

@ -50,6 +50,10 @@ In addition, the following instruction set extensions are available.
- 2.0
- always enabled
* - **Zifencei**: Instruction-Fetch Fence
- 2.0
- always enabled
Most content of the RISC-V privileged specification is optional.
Ibex currently supports the following features according to the RISC-V Privileged Specification, version 1.11.

View file

@ -75,3 +75,8 @@ Read the description for more information.
| | | instruction-side memory interface takes to receive data the |
| | | longer the branch will stall. |
+-----------------------+-----------------------+-------------------------------------------------------------+
| Instruction Fence | 1 - N | The FENCE.I instruction as defined in 'Zifencei' of the |
| | | RISC-V specification. Internally it is implemented as a |
| | | jump (which does the required flushing) so it has the same |
| | | stall characteristics (see above). |
+-----------------------+-----------------------+-------------------------------------------------------------+

View file

@ -490,20 +490,36 @@ module ibex_decoder #(
/////////////
OPCODE_MISC_MEM: begin
// For now, treat the fence (funct3 == 000) instruction as a nop.
// This may not be correct in a system with caches and should be
// revisited.
// fence.i (funct3 == 001) was moved to a separate Zifencei extension
// in the RISC-V ISA spec proposed for ratification, so we treat it as
// an illegal instruction.
if (instr[14:12] == 3'b000) begin
alu_operator_o = ALU_ADD; // nop
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_IMM;
regfile_we = 1'b0;
end else begin
illegal_insn = 1'b1;
end
// For now, treat the FENCE (funct3 == 000) instruction as a NOP. This may not be correct
// in a system with caches and should be revisited.
// FENCE.I will flush the IF stage and prefetch buffer but nothing else.
unique case (instr[14:12])
3'b000: begin
alu_operator_o = ALU_ADD; // nop
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_IMM;
regfile_we = 1'b0;
end
3'b001: begin
// FENCE.I is implemented as a jump to the next PC, this gives the required flushing
// behaviour (iside prefetch buffer flushed and response to any outstanding iside
// requests will be ignored).
jump_in_dec_o = 1'b1;
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_INCR_PC;
alu_operator_o = ALU_ADD;
regfile_we = 1'b0;
if (instr_new_i) begin
jump_set_o = 1'b1;
end
end
default: begin
illegal_insn = 1'b1;
end
endcase
end
OPCODE_SYSTEM: begin

View file

@ -74,7 +74,9 @@ module ibex_prefetch_buffer (
// PMP errors are generated in the address phase, and registered into a fake data phase
assign instr_or_pmp_err = instr_err_i | rdata_pmp_err_q[0];
// A branch will invalidate any previously fetched instructions
// A branch will invalidate any previously fetched instructions.
// Note that the FENCE.I instruction relies on this flushing behaviour on branch. If it is
// altered the FENCE.I implementation may require changes.
assign fifo_clear = branch_i;
ibex_fetch_fifo #(