update new int controller

This commit is contained in:
Pasquale Davide Schiavone 2017-04-26 15:35:07 +02:00
parent d0a0d8d093
commit cb54f9dc01
10 changed files with 444 additions and 417 deletions

View file

@ -191,6 +191,13 @@ parameter SP_DCR_MSB = 8'h01;
parameter SP_DMR_MSB = 8'h02;
parameter SP_DSR_MSB = 8'h04;
// Privileged mode
typedef enum logic[1:0] {
PRIV_LVL_M = 2'b11,
PRIV_LVL_H = 2'b10,
PRIV_LVL_S = 2'b01,
PRIV_LVL_U = 2'b00
} PrivLvl_t;
///////////////////////////////////////////////
// ___ ____ ____ _ //
@ -280,6 +287,11 @@ parameter EXC_PC_LOAD = 2'b10;
parameter EXC_PC_STORE = 2'b10;
parameter EXC_PC_IRQ = 2'b11;
// Exception Cause
parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
parameter EXC_CAUSE_BREAKPOINT = 6'h03;
parameter EXC_CAUSE_ECALL_MMODE = 6'h0B;
// Exceptions offsets
// target address = {boot_addr[31:8], EXC_OFF} (boot_addr must be 32 BYTE aligned!)
// offset 00 to 7e is used for external interrupts

View file

@ -11,7 +11,7 @@ zeroriscy:
zeroriscy_cs_registers.sv,
zeroriscy_debug_unit.sv,
zeroriscy_decoder.sv,
zeroriscy_exc_controller.sv,
zeroriscy_int_controller.sv,
zeroriscy_ex_block.sv,
zeroriscy_id_stage.sv,
zeroriscy_if_stage.sv,

View file

