Implement WFI as stalling, fix issue #51

This commit is contained in:
Florian Zaruba 2017-06-27 18:57:39 +02:00
parent f1272d0c55
commit 5aa9084279
5 changed files with 57 additions and 8 deletions

View file

@ -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 ),

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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