[WIP] Implement exception handling

This commit is contained in:
Florian Zaruba 2017-05-31 23:17:07 +02:00
parent 00b11efc6f
commit 4d7b9a1b75
8 changed files with 121 additions and 49 deletions

View file

@ -223,9 +223,9 @@ package ariane_pkg;
localparam LD_ACCESS_FAULT = 64'h5;
localparam ST_ADDR_MISALIGNED = 64'h6;
localparam ST_ACCESS_FAULT = 64'h7;
localparam ENV_CALL_UMODE = 64'h8;
localparam ENV_CALL_SMODE = 64'h9;
localparam ENV_CALL_MMODE = 64'hB;
localparam ENV_CALL_UMODE = 64'h8; // environment call from user mode
localparam ENV_CALL_SMODE = 64'h9; // environment call from supvervisor mode
localparam ENV_CALL_MMODE = 64'hB; // environment call from machine mode
typedef enum logic [11:0] {
CSR_SSTATUS = 12'h100,

View file

@ -205,6 +205,9 @@ module ariane
logic flush_unissued_instr_ctrl_id;
logic flush_scoreboard_ctrl_id;
logic flush_ctrl_if;
logic flush_ctrl_id;
logic flush_controller_ex;
// TODO: Preliminary signal assignments
logic flush_tlb;
@ -271,6 +274,7 @@ module ariane
.decoded_instr_ack_o ( decode_ack_id_if ),
.ex_if_i ( exception_if_id ), // exception from if
.ready_o ( ready_id_if ),
.priv_lvl_i ( priv_lvl ),
// Functional Units
.operator_o ( operator_id_ex ),
.operand_a_o ( operand_a_id_ex ),
@ -424,19 +428,15 @@ module ariane
// ------------
// Controller
// ------------
logic flush_commit_i;
logic flush_controller_ex;
controller controller_i (
.flush_bp_o ( ),
.flush_scoreboard_o ( flush_scoreboard_ctrl_id ),
.flush_unissued_instr_o ( flush_unissued_instr_ctrl_id ),
.flush_if_o ( flush_ctrl_if ),
.flush_id_o ( ),
.flush_id_o ( flush_ctrl_id ),
.flush_ex_o ( flush_controller_ex ),
.flush_ready_lsu_i ( ),
.flush_commit_i ( flush_commit_i ),
.ex_i ( ex_commit ),
.flush_csr_i ( flush_csr_ctrl ),
.resolved_branch_i ( resolved_branch ),
.*
@ -449,23 +449,23 @@ module ariane
instruction_tracer_if tracer_if (clk_i);
// assign instruction tracer interface
// control signals
assign tracer_if.rstn = rst_ni;
assign tracer_if.rstn = rst_ni;
assign tracer_if.flush_unissued = flush_unissued_instr_ctrl_id;
assign tracer_if.flush = flush_controller_ex;
// fetch
assign tracer_if.fetch = fetch_entry_if_id;
assign tracer_if.fetch_valid = fetch_valid_if_id;
assign tracer_if.fetch_ack = decode_ack_id_if;
assign tracer_if.fetch = fetch_entry_if_id;
assign tracer_if.fetch_valid = fetch_valid_if_id;
assign tracer_if.fetch_ack = decode_ack_id_if;
// Issue
assign tracer_if.issue_ack = id_stage_i.scoreboard_i.issue_ack_i;
assign tracer_if.issue_sbe = id_stage_i.scoreboard_i.issue_instr_o;
assign tracer_if.issue_ack = id_stage_i.scoreboard_i.issue_ack_i;
assign tracer_if.issue_sbe = id_stage_i.scoreboard_i.issue_instr_o;
// write-back
assign tracer_if.waddr = waddr_a_commit_id;
assign tracer_if.wdata = wdata_a_commit_id;
assign tracer_if.we = we_a_commit_id;
assign tracer_if.waddr = waddr_a_commit_id;
assign tracer_if.wdata = wdata_a_commit_id;
assign tracer_if.we = we_a_commit_id;
// commit
assign tracer_if.commit_instr = commit_instr_id_commit;
assign tracer_if.commit_ack = commit_ack_commit_id;
assign tracer_if.commit_instr = commit_instr_id_commit;
assign tracer_if.commit_ack = commit_ack_commit_id;
program instr_tracer (instruction_tracer_if tracer_if);
instruction_tracer it = new (tracer_if);

View file

@ -19,8 +19,8 @@
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
output exception exception_o, // take exception to controller
@ -39,9 +39,9 @@ module commit_stage (
output logic [63:0] csr_wdata_o,
input logic [63:0] csr_rdata_i,
input exception csr_exception_i,
// to ex
output logic commit_lsu_o,
output logic commit_csr_o,
// commit signals to ex
output logic commit_lsu_o, // commit the pending store
output logic commit_csr_o, // commit the pending CSR instruction
// general control signal
input logic [4:0] irq_enable_i
);

View file

@ -23,30 +23,61 @@ module controller (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
output logic flush_bp_o, // flush branch prediction data structures
output logic flush_unissued_instr_o,
output logic flush_scoreboard_o,
output logic flush_if_o,
output logic flush_id_o,
output logic flush_ex_o,
output logic flush_bp_o, // flush branch prediction data structures
output logic flush_if_o, // flush the IF stage
output logic flush_unissued_instr_o, // flush un-issued instructions of the scoreboard
output logic flush_scoreboard_o, // flush the whole scoreboard
output logic flush_id_o, // flush ID stage
output logic flush_ex_o, // flush EX stage
input logic flush_ready_lsu_i, // we need to wait for this signal from LSU
input logic flush_commit_i, // flush request from commit stage in
input logic flush_csr_i,
input branchpredict resolved_branch_i
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
input logic flush_csr_i // we got an instruction which altered the CSR, flush the pipeline
);
// flush branch prediction
assign flush_bp_o = 1'b0;
// ------------
// Flush CTRL
// ------------
always_comb begin : flush_ctrl
flush_if_o = 1'b0;
flush_unissued_instr_o = 1'b0;
flush_scoreboard_o = 1'b0;
flush_if_o = 1'b0;
flush_id_o = 1'b0;
flush_ex_o = 1'b0;
// ------------
// Mis-predict
// ------------
// flush on mispredict
if (resolved_branch_i.is_mispredict) begin
// flush only un-issued instructions
flush_unissued_instr_o = 1'b1;
// and if stage
flush_if_o = 1'b1;
end
// ------------
// Exception
// ------------
if (ex_i.valid) begin
flush_if_o = 1'b1;
flush_scoreboard_o = 1'b1;
flush_id_o = 1'b1;
flush_ex_o = 1'b1;
end
// ---------------------------------
// CSR instruction with side-effect
// ---------------------------------
if (flush_csr_i) begin
flush_if_o = 1'b1;
flush_scoreboard_o = 1'b1;
flush_id_o = 1'b1;
flush_ex_o = 1'b1;
end
end
// flush on exception
endmodule

View file

@ -165,6 +165,7 @@ module csr_regfile #(
// CSR Write and update logic
// ---------------------------
always_comb begin : csr_update
flush_o = 1'b0;
update_access_exception = 1'b0;
priv_lvl_n = priv_lvl_q;
@ -233,6 +234,8 @@ module csr_regfile #(
CSR_MTVAL: mtval_n = csr_wdata;
default: update_access_exception = 1'b1;
endcase
// TODO: this is unnecessary
flush_o = 1'b1;
end else begin
update_access_exception = 1'b1;
end

View file

@ -18,10 +18,15 @@ module decoder (
input logic [31:0] instruction_i, // instruction from IF
input branchpredict_sbe branch_predict_i,
input exception ex_i, // if an exception occured in if
input priv_lvl_t priv_lvl_i, // current privilege level
output scoreboard_entry instruction_o, // scoreboard entry to scoreboard
output logic is_control_flow_instr_o // this instruction will change the control flow
);
logic illegal_instr;
// this instruction is an environment call (ecall), it is handled like an exception
logic ecall;
// this instruction is a software break-point
logic ebreak;
instruction instr;
assign instr = instruction'(instruction_i);
// --------------------
@ -60,6 +65,8 @@ module decoder (
instruction_o.is_compressed = is_compressed_i;
instruction_o.use_zimm = 1'b0;
instruction_o.bp = branch_predict_i;
ecall = 1'b0;
ebreak = 1'b0;
if (~ex_i.valid) begin
case (instr.rtype.opcode)
@ -70,10 +77,32 @@ module decoder (
unique case (instr.itype.funct3)
3'b000: begin
// TODO:
// ECALL, EBREAK, SFEBCE.VM
// MRET/SRET/URET, WFI
illegal_instr = 1'b1;
case (instr.itype.imm)
// ECALL
12'b0: ecall = 1'b1;
// EBREAK:
12'b1: ebreak = 1'b1;
// URET
// 12'b10: ;
// SRET
// 12'b100000010:;
// MRET
// 12'b1100000010:;
// WFI
// 12'b1_0000_0101:;
// SFENCE.VMA
default: begin
// if (instr.itype.imm[11:5] == 7'b1001) begin
//
// end else begin
illegal_instr = 1'b1;
// end
end
endcase
end
// atomically swaps values in the CSR and integer register
3'b001: begin// CSRRW
@ -408,15 +437,24 @@ module decoder (
instruction_o.valid = 1'b0;
// look if we didn't already get an exception in any previous
// stage - we should not overwrite it as we retain order regarding the exception
if (~ex_i.valid && illegal_instr) begin
if (~ex_i.valid) begin
// instructions which will throw an exception are marked as valid
// e.g.: they can be committed anytime and do not need to wait for any functional unit
instruction_o.valid = 1'b1;
instruction_o.ex.valid = 1'b1;
// we decoded an illegal exception here
instruction_o.ex.cause = ILLEGAL_INSTR;
// if we decoded an illegal instruction save the faulting instruction to tval
instruction_o.ex.tval = instruction_i;
if (illegal_instr) begin
instruction_o.valid = 1'b1;
instruction_o.ex.valid = 1'b1;
// we decoded an illegal exception here
instruction_o.ex.cause = ILLEGAL_INSTR;
// if we decoded an illegal instruction save the faulting instruction to tval
instruction_o.ex.tval = instruction_i;
// we got an ecall, set the correct cause depending on the current privilege level
end else if (ecall) begin
case (priv_lvl_i) begin
endcase
end else if (ebreak) begin
end
end
end
endmodule

View file

@ -35,6 +35,8 @@ module id_stage #(
input logic fetch_entry_valid_i,
output logic decoded_instr_ack_o,
input exception ex_if_i, // we already got an exception in IF
// from CSR file
input priv_lvl_t priv_lvl_i, // current privilege level
output logic ready_o, // id is ready
output fu_op operator_o,

View file

@ -21,5 +21,3 @@ add wave -noupdate -group ex_stage /core_tb/dut/ex_stage_i/*
add wave -noupdate -group commit_stage /core_tb/dut/commit_stage_i/*
add wave -noupdate -group csr_file /core_tb/dut/csr_regfile_i/*
add wave -noupdate -group controller /core_tb/dut/controller_i/*
TreeUpdate [SetDefaultTree]