@ -47,10 +47,13 @@ module zeroriscy_controller
// decoder related signals
output logic deassert_we_o, // deassert write enable for next instruction
input logic illegal_insn_i, // decoder encountered an invalid instruction
input logic mret_insn_i, // decoder encountered an eret instruction
input logic ecall_insn_i, // ecall encountered an mret instruction
input logic mret_insn_i, // decoder encountered an mret instruction
input logic pipe_flush_i, // decoder wants to do a pipe flush
input logic ebrk_insn_i, // decoder encountered an ebreak instruction
input logic csr_status_i, // decoder encountered an csr status instruction
// from IF/ID pipeline
input logic instr_valid_i, // instruction coming from IF/ID pipeline is valid
@ -61,6 +64,7 @@ module zeroriscy_controller
// to prefetcher
output logic pc_set_o, // jump to address set by pc_mux
output logic [2:0] pc_mux_o, // Selector in the Fetch stage to select the rigth PC (normal, jump ...)
output logic [1:0] exc_pc_mux_o, // Selects target PC for exception
// LSU
input logic data_misaligned_i,
@ -74,14 +78,23 @@ module zeroriscy_controller
input logic instr_multicyle_i, // multicycle instructions active
// Exception Controller Signals
input logic int_req_i,
input logic ext_req_i,
output logic exc_ack_o,
// Interrupt Controller Signals
input logic irq_req_ctrl_i,
input logic [4:0] irq_id_ctrl_i,
input logic m_IE_i, // interrupt enable bit from CSR (M mode)
output logic irq_ack_o,
output logic exc_save_if_o,
output logic exc_save_id_o,
output logic exc_restore_id_o,
output logic [5:0] exc_cause_o,
output logic exc_ack_o,
output logic exc_kill_o,
output logic csr_save_if_o,
output logic csr_save_id_o,
output logic [5:0] csr_cause_o,
output logic csr_restore_mret_id_o,
output logic csr_save_cause_o,
// Debug Signals
input logic dbg_req_i, // a trap was hit, so we have to flush EX and WB
@ -90,6 +103,9 @@ module zeroriscy_controller
input logic dbg_stall_i, // Pipeline stall is requested
input logic dbg_jump_req_i, // Change PC to value from debug unit
input logic [DBG_SETS_W-1:0] dbg_settings_i,
output logic dbg_trap_o,
// forwarding signals
output logic [1:0] operand_a_fw_mux_sel_o, // regfile ra data selector form ID stage
@ -111,11 +127,12 @@ module zeroriscy_controller
);
// FSM state encoding
enum logic [3:0] { RESET, BOOT_SET, WAIT_SLEEP, SLEEP, FIRST_FETCH,
DECODE, FLUSH, IRQ_TAKEN,
DBG_SIGNAL, DBG_SIGNAL_SLEEP, DBG_WAIT, DBG_WAIT_BRANCH, DBG_WAIT_SLEEP } ctrl_fsm_cs, ctrl_fsm_ns;
logic irq_enable_int;
`ifndef SYNTHESIS
// synopsys translate_off
// make sure we are called later so that we do not generate messages for
@ -145,27 +162,45 @@ module zeroriscy_controller
always_comb
begin
// Default values
instr_req_o = 1'b1;
instr_req_o = 1'b1;
exc_ack_o = 1'b0;
exc_save_if_o = 1'b0;
exc_save_id_o = 1'b0;
exc_restore_id_o = 1'b0;
exc_ack_o = 1'b0;
exc_kill_o = 1'b0;
pc_mux_o = PC_BOOT;
pc_set_o = 1'b0;
csr_save_if_o = 1'b0;
csr_save_id_o = 1'b0;
csr_restore_mret_id_o = 1'b0;
csr_save_cause_o = 1'b0;
ctrl_fsm_ns = ctrl_fsm_cs;
exc_cause_o = '0;
exc_pc_mux_o = EXC_PC_IRQ;
ctrl_busy_o = 1'b1;
is_decoding_o = 1'b0;
csr_cause_o = '0;
halt_if_o = 1'b0;
halt_id_o = 1'b0;
dbg_ack_o = 1'b0;
pc_mux_o = PC_BOOT;
pc_set_o = 1'b0;
irq_ack_o = 1'b0;
first_fetch_o = 1'b0;
ctrl_fsm_ns = ctrl_fsm_cs;
ctrl_busy_o = 1'b1;
is_decoding_o = 1'b0;
first_fetch_o = 1'b0;
halt_if_o = 1'b0;
halt_id_o = 1'b0;
dbg_ack_o = 1'b0;
irq_ack_o = 1'b0;
irq_enable_int = m_IE_i;
// a trap towards the debug unit is generated when one of the
// following conditions are true:
// - ebreak instruction encountered
// - single-stepping mode enabled
// - illegal instruction exception and IIE bit is set
// - IRQ and INTE bit is set and no exception is currently running
// - Debuger requests halt
dbg_trap_o = 1'b0;
unique case (ctrl_fsm_cs)
// We were just reset, wait for fetch_enable
@ -211,18 +246,19 @@ module zeroriscy_controller
instr_req_o = 1'b0;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
if (dbg_req_i) begin
// debug request, now we need to check if we should stay sleeping or
// go to normal processing later
if (fetch_enable_i || ext_req_i)
if (fetch_enable_i || irq_req_ctrl_i)
ctrl_fsm_ns = DBG_SIGNAL;
else
ctrl_fsm_ns = DBG_SIGNAL_SLEEP;
end else begin
// no debug request incoming, normal execution flow
if (fetch_enable_i || ext_req_i)
if (fetch_enable_i || irq_req_ctrl_i)
begin
ctrl_fsm_ns = FIRST_FETCH;
end
@ -238,7 +274,7 @@ module zeroriscy_controller
ctrl_fsm_ns = DECODE;
end
if (ext_req_i) begin
if (irq_req_ctrl_i & irq_enable_int) begin
// This assumes that the pipeline is always flushed before
// going to sleep.
ctrl_fsm_ns = IRQ_TAKEN;
@ -263,44 +299,30 @@ module zeroriscy_controller
branch_set_i: begin
pc_mux_o = PC_JUMP;
pc_set_o = 1'b1;
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
if (dbg_req_i)
ctrl_fsm_ns = DBG_SIGNAL;
end
jump_set_i: begin
pc_mux_o = PC_JUMP;
pc_set_o = 1'b1;
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
if (dbg_req_i)
ctrl_fsm_ns = DBG_SIGNAL;
end
int_req_i: begin
ctrl_fsm_ns = FLUSH;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
mret_insn_i: begin
ctrl_fsm_ns = FLUSH;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
pipe_flush_i: begin
// handle WFI instruction, flush pipeline and (potentially) go to
// sleep
ctrl_fsm_ns = FLUSH;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
ebrk_insn_i: begin
mret_insn_i | ecall_insn_i | pipe_flush_i | ebrk_insn_i | illegal_insn_i | csr_status_i: begin
ctrl_fsm_ns = FLUSH;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
default: begin
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
unique case (1'b1)
ext_req_i & ~instr_multicyle_i & ~branch_in_id_i: begin
irq_req_ctrl_i & irq_enable_int & ~instr_multicyle_i & ~branch_in_id_i: begin
ctrl_fsm_ns = IRQ_TAKEN;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
end
dbg_req_i & ~branch_taken_ex_i: begin
halt_if_o = 1'b1;
@ -308,15 +330,15 @@ module zeroriscy_controller
ctrl_fsm_ns = DBG_SIGNAL;
end
end
default:;
default:
exc_kill_o = irq_req_ctrl_i & ~instr_multicyle_i & ~branch_in_id_i ? 1'b1 : 1'b0;
endcase
end
endcase
end
else //~instr_valid_i
begin
if (ext_req_i) begin
if (irq_req_ctrl_i & irq_enable_int) begin
ctrl_fsm_ns = IRQ_TAKEN;
halt_if_o = 1'b1;
halt_id_o = 1'b1;
@ -376,6 +398,24 @@ module zeroriscy_controller
end
end
IRQ_TAKEN:
begin
pc_mux_o = PC_EXCEPTION;
pc_set_o = 1'b1;
exc_pc_mux_o = EXC_PC_IRQ;
exc_cause_o = {1'b0,irq_id_ctrl_i};
csr_save_cause_o = 1'b1;
csr_cause_o = {1'b1,irq_id_ctrl_i};
csr_save_if_o = 1'b1;
irq_ack_o = 1'b1;
exc_ack_o = 1'b1;
ctrl_fsm_ns = DECODE;
end
// flush the pipeline, insert NOP
FLUSH:
@ -386,17 +426,45 @@ module zeroriscy_controller
ctrl_fsm_ns = dbg_req_i ? DBG_SIGNAL : DECODE;
unique case (1'b1)
int_req_i: begin
pc_mux_o = PC_EXCEPTION;
pc_set_o = 1'b1;
exc_ack_o = 1'b1;
exc_save_id_o = 1'b1;
unique case(1'b1)
ecall_insn_i: begin
//ecall
pc_mux_o = PC_EXCEPTION;
pc_set_o = 1'b1;
csr_save_id_o = 1'b1;
csr_save_cause_o = 1'b1;
exc_pc_mux_o = EXC_PC_ECALL;
exc_cause_o = EXC_CAUSE_ECALL_MMODE;
csr_cause_o = EXC_CAUSE_ECALL_MMODE;
dbg_trap_o = dbg_settings_i[DBG_SETS_ECALL] | dbg_settings_i[DBG_SETS_SSTE];
end
illegal_insn_i: begin
//exceptions
pc_mux_o = PC_EXCEPTION;
pc_set_o = 1'b1;
csr_save_id_o = 1'b1;
csr_save_cause_o = 1'b1;
exc_pc_mux_o = EXC_PC_ILLINSN;
exc_cause_o = EXC_CAUSE_ILLEGAL_INSN;
csr_cause_o = EXC_CAUSE_ILLEGAL_INSN;
dbg_trap_o = dbg_settings_i[DBG_SETS_EILL] | dbg_settings_i[DBG_SETS_SSTE];
end
mret_insn_i: begin
pc_mux_o = PC_ERET;
pc_set_o = 1'b1;
exc_restore_id_o = 1'b1;
//mret
pc_mux_o = PC_ERET;
pc_set_o = 1'b1;
csr_restore_mret_id_o = 1'b1;
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
end
ebrk_insn_i: begin
dbg_trap_o = dbg_settings_i[DBG_SETS_EBRK] | dbg_settings_i[DBG_SETS_SSTE];;
exc_cause_o = EXC_CAUSE_BREAKPOINT;
end
csr_status_i: begin
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
end
pipe_flush_i: begin
dbg_trap_o = dbg_settings_i[DBG_SETS_SSTE];
end
default:;
endcase
@ -414,17 +482,6 @@ module zeroriscy_controller
end
end
IRQ_TAKEN:
begin
pc_mux_o = PC_EXCEPTION;
pc_set_o = 1'b1;
exc_ack_o = 1'b1;
//the instruction in id has been already executed or it was not valid
exc_save_if_o = 1'b1;
irq_ack_o = 1'b1;
ctrl_fsm_ns = DECODE;
end
default: begin
instr_req_o = 1'b0;
ctrl_fsm_ns = RESET;
@ -485,6 +542,6 @@ module zeroriscy_controller
//----------------------------------------------------------------------------
`ifndef VERILATOR
assert property (
@(posedge clk) (~(dbg_req_i & ext_req_i)) ) else $warning("Both dbg_req_i and ext_req_i are active");
@(posedge clk) (~(dbg_req_i & irq_req_ctrl_i)) ) else $warning("Both dbg_req_i and irq_req_ctrl_i are active");
`endif
endmodule // controller

View file

@ -108,6 +108,7 @@ module zeroriscy_core
logic pc_set;
logic [2:0] pc_mux_id; // Mux selector for next PC
logic [1:0] exc_pc_mux_id; // Mux selector for exception PC
logic [5:0] exc_cause;
logic lsu_load_err;
logic lsu_store_err;
@ -115,7 +116,6 @@ module zeroriscy_core
// ID performance counter signals
logic is_decoding;
logic data_misaligned;
logic [31:0] misaligned_addr;
@ -128,7 +128,6 @@ module zeroriscy_core
logic if_busy;
logic lsu_busy;
// ALU Control
logic [ALU_OP_WIDTH-1:0] alu_operator_ex;
logic [31:0] alu_operand_a_ex;
@ -167,7 +166,6 @@ module zeroriscy_core
logic data_misaligned_ex;
logic [31:0] regfile_wdata_lsu;
// stall control
logic halt_if;
logic id_ready;
@ -183,15 +181,15 @@ module zeroriscy_core
logic instr_req_int; // Id stage asserts a req to instruction core interface
// Interrupts
logic irq_enable;
logic m_irq_enable;
logic [31:0] mepc;
logic [5:0] exc_cause;
logic save_exc_cause;
logic exc_save_if;
logic exc_save_id;
logic exc_save_takenbranch_ex;
logic exc_restore_id;
logic csr_save_cause;
logic csr_save_if;
logic csr_save_id;
logic [5:0] csr_cause;
logic csr_restore_mret_id;
logic csr_restore_uret_id;
// Debug Unit
logic [DBG_SETS_W-1:0] dbg_settings;
@ -375,6 +373,7 @@ module zeroriscy_core
.pc_set_o ( pc_set ),
.pc_mux_o ( pc_mux_id ),
.exc_pc_mux_o ( exc_pc_mux_id ),
.exc_cause_o ( exc_cause ),
.illegal_c_insn_i ( illegal_c_insn_id ),
.is_compressed_i ( is_compressed_id ),
@ -403,6 +402,11 @@ module zeroriscy_core
// CSR ID/EX
.csr_access_ex_o ( csr_access_ex ),
.csr_op_ex_o ( csr_op_ex ),
.csr_cause_o ( csr_cause ),
.csr_save_if_o ( csr_save_if ), // control signal to save pc
.csr_save_id_o ( csr_save_id ), // control signal to save pc
.csr_restore_mret_id_o ( csr_restore_mret_id ), // control signal to restore pc
.csr_save_cause_o ( csr_save_cause ),
// LSU
.data_req_ex_o ( data_req_ex ), // to load store unit
@ -419,14 +423,9 @@ module zeroriscy_core
// Interrupt Signals
.irq_i ( irq_i ), // incoming interrupts
.irq_id_i ( irq_id_i ),
.irq_enable_i ( irq_enable ), // global interrupt enable
.m_irq_enable_i ( m_irq_enable ),
.irq_ack_o ( irq_ack_o ),
.exc_cause_o ( exc_cause ),
.save_exc_cause_o ( save_exc_cause ),
.exc_save_if_o ( exc_save_if ), // control signal to save pc
.exc_save_id_o ( exc_save_id ), // control signal to save pc
.exc_restore_id_o ( exc_restore_id ), // control signal to restore pc
.lsu_load_err_i ( lsu_load_err ),
.lsu_store_err_i ( lsu_store_err ),
@ -492,7 +491,6 @@ module zeroriscy_core
.lsu_en_i ( data_req_ex ),
.lsu_ready_ex_i ( data_valid_lsu ),
.ex_ready_o ( ex_ready )
);
////////////////////////////////////////////////////////////////////////////////////////
@ -569,7 +567,8 @@ module zeroriscy_core
// Core and Cluster ID from outside
.core_id_i ( core_id_i ),
.cluster_id_i ( cluster_id_i ),
// boot address
.boot_addr_i ( boot_addr_i[31:8] ),
// Interface to CSRs (SRAM like)
.csr_access_i ( csr_access ),
.csr_addr_i ( csr_addr ),
@ -578,18 +577,17 @@ module zeroriscy_core
.csr_rdata_o ( csr_rdata ),
// Interrupt related control signals
.irq_enable_o ( irq_enable ),
.m_irq_enable_o ( m_irq_enable ),
.mepc_o ( mepc ),
.pc_if_i ( pc_if ),
.pc_id_i ( pc_id ),
.data_load_event_ex_i ( data_load_event_ex ),
.exc_save_if_i ( exc_save_if ),
.exc_save_id_i ( exc_save_id ),
.exc_restore_i ( exc_restore_id ),
.exc_cause_i ( exc_cause ),
.save_exc_cause_i ( save_exc_cause ),
.csr_save_if_i ( csr_save_if ),
.csr_save_id_i ( csr_save_id ),
.csr_restore_mret_i ( csr_restore_mret_id ),
.csr_cause_i ( csr_cause ),
.csr_save_cause_i ( csr_save_cause ),
// performance counter related signals

View file

@ -49,6 +49,9 @@ module zeroriscy_cs_registers
input logic [3:0] core_id_i,
input logic [5:0] cluster_id_i,
// Used for boot address
input logic [23:0] boot_addr_i,
// Interface to registers (SRAM like)
input logic csr_access_i,
input logic [11:0] csr_addr_i,
@ -57,19 +60,18 @@ module zeroriscy_cs_registers
output logic [31:0] csr_rdata_o,
// Interrupts
output logic irq_enable_o,
output logic m_irq_enable_o,
output logic [31:0] mepc_o,
input logic [31:0] pc_if_i,
input logic [31:0] pc_id_i,
input logic data_load_event_ex_i,
input logic exc_save_if_i,
input logic exc_save_id_i,
input logic exc_restore_i,
input logic csr_save_if_i,
input logic csr_save_id_i,
input logic csr_restore_mret_i,
input logic [5:0] exc_cause_i,
input logic save_exc_cause_i,
input logic [5:0] csr_cause_i,
input logic csr_save_cause_i,
// Performance Counters
@ -99,6 +101,29 @@ module zeroriscy_cs_registers
localparam N_PERF_REGS = N_PERF_COUNTERS;
`endif
`define MSTATUS_UIE_BITS 0
`define MSTATUS_SIE_BITS 1
`define MSTATUS_MIE_BITS 3
`define MSTATUS_UPIE_BITS 4
`define MSTATUS_SPIE_BITS 5
`define MSTATUS_MPIE_BITS 7
`define MSTATUS_SPP_BITS 8
`define MSTATUS_MPP_BITS 12:11
typedef struct packed {
//logic uie; - unimplemented, hardwired to '0
// logic sie; - unimplemented, hardwired to '0
// logic hie; - unimplemented, hardwired to '0
logic mie;
//logic upie; - unimplemented, hardwired to '0
// logic spie; - unimplemented, hardwired to '0
// logic hpie; - unimplemented, hardwired to '0
logic mpie;
// logic spp; - unimplemented, hardwired to '0
// logic[1:0] hpp; - unimplemented, hardwired to '0
PrivLvl_t mpp;
} Status_t;
// Performance Counter Signals
logic id_valid_q;
logic [N_PERF_COUNTERS-1:0] PCCR_in; // input signals for each counter category
@ -122,9 +147,8 @@ module zeroriscy_cs_registers
// Interrupt control signals
logic [31:0] mepc_q, mepc_n;
logic [ 1:0] mstatus_q, mstatus_n;
logic [ 5:0] exc_cause_q, exc_cause_n;
logic mie,mpie;
logic [ 5:0] mcause_q, mcause_n;
Status_t mstatus_q, mstatus_n;
////////////////////////////////////////////
// ____ ____ ____ ____ //
@ -135,9 +159,6 @@ module zeroriscy_cs_registers
// |___/ //
////////////////////////////////////////////
assign mie = mstatus_q[0];
assign mpie = mstatus_q[1];
// read logic
always_comb
begin
@ -146,12 +167,23 @@ module zeroriscy_cs_registers
case (csr_addr_i)
// mstatus: always M-mode, contains IE bit
12'h300: csr_rdata_int = {19'b0, 2'b11, 3'b0, mpie, 3'h0, mie, 3'h0};
12'h300: csr_rdata_int = {19'b0, mstatus_q.mpp, 3'b0, mstatus_q.mpie, 3'h0, mstatus_q.mie, 3'h0};
// mstatus
12'h300: csr_rdata_int = {
19'b0,
mstatus_q.mpp,
3'b0,
mstatus_q.mpie,
3'h0,
mstatus_q.mie,
3'h0
};
// mtvec: machine trap-handler base address
12'h305: csr_rdata_int = {boot_addr_i, 8'h0};
// mepc: exception program counter
12'h341: csr_rdata_int = mepc_q;
// mcause: exception cause
12'h342: csr_rdata_int = {exc_cause_q[5], 26'b0, exc_cause_q[4:0]};
12'h342: csr_rdata_int = {mcause_q[5], 26'b0, mcause_q[4:0]};
// mhartid: unique hardware thread id
12'hF14: csr_rdata_int = {21'b0, cluster_id_i[5:0], 1'b0, core_id_i[3:0]};
@ -165,39 +197,49 @@ module zeroriscy_cs_registers
begin
mepc_n = mepc_q;
mstatus_n = mstatus_q;
exc_cause_n = exc_cause_q;
mcause_n = mcause_q;
case (csr_addr_i)
// mstatus: IE bit
12'h300: if (csr_we_int) mstatus_n = {csr_wdata_int[7], csr_wdata_int[3]};
12'h300: if (csr_we_int) begin
mstatus_n = '{
mie: csr_wdata_int[`MSTATUS_MIE_BITS],
mpie: csr_wdata_int[`MSTATUS_MPIE_BITS],
mpp: PrivLvl_t'(PRIV_LVL_M)
};
end
// mepc: exception program counter
12'h341: if (csr_we_int) mepc_n = csr_wdata_int;
// mcause
12'h342: if (csr_we_int) exc_cause_n = {csr_wdata_int[31], csr_wdata_int[4:0]};
12'h342: if (csr_we_int) mcause_n = {csr_wdata_int[31], csr_wdata_int[4:0]};
endcase
// exception controller gets priority over other writes
if (exc_save_if_i || exc_save_id_i) begin
mstatus_n = {mie,1'b0};
unique case (1'b1)
if (data_load_event_ex_i) begin
mepc_n = pc_id_i;
end else begin
if (exc_save_if_i)
mepc_n = pc_if_i;
else
mepc_n = pc_id_i;
end
end
csr_save_cause_i: begin
unique case (1'b1)
csr_save_if_i:
mepc_n = pc_if_i;
csr_save_id_i:
mepc_n = pc_id_i;
default:;
endcase
mstatus_n.mpie = mstatus_q.mie;
mstatus_n.mie = 1'b0;
mcause_n = csr_cause_i;
end //csr_save_cause_i
if (save_exc_cause_i)
exc_cause_n = exc_cause_i;
csr_restore_mret_i: begin //MRET
mstatus_n.mie = mstatus_q.mpie;
mstatus_n.mpie = 1'b1;
end //csr_restore_mret_i
default:;
endcase
if (exc_restore_i) begin
mstatus_n = {mstatus_q[1],mstatus_q[1]};
end
end
@ -234,8 +276,8 @@ module zeroriscy_cs_registers
// directly output some registers
assign irq_enable_o = mie;
assign mepc_o = mepc_q;
assign m_irq_enable_o = mstatus_q.mie;
assign mepc_o = mepc_q;
// actual registers
@ -243,16 +285,24 @@ module zeroriscy_cs_registers
begin
if (rst_n == 1'b0)
begin
mstatus_q <= '0;
mstatus_q <= '{
mie: 1'b0,
mpie: 1'b0,
mpp: PRIV_LVL_M
};
mepc_q <= '0;
exc_cause_q <= '0;
mcause_q <= '0;
end
else
begin
// update CSRs
mstatus_q <= mstatus_n;
mstatus_q <= '{
mie: mstatus_n.mie,
mpie: mstatus_n.mpie,
mpp: PRIV_LVL_M
};
mepc_q <= mepc_n;
exc_cause_q <= exc_cause_n;
mcause_q <= mcause_n;
end
end

View file

@ -71,6 +71,7 @@ module zeroriscy_decoder
// CSR manipulation
output logic csr_access_o, // access to CSR
output logic [1:0] csr_op_o, // operation to perform on CSR
output logic csr_status_o, // access to xstatus CSR
// LD/ST unit signals
output logic data_req_o, // start transaction to data memory
@ -96,7 +97,7 @@ module zeroriscy_decoder
logic jump_in_id;
logic [1:0] csr_op;
logic csr_illegal;
/////////////////////////////////////////////
// ____ _ //
@ -126,6 +127,8 @@ module zeroriscy_decoder
regfile_we = 1'b0;
csr_access_o = 1'b0;
csr_status_o = 1'b0;
csr_illegal = 1'b0;
csr_op = CSR_OP_NONE;
data_we_o = 1'b0;
@ -531,8 +534,16 @@ module zeroriscy_decoder
2'b01: csr_op = CSR_OP_WRITE;
2'b10: csr_op = CSR_OP_SET;
2'b11: csr_op = CSR_OP_CLEAR;
default: illegal_insn_o = 1'b1;
default: csr_illegal = 1'b1;
endcase
if(~csr_illegal)
if (instr_rdata_i[31:20] == 12'h300)
//access to mstatus
csr_status_o = 1'b1;
illegal_insn_o = csr_illegal;
end
end

View file

@ -68,7 +68,7 @@ module zeroriscy_ex_block
output logic ex_ready_o // EX stage gets new data
);
localparam MULT_TYPE = 0; //0 is SLOW
localparam MULT_TYPE = 1; //0 is SLOW
logic [31:0] alu_result, multdiv_result;
@ -122,6 +122,15 @@ end
.is_equal_result_o ( alu_is_equal_result )
);
////////////////////////////////////////////////////////////////
// __ __ _ _ _ _____ ___ ____ _ ___ _____ ____ //
// | \/ | | | | | |_ _|_ _| _ \| | |_ _| ____| _ \ //
// | |\/| | | | | | | | | || |_) | | | || _| | |_) | //
// | | | | |_| | |___| | | || __/| |___ | || |___| _ < //
// |_| |_|\___/|_____|_| |___|_| |_____|___|_____|_| \_\ //
// //
////////////////////////////////////////////////////////////////
if (MULT_TYPE == 0) begin : multdiv_slow
zeroriscy_multdiv_slow multdiv_i
(

View file

@ -1,222 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 ETH Zurich, University of Bologna //
// All rights reserved. //
// //
// This code is under development and not yet released to the public. //
// Until it is released, the code is under the copyright of ETH Zurich //
// and the University of Bologna, and may contain unpublished work. //
// Any reuse/redistribution should only be under explicit permission. //
// //
// Bug fixes and contributions will eventually be released under the //
// SolderPad open hardware license and under the copyright of ETH Zurich //
// and the University of Bologna. //
// //
// Engineer: Andreas Traber - atraber@student.ethz.ch //
// //
// Additional contributions by: //
// Sven Stucki - svstucki@student.ethz.ch //
// Davide Schiavone - pschiavo@iis.ee.ethz.ch //
// //
// Design Name: Exception Controller //
// Project Name: zero-riscy //
// Language: SystemVerilog //
// //
// Description: Exception Controller of the pipelined processor //
// //
////////////////////////////////////////////////////////////////////////////////
import zeroriscy_defines::*;
module zeroriscy_exc_controller
(
input logic clk,
input logic rst_n,
// handshake signals to controller
output logic int_req_o,
output logic ext_req_o,
input logic ack_i,
input logic ctr_decoding_i,
output logic trap_o,
// to IF stage
output logic [1:0] pc_mux_o, // selects target PC for exception
// interrupt lines
input logic irq_i, // level-triggered interrupt inputs
input logic [4:0] irq_id_i, // interrupt id [0,1,....31]
input logic irq_enable_i, // interrupt enable bit from CSR
// from decoder
input logic ebrk_insn_i, // ebrk instruction encountered (EBREAK)
input logic illegal_insn_i, // illegal instruction encountered
input logic ecall_insn_i, // ecall instruction encountered
// to CSR
output logic [5:0] cause_o,
output logic save_cause_o,
// from debug unit
input logic [DBG_SETS_W-1:0] dbg_settings_i
);
enum logic [1:0] { IDLE, WAIT_CONTROLLER_INT, WAIT_CONTROLLER_EXT, WAIT_CONTROLLER_DBG } exc_ctrl_cs, exc_ctrl_ns;
logic int_req_int, ext_req_int;
logic [1:0] pc_mux_int, pc_mux_int_q;
logic [5:0] cause_int, cause_int_q;
logic trap_int;
// a trap towards the debug unit is generated when one of the
// following conditions are true:
// - ebreak instruction encountered
// - single-stepping mode enabled
// - illegal instruction exception and IIE bit is set
// - IRQ and INTE bit is set and no exception is currently running
// - Debuger requests halt
assign trap_int = (dbg_settings_i[DBG_SETS_SSTE])
| (ecall_insn_i & dbg_settings_i[DBG_SETS_ECALL])
| (ebrk_insn_i & dbg_settings_i[DBG_SETS_EBRK])
| (illegal_insn_i & dbg_settings_i[DBG_SETS_EILL])
| (irq_enable_i & irq_i & dbg_settings_i[DBG_SETS_IRQ]);
// request for exception/interrupt
assign int_req_int = ecall_insn_i
| illegal_insn_i;
assign ext_req_int = irq_enable_i & irq_i;
// Exception cause and ISR address selection
always_comb
begin
cause_int = 6'b0;
pc_mux_int = '0;
unique case(1'b1)
ebrk_insn_i:
cause_int = 6'b0_00011;
ecall_insn_i: begin
cause_int = 6'b0_01011;
pc_mux_int = EXC_PC_ECALL;
end
illegal_insn_i: begin
cause_int = 6'b0_00010;
pc_mux_int = EXC_PC_ILLINSN;
end
default: begin
//exceptions have priority over interrupts
if (irq_enable_i & irq_i) begin
// pc_mux_int is a critical signal, so try to get it as soon as possible
pc_mux_int = EXC_PC_IRQ;
cause_int = {1'b1,irq_id_i};
end
end
endcase
end
always_ff @(posedge clk, negedge rst_n)
begin
if (rst_n == 1'b0) begin
cause_int_q <= '0;
pc_mux_int_q <= '0;
end else if (exc_ctrl_cs == IDLE && (ctr_decoding_i | ext_req_o)) begin
// save cause and ISR when new irq request is first sent to controller
cause_int_q <= cause_int;
pc_mux_int_q <= pc_mux_int;
end
end
// Exception cause and mux output (with bypass)
assign cause_o = cause_int_q;
assign pc_mux_o = pc_mux_int_q;
// Exception controller FSM
always_comb
begin
exc_ctrl_ns = exc_ctrl_cs;
int_req_o = 1'b0;
ext_req_o = 1'b0;
save_cause_o = 1'b0;
trap_o = 1'b0;
unique case (exc_ctrl_cs)
IDLE:
begin
int_req_o = int_req_int;
ext_req_o = ext_req_int;
trap_o = dbg_settings_i[DBG_SETS_SSTE];
unique case(1'b1)
int_req_int & ctr_decoding_i:
exc_ctrl_ns = WAIT_CONTROLLER_INT;
ebrk_insn_i & ctr_decoding_i:
exc_ctrl_ns = WAIT_CONTROLLER_DBG;
default:
if (ext_req_o)
exc_ctrl_ns = WAIT_CONTROLLER_EXT;
endcase
end
WAIT_CONTROLLER_INT:
begin
int_req_o = 1'b1;
ext_req_o = 1'b0;
trap_o = trap_int;
if (ack_i) begin
save_cause_o = 1'b1;
exc_ctrl_ns = IDLE;
end
end
WAIT_CONTROLLER_EXT:
begin
int_req_o = 1'b0;
ext_req_o = 1'b1;
trap_o = trap_int;
if (ack_i) begin
save_cause_o = 1'b1;
exc_ctrl_ns = IDLE;
end
end
WAIT_CONTROLLER_DBG:
begin
exc_ctrl_ns = IDLE;
trap_o = trap_int;
end
default:
begin
exc_ctrl_ns = IDLE;
end
endcase
end
always_ff @(posedge clk, negedge rst_n)
begin
if (rst_n == 1'b0)
exc_ctrl_cs <= IDLE;
else
exc_ctrl_cs <= exc_ctrl_ns;
end
`ifndef SYNTHESIS
// synopsys translate_off
// evaluate at falling edge to avoid duplicates during glitches
always_ff @(negedge clk)
begin
if (rst_n && (int_req_o | ext_req_o) && ack_i)
$display("%t: Entering exception routine.", $time);
end
// synopsys translate_on
`endif
endmodule

View file

@ -77,11 +77,8 @@ module zeroriscy_id_stage
// Stalls
output logic halt_if_o, // controller requests a halt of the IF stage
output logic id_ready_o, // ID stage is ready for the next instruction
input logic ex_ready_i,
output logic id_valid_o, // ID stage is done
// ALU
@ -97,9 +94,14 @@ module zeroriscy_id_stage
output logic [31:0] multdiv_operand_a_ex_o,
output logic [31:0] multdiv_operand_b_ex_o,
// CSR ID
// CSR
output logic csr_access_ex_o,
output logic [1:0] csr_op_ex_o,
output logic [5:0] csr_cause_o,
output logic csr_save_if_o,
output logic csr_save_id_o,
output logic csr_restore_mret_id_o,
output logic csr_save_cause_o,
// Interface to load store unit
output logic data_req_ex_o,
@ -116,15 +118,9 @@ module zeroriscy_id_stage
// Interrupt signals
input logic irq_i,
input logic [4:0] irq_id_i,
input logic irq_enable_i,
input logic m_irq_enable_i,
output logic irq_ack_o,
output logic [5:0] exc_cause_o,
output logic save_exc_cause_o,
output logic exc_save_if_o,
output logic exc_save_id_o,
output logic exc_restore_id_o,
input logic lsu_load_err_i,
input logic lsu_store_err_i,
@ -137,11 +133,11 @@ module zeroriscy_id_stage
output logic dbg_trap_o,
input logic dbg_reg_rreq_i,
input logic [4:0] dbg_reg_raddr_i,
input logic [4:0] dbg_reg_raddr_i,
output logic [31:0] dbg_reg_rdata_o,
input logic dbg_reg_wreq_i,
input logic [4:0] dbg_reg_waddr_i,
input logic [4:0] dbg_reg_waddr_i,
input logic [31:0] dbg_reg_wdata_i,
input logic dbg_jump_req_i,
@ -208,7 +204,9 @@ module zeroriscy_id_stage
// Signals running between controller and exception controller
logic int_req, ext_req, exc_ack; // handshake
logic irq_req_ctrl;
logic [4:0] irq_id_ctrl;
logic exc_ack, exc_kill;// handshake
// Register file interface
logic [4:0] regfile_addr_ra_id;
@ -246,6 +244,7 @@ module zeroriscy_id_stage
// CSR control
logic csr_access;
logic [1:0] csr_op;
logic csr_status;
// Forwarding
logic [1:0] operand_a_fw_mux_sel;
@ -489,6 +488,7 @@ module zeroriscy_id_stage
// CSR control signals
.csr_access_o ( csr_access ),
.csr_op_o ( csr_op ),
.csr_status_o ( csr_status ),
// Data bus interface
.data_req_o ( data_req_id ),
@ -525,9 +525,11 @@ module zeroriscy_id_stage
// decoder related signals
.deassert_we_o ( deassert_we ),
.illegal_insn_i ( illegal_insn_dec | illegal_reg_rv32e ),
.ecall_insn_i ( ecall_insn_dec ),
.mret_insn_i ( mret_insn_dec ),
.pipe_flush_i ( pipe_flush_dec ),
.ebrk_insn_i ( ebrk_insn ),
.csr_status_i ( csr_status ),
// from IF/ID pipeline
.instr_valid_i ( instr_valid_i ),
@ -538,6 +540,8 @@ module zeroriscy_id_stage
// to prefetcher
.pc_set_o ( pc_set_o ),
.pc_mux_o ( pc_mux_o ),
.exc_pc_mux_o ( exc_pc_mux_o ),
.exc_cause_o ( exc_cause_o ),
// LSU
.data_misaligned_i ( data_misaligned_i ),
@ -550,20 +554,31 @@ module zeroriscy_id_stage
.jump_in_id_i ( jump_in_id ),
.instr_multicyle_i ( instr_multicyle ),
// Exception Controller Signals
.int_req_i ( int_req ),
.ext_req_i ( ext_req ),
.exc_ack_o ( exc_ack ),
// Interrupt Controller Signals
.irq_req_ctrl_i ( irq_req_ctrl ),
.irq_id_ctrl_i ( irq_id_ctrl ),
.m_IE_i ( m_irq_enable_i ),
.irq_ack_o ( irq_ack_o ),
.exc_save_if_o ( exc_save_if_o ),
.exc_save_id_o ( exc_save_id_o ),
.exc_restore_id_o ( exc_restore_id_o ),
.exc_ack_o ( exc_ack ),
.exc_kill_o ( exc_kill ),
// CSR Controller Signals
.csr_save_cause_o ( csr_save_cause_o ),
.csr_cause_o ( csr_cause_o ),
.csr_save_if_o ( csr_save_if_o ),
.csr_save_id_o ( csr_save_id_o ),
.csr_restore_mret_id_o ( csr_restore_mret_id_o ),
// Debug Unit Signals
.dbg_req_i ( dbg_req_i ),
.dbg_ack_o ( dbg_ack_o ),
.dbg_stall_i ( dbg_stall_i ),
.dbg_jump_req_i ( dbg_jump_req_i ),
.dbg_settings_i ( dbg_settings_i ),
.dbg_trap_o ( dbg_trap_o ),
// Forwarding signals
.operand_a_fw_mux_sel_o ( operand_a_fw_mux_sel ),
@ -585,47 +600,35 @@ module zeroriscy_id_stage
.perf_ld_stall_o ( perf_ld_stall_o )
);
///////////////////////////////////////////////////////////////////////
// _____ ____ _ _ _ //
// | ____|_ _____ / ___|___ _ __ | |_ _ __ ___ | | | ___ _ __ //
// | _| \ \/ / __| | | / _ \| '_ \| __| '__/ _ \| | |/ _ \ '__| //
// | |___ > < (__ _ | |__| (_) | | | | |_| | | (_) | | | __/ | //
// |_____/_/\_\___(_) \____\___/|_| |_|\__|_| \___/|_|_|\___|_| //
// //
///////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// _____ _ _____ _ _ _ //
// |_ _| | | / __ \ | | | | | //
// | | _ __ | |_ | / \/ ___ _ __ | |_ _ __ ___ | | | ___ _ __ //
// | || '_ \| __| | | / _ \| '_ \| __| '__/ _ \| | |/ _ \ '__| //
// _| || | | | |_ _ | \__/\ (_) | | | | |_| | | (_) | | | __/ | //
// \___/_| |_|\__(_) \____/\___/|_| |_|\__|_| \___/|_|_|\___|_| //
// //
////////////////////////////////////////////////////////////////////////
zeroriscy_exc_controller exc_controller_i
zeroriscy_int_controller int_controller_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.clk ( clk ),
.rst_n ( rst_n ),
// to controller
.int_req_o ( int_req ),
.ext_req_o ( ext_req ),
.ack_i ( exc_ack ),
.ctr_decoding_i ( is_decoding_o ),
.irq_req_ctrl_o ( irq_req_ctrl ),
.irq_id_ctrl_o ( irq_id_ctrl ),
.trap_o ( dbg_trap_o ),
// to IF stage
.pc_mux_o ( exc_pc_mux_o ),
.ctrl_ack_i ( exc_ack ),
.ctrl_kill_i ( exc_kill ),
// Interrupt signals
.irq_i ( irq_i ),
.irq_id_i ( irq_id_i ),
.irq_enable_i ( irq_enable_i ),
.irq_i ( irq_i ),
.irq_id_i ( irq_id_i ),
.ebrk_insn_i ( ebrk_insn ),
.illegal_insn_i ( illegal_insn_dec ),
.ecall_insn_i ( ecall_insn_dec ),
.cause_o ( exc_cause_o ),
.save_cause_o ( save_exc_cause_o ),
.dbg_settings_i ( dbg_settings_i )
.m_IE_i ( m_irq_enable_i )
);
/////////////////////////////////////
// ___ ____ _______ __ //
// |_ _| _ \ | ____\ \/ / //

109
zeroriscy_int_controller.sv Normal file
View file

@ -0,0 +1,109 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 ETH Zurich, University of Bologna //
// All rights reserved. //
// //
// This code is under development and not yet released to the public. //
// Until it is released, the code is under the copyright of ETH Zurich //
// and the University of Bologna, and may contain unpublished work. //
// Any reuse/redistribution should only be under explicit permission. //
// //
// Bug fixes and contributions will eventually be released under the //
// SolderPad open hardware license and under the copyright of ETH Zurich //
// and the University of Bologna. //
// //
// Engineer: Davide Schiavone - pschiavo@iis.ee.ethz.ch //
// //
// Additional contributions by: //
// //
// Design Name: Interrupt Controller //
// Project Name: zero-riscy //
// Language: SystemVerilog //
// //
// Description: Interrupt Controller of the pipelined processor //
// //
////////////////////////////////////////////////////////////////////////////////
import zeroriscy_defines::*;
module zeroriscy_int_controller
(
input logic clk,
input logic rst_n,
// irq_req for controller
output logic irq_req_ctrl_o,
output logic [4:0] irq_id_ctrl_o,
// handshake signals to controller
input logic ctrl_ack_i,
input logic ctrl_kill_i,
// external interrupt lines
input logic irq_i, // level-triggered interrupt inputs
input logic [4:0] irq_id_i, // interrupt id [0,1,....31]
input logic m_IE_i // interrupt enable bit from CSR (M mode)
);
enum logic [1:0] { IDLE, IRQ_PENDING, IRQ_DONE} exc_ctrl_cs, exc_ctrl_ns;
logic irq_enable_ext;
logic [4:0] irq_id_q;
assign irq_enable_ext = m_IE_i;
assign irq_req_ctrl_o = exc_ctrl_cs == IRQ_PENDING;
assign irq_id_ctrl_o = irq_id_q;
always_ff @(posedge clk, negedge rst_n)
begin
if (rst_n == 1'b0) begin
irq_id_q <= '0;
exc_ctrl_cs <= IDLE;
end else begin
unique case (exc_ctrl_cs)
IDLE:
begin
if(irq_enable_ext & irq_i) begin
exc_ctrl_cs <= IRQ_PENDING;
irq_id_q <= irq_id_i;
end
end
IRQ_PENDING:
begin
unique case(1'b1)
ctrl_ack_i:
exc_ctrl_cs <= IRQ_DONE;
ctrl_kill_i:
exc_ctrl_cs <= IDLE;
default:
exc_ctrl_cs <= IRQ_PENDING;
endcase
end
IRQ_DONE:
begin
exc_ctrl_cs <= IDLE;
end
endcase
end
end
`ifndef SYNTHESIS
// synopsys translate_off
// evaluate at falling edge to avoid duplicates during glitches
always_ff @(negedge clk)
begin
if (rst_n && exc_ctrl_cs == IRQ_DONE)
$display("%t: Entering interrupt service routine. [%m]", $time);
end
// synopsys translate_on
`endif
endmodule