diff --git a/src/ariane.sv b/src/ariane.sv index 1914e2835..3d0af9ad1 100644 --- a/src/ariane.sv +++ b/src/ariane.sv @@ -228,6 +228,9 @@ module ariane logic flush_ctrl_ex; logic flush_tlb_ctrl_ex; logic sfence_vma_commit_controller; + logic halt_ctrl_commit; + logic halt_debug_ctrl; + logic halt_csr_ctrl; assign sec_lvl_o = priv_lvl; // -------------- @@ -426,6 +429,7 @@ module ariane // Commit // --------- commit_stage commit_stage_i ( + .halt_i ( halt_ctrl_commit ), .exception_o ( ex_commit ), .commit_instr_i ( commit_instr_id_commit ), .commit_ack_o ( commit_ack ), @@ -452,6 +456,7 @@ module ariane ) csr_regfile_i ( .flush_o ( flush_csr_ctrl ), + .halt_csr_o ( halt_csr_ctrl ), .commit_ack_i ( commit_ack ), .ex_i ( ex_commit ), .csr_op_i ( csr_op_commit_csr ), @@ -489,6 +494,10 @@ module ariane .flush_id_o ( flush_ctrl_id ), .flush_ex_o ( flush_ctrl_ex ), .flush_tlb_o ( flush_tlb_ctrl_ex ), + + .halt_csr_i ( halt_csr_ctrl ), + .halt_debug_i ( 1'b0 ), + .halt_o ( halt_ctrl_commit ), // control ports .eret_i ( eret ), .ex_i ( ex_commit ), diff --git a/src/commit_stage.sv b/src/commit_stage.sv index 78b4dfebe..10b1b6a3b 100644 --- a/src/commit_stage.sv +++ b/src/commit_stage.sv @@ -19,8 +19,10 @@ import ariane_pkg::*; module commit_stage ( - input logic clk_i, // Clock - input logic rst_ni, // Asynchronous reset active low + input logic clk_i, // Clock + input logic rst_ni, // Asynchronous reset active low + + input logic halt_i, // request to halt the core output exception exception_o, // take exception to controller @@ -66,7 +68,8 @@ module commit_stage ( sfence_vma_o = 1'b0; // we will not commit the instruction if we took an exception - if (commit_instr_i.valid) begin + // but we do not commit the instruction if we requested a halt + if (commit_instr_i.valid && !halt_i) begin // register will be the all zero register. // and also acknowledge the instruction, this is mainly done for the instruction tracer // as it will listen on the instruction ack signal. For the overall result it does not make any diff --git a/src/controller.sv b/src/controller.sv index a3f1e856d..bd676a743 100644 --- a/src/controller.sv +++ b/src/controller.sv @@ -31,6 +31,9 @@ module controller ( output logic flush_ex_o, // Flush EX stage output logic flush_tlb_o, // Flush TLBs + input logic halt_csr_i, // Halt request from CSR (WFI instruction) + input logic halt_debug_i, // Halt request from debug + output logic halt_o, // Halt signal to commit stage input logic eret_i, // Return from exception input exception ex_i, // We got an exception, flush the pipeline input branchpredict resolved_branch_i, // We got a resolved branch, check if we need to flush the front-end @@ -111,5 +114,11 @@ module controller ( end end - // flush on exception + + // ---------------------- + // Halt Logic + // ---------------------- + always_comb begin + halt_o = halt_debug_i || halt_csr_i; + end endmodule diff --git a/src/csr_regfile.sv b/src/csr_regfile.sv index e10801a1a..5d36a164a 100644 --- a/src/csr_regfile.sv +++ b/src/csr_regfile.sv @@ -27,6 +27,7 @@ module csr_regfile #( input logic rst_ni, // Asynchronous reset active low // send a flush request out if a CSR with a side effect has changed (e.g. written) output logic flush_o, + output logic halt_csr_o, // halt requested // commit acknowledge input logic commit_ack_i, // Commit acknowledged a instruction -> increase instret CSR // Core and Cluster ID @@ -131,9 +132,11 @@ module csr_regfile #( logic [63:0] scause_q, scause_n; logic [63:0] stval_q, stval_n; - logic [63:0] cycle_q, cycle_n; - logic [63:0] time_q, time_n; - logic [63:0] instret_q, instret_n; + logic wfi_n, wfi_q; + + logic [63:0] cycle_q, cycle_n; + logic [63:0] time_q, time_n; + logic [63:0] instret_q, instret_n; typedef struct packed { logic [3:0] mode; @@ -466,6 +469,8 @@ module csr_regfile #( // -------------------------------------- always_comb begin : exception_ctrl automatic logic [63:0] interrupt_cause = '0; + // wait for interrupt register + wfi_n = wfi_q; csr_exception_o = { 64'b0, 64'b0, 1'b0 @@ -532,6 +537,17 @@ module csr_regfile #( // this spares the extra wiring from commit to CSR and back to commit csr_exception_o.valid = 1'b1; end + + // ------------------- + // Wait for Interrupt + // ------------------- + // if there is any interrupt pending un-stall the core + if (|mip_q) begin + wfi_n = 1'b0; + // or alternatively if there is no exception pending, wait here for the interrupt + end else if (csr_op_i == WFI && !ex_i.valid) begin + wfi_n = 1'b1; + end end // ------------------- @@ -549,6 +565,7 @@ module csr_regfile #( assign tvm_o = mstatus_q.tvm; assign tw_o = mstatus_q.tw; assign tsr_o = mstatus_q.tsr; + assign halt_csr_o = wfi_q; // output assignments dependent on privilege mode always_comb begin : priv_output @@ -599,6 +616,8 @@ module csr_regfile #( instret_q <= 64'b0; // aux registers en_ld_st_translation_q <= 1'b0; + // wait for interrupt + wfi_q <= 1'b0; end else begin priv_lvl_q <= priv_lvl_n; // machine mode registers @@ -624,6 +643,8 @@ module csr_regfile #( instret_q <= instret_n; // aux registers en_ld_st_translation_q <= en_ld_st_translation_n; + // wait for interrupt + wfi_q <= wfi_n; end end diff --git a/src/decoder.sv b/src/decoder.sv index 4075308a8..23f328fec 100644 --- a/src/decoder.sv +++ b/src/decoder.sv @@ -121,8 +121,15 @@ module decoder ( instruction_o.op = WFI; // if timeout wait is set, trap on an illegal instruction in S Mode // (after 0 cycles timeout) - if (priv_lvl_i == PRIV_LVL_S && tw_i) + if (priv_lvl_i == PRIV_LVL_S && tw_i) begin illegal_instr = 1'b1; + instruction_o.op = ADD; + end + // we don't support U mode interrupts so WFI is illegal in this context + if (priv_lvl_i == PRIV_LVL_U) begin + illegal_instr = 1'b1; + instruction_o.op = ADD; + end end // SFENCE.VMA default: begin