diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 93b62c55..8788771e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -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]" diff --git a/doc/introduction.rst b/doc/introduction.rst index fcd9410c..cdfb43ee 100644 --- a/doc/introduction.rst +++ b/doc/introduction.rst @@ -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. diff --git a/doc/pipeline_details.rst b/doc/pipeline_details.rst index eb13dd6b..2c860436 100644 --- a/doc/pipeline_details.rst +++ b/doc/pipeline_details.rst @@ -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). | ++-----------------------+-----------------------+-------------------------------------------------------------+ diff --git a/rtl/ibex_decoder.sv b/rtl/ibex_decoder.sv index 72f483dd..cbfb4a7f 100644 --- a/rtl/ibex_decoder.sv +++ b/rtl/ibex_decoder.sv @@ -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 diff --git a/rtl/ibex_prefetch_buffer.sv b/rtl/ibex_prefetch_buffer.sv index 605010ab..ebd60246 100644 --- a/rtl/ibex_prefetch_buffer.sv +++ b/rtl/ibex_prefetch_buffer.sv @@ -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 #(