CSR regfile implemented, compliant to priv 1.10

This commit is contained in:
Florian Zaruba 2017-05-04 19:31:14 +02:00
parent 6e26afdc2b
commit e683824b2a
2 changed files with 390 additions and 27 deletions

View file

@ -16,6 +16,15 @@ package ariane_pkg;
localparam TRANS_ID_BITS = $clog2(NR_SB_ENTRIES); // depending on the number of scoreboard entries we need that many bits
// to uniquely identify the entry in the scoreboard
localparam NR_WB_PORTS = 2;
localparam ISA_CODE = (1 << 2) // C - Compressed extension
| (1 << 8) // I - RV32I/64I/128I base ISA
| (1 << 12) // M - Integer Multiply/Divide extension
| (0 << 13) // N - User level interrupts supported
| (1 << 18) // S - Supervisor mode implemented
| (1 << 20) // U - User mode implemented
| (0 << 23) // X - Non-standard extensions present
| (2 << 62); // RV64
// ---------------
// Fetch Stage
// ---------------
@ -44,33 +53,40 @@ package ariane_pkg;
// EX Stage
// ---------------
typedef enum logic [7:0] { ADD, SUB, ADDW, SUBW, // basic ALU op
XORL, ORL, ANDL, // logic operations
SRA, SRL, SLL, SRLW, SLLW, SRAW, // shifts
LTS, LTU, LES, LEU, GTS, GTU, GES, GEU, EQ, NE, // comparisons
SLTS, SLTU, SLETS, SLETU, // set lower than operations
MRET, SRET, URET, ECALL, WRITE, READ, SET, CLEAR, // CSR functions
LD, SD, LW, LWU, SW, LH, LHU, SH, LB, SB, LBU, SBU // LSU functions
} fu_op;
typedef enum logic [7:0] { // basic ALU op
ADD, SUB, ADDW, SUBW,
// logic operations
XORL, ORL, ANDL,
// shifts
SRA, SRL, SLL, SRLW, SLLW, SRAW,
// comparisons
LTS, LTU, LES, LEU, GTS, GTU, GES, GEU, EQ, NE,
// set lower than operations
SLTS, SLTU, SLETS, SLETU,
// CSR functions
MRET, SRET, URET, ECALL, CSR_WRITE, CSR_READ, CSR_SET, CSR_CLEAR,
// LSU functions
LD, SD, LW, LWU, SW, LH, LHU, SH, LB, SB, LBU, SBU
} fu_op;
// ---------------
// ID/EX/WB Stage
// ---------------
typedef struct packed {
logic [TRANS_ID_BITS-1:0] trans_id; // this can potentially be simplified, we could index the scoreboard entry
// with the transaction id in any case make the width more generic
fu_t fu; // functional unit to use
fu_op op; // operation to perform in each functional unit
logic [4:0] rs1; // register source address 1
logic [4:0] rs2; // register source address 2
logic [4:0] rd; // register destination address
logic [63:0] result; // for unfinished instructions this field also holds the immediate
logic valid; // is the result valid
logic use_imm; // should we use the immediate as operand b?
logic use_pc; // set if we need to use the PC as operand A, PC from exception
exception ex; // exception has occurred
logic is_compressed; // signals a compressed instructions, we need this information at the commit stage if
// we want jump accordingly e.g.: +4, +2
logic [TRANS_ID_BITS-1:0] trans_id; // this can potentially be simplified, we could index the scoreboard entry
// with the transaction id in any case make the width more generic
fu_t fu; // functional unit to use
fu_op op; // operation to perform in each functional unit
logic [4:0] rs1; // register source address 1
logic [4:0] rs2; // register source address 2
logic [4:0] rd; // register destination address
logic [63:0] result; // for unfinished instructions this field also holds the immediate
logic valid; // is the result valid
logic use_imm; // should we use the immediate as operand b?
logic use_pc; // set if we need to use the PC as operand A, PC from exception
exception ex; // exception has occurred
logic is_compressed; // signals a compressed instructions, we need this information at the commit stage if
// we want jump accordingly e.g.: +4, +2
} scoreboard_entry;
// --------------------
@ -144,7 +160,6 @@ package ariane_pkg;
// --------------------
typedef enum logic[1:0] {
PRIV_LVL_M = 2'b11,
// PRIV_LVL_H = 2'b10, This mode does not longer exist
PRIV_LVL_S = 2'b01,
PRIV_LVL_U = 2'b00
} priv_lvl_t;
@ -181,4 +196,47 @@ package ariane_pkg;
localparam ENV_CALL_UMODE = 64'h8;
localparam ENV_CALL_SMODE = 64'h9;
localparam ENV_CALL_MMODE = 64'hB;
typedef enum logic [11:0] {
CSR_SSTATUS = 12'h100,
CSR_SIE = 12'h104,
CSR_STVEC = 12'h105,
CSR_SSCRATCH = 12'h140,
CSR_SEPC = 12'h141,
CSR_SCAUSE = 12'h142,
CSR_STVAL = 12'h143,
CSR_SIP = 12'h144,
CSR_SATP = 12'h180,
CSR_MSTATUS = 12'h300,
CSR_MISA = 12'h301,
CSR_MEDELEG = 12'h302,
CSR_MIDELEG = 12'h303,
CSR_MIE = 12'h304,
CSR_MTVEC = 12'h305,
CSR_MSCRATCH = 12'h340,
CSR_MEPC = 12'h341,
CSR_MCAUSE = 12'h342,
CSR_MTVAL = 12'h343,
CSR_MIP = 12'h344,
CSR_MVENDORID = 12'hF11,
CSR_MARCHID = 12'hF12,
CSR_MIMPID = 12'hF13,
CSR_MHARTID = 12'hF14
} csr_reg_t;
// decoded csr address
typedef struct packed {
logic [1:0] rw;
priv_lvl_t priv_lvl;
logic [7:0] address;
} csr_addr_t;
`ifndef VERILATOR
typedef union packed {
csr_reg_t address;
csr_addr_t csr_decode;
} csr_t;
`endif
endpackage

View file

@ -17,10 +17,315 @@
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
// University of Bologna.
//
module csr_regfile (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
output priv_lvl_t priv_lvl_o
import ariane_pkg::*;
module csr_regfile #(
parameter int ASID_WIDTH = 1
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
// Core and Cluster ID
input logic [3:0] core_id_i,
input logic [5:0] cluster_id_i,
input logic [63:0] boot_addr_i,
// we are taking an exception
input exception ex_i,
input fu_op [1:0] csr_op_i,
input logic [11:0] csr_addr_i,
input logic [63:0] csr_wdata_i,
output logic [63:0] csr_rdata_o,
input logic [63:0] pc_i, // PC of instruction accessing the CSR
output exception csr_exception_o, // attempts to access a CSR without appropriate privilege
// level or to write a read-only register also
// raises illegal instruction exceptions.
// Interrupts/Exceptions
output logic [3:0] irq_enable_o,
output logic [31:0] epc_o,
output logic [31:0] trap_vector_base_o,
output priv_lvl_t priv_lvl_o,
input logic [63:0] badaddr_i,
input logic [63:0] exc_cause_i,
input logic save_exc_cause_i,
// MMU
output logic enable_translation_o,
output logic flag_pum_o,
output logic flag_mxr_o,
// input logic flag_mprv_i,
output logic [37:0] pd_ppn_o,
output logic [ASID_WIDTH-1:0] asid_o
// Performance Counter
);
csr_t csr_addr;
assign csr_addr = csr_t'(csr_addr_i);
// internal signal to keep track of access exceptions
logic read_access_exception, update_access_exception;
logic csr_we;
logic [63:0] csr_wdata, csr_rdata;
// ----------------
// CSR Registers
// ----------------
// privilege level register
priv_lvl_t priv_lvl_n, priv_lvl_q, prev_priv_lvl_n, prev_priv_lvl_q;
typedef struct packed {
logic sd; // signal dirty - read-only - hardwired zero
logic [62:36] wpri4;
logic [1:0] sxl; // variable supervisor mode xlen - hardwired to zero
logic [1:0] uxl; // variable user mode xlen - hardwired to zero
logic [8:0] wpri3;
logic tsr; // trap sret
logic tw; // time wait
logic tvm; // trap virtual memory
logic mxr; // make executable readable
logic sum; // permit supervisor user memory access
logic mprv; // modify privilege - privilege level for ld/st
logic [1:0] xs; // extension register - hardwired to zero
logic [1:0] fs; // extension register - hardwired to zero
priv_lvl_t mpp; // holds the previous privilege mode up to machine
logic [1:0] wpri2; // writes preserved reads ignored
logic spp; // holds the previous privilege mode up to supervisor
logic mpie; // machine interrupts enable bit active prior to trap
logic wpri1; // writes preserved reads ignored
logic spie; // supervisor interrupts enable bit active prior to trap
logic upie; // user interrupts enable bit active prior to trap - hardwired to zero
logic mie; // machine interrupts enable
logic wpri0; // writes preserved reads ignored
logic sie; // supervisor interrupts enable
logic uie; // user interrupts enable - hardwired to zero
} status_t;
status_t mstatus_q, mstatus_n;
logic [63:0] mtvec_q, mtvec_n;
logic [63:0] medeleg_q, medeleg_n;
logic [63:0] mideleg_q, mideleg_n;
logic [63:0] mip_q, mip_n;
logic [63:0] mie_q, mie_n;
logic [63:0] mscratch_q, mscratch_n;
logic [63:0] mepc_q, mepc_n;
logic [63:0] mcause_q, mcause_n;
logic [63:0] mtval_q, mtval_n;
logic [63:0] stvec_q, stvec_n;
logic [63:0] sscratch_q, sscratch_n;
logic [63:0] sepc_q, sepc_n;
logic [63:0] scause_q, scause_n;
logic [63:0] stval_q, stval_n;
typedef struct packed {
logic [3:0] mode;
logic [15:0] asid;
logic [43:0] ppn;
} sapt_t;
sapt_t satp_q, satp_n;
// ----------------
// CSR Read logic
// ----------------
always_comb begin : csr_read
// a read access exception can only occur if we attempt to read a CSR which does not exist
read_access_exception = 1'b0;
csr_rdata = 64'b0;
case (csr_addr.address)
CSR_SSTATUS: csr_rdata = mstatus_q & 64'h3fffe1fee;
CSR_SIE: csr_rdata = mie_q & mideleg_q;
CSR_SIP: csr_rdata = mip_q & mideleg_q;
CSR_STVEC: csr_rdata = stvec_q;
CSR_SSCRATCH: csr_rdata = sscratch_q;
CSR_SEPC: csr_rdata = sepc_q;
CSR_SCAUSE: csr_rdata = scause_q;
CSR_STVAL: csr_rdata = stval_q;
CSR_SATP: csr_rdata = satp_q;
CSR_MSTATUS: csr_rdata = mstatus_q;
CSR_MISA: csr_rdata = ISA_CODE;
CSR_MEDELEG: csr_rdata = medeleg_q;
CSR_MIDELEG: csr_rdata = mideleg_q;
CSR_MIP: csr_rdata = mip_q;
CSR_MIE: csr_rdata = mie_q;
CSR_MTVEC: csr_rdata = mtvec_q;
CSR_MSCRATCH: csr_rdata = mscratch_q;
CSR_MEPC: csr_rdata = mepc_q;
CSR_MCAUSE: csr_rdata = mcause_q;
CSR_MTVAL: csr_rdata = mtval_q;
CSR_MVENDORID: csr_rdata = 63'b0; // not implemented
CSR_MARCHID: csr_rdata = 63'b0; // PULP, anonymous source (no allocated ID yet)
CSR_MIMPID: csr_rdata = 63'b0;
CSR_MHARTID: csr_rdata = {53'b0, cluster_id_i[5:0], 1'b0, core_id_i[3:0]};
default: read_access_exception = 1'b1;
endcase
end
// ---------------------------
// CSR Write and update logic
// ---------------------------
always_comb begin : csr_update
update_access_exception = 1'b0;
mstatus_n = mstatus_q;
mtvec_n = mtvec_q;
medeleg_n = medeleg_q;
mideleg_n = mideleg_q;
mip_n = mip_q;
mie_n = mie_q;
mepc_n = mepc_q;
mcause_n = mcause_q;
mscratch_n = mscratch_q;
mtval_n = mtval_q;
sepc_n = sepc_q;
scause_n = scause_q;
stvec_n = stvec_q;
sscratch_n = sscratch_q;
stval_n = stval_q;
// check for correct access rights and that we are writing
if ((priv_lvl_q && csr_addr.csr_decode.priv_lvl) == csr_addr.csr_decode.priv_lvl && csr_we) begin
case (csr_addr.address)
// sstatus is a subset of mstatus - mask it accordingly
CSR_SSTATUS: mstatus_n = csr_wdata & 64'h3fffe1fee;
// even machine mode interrupts can be visible and set-able to supervisor
// if the corresponding bit in mideleg is set
CSR_SIE: mie_n = csr_wdata & (~64'h111) & mideleg_q;
CSR_SIP: mip_n = csr_wdata & (~64'h111) & mideleg_q;
CSR_STVEC: stvec_n = {csr_wdata[63:2], 1'b0, csr_wdata[0]};
CSR_SSCRATCH: sscratch_n = csr_wdata;
CSR_SEPC: sepc_n = csr_wdata_i[63:1];
CSR_SCAUSE: scause_n = csr_wdata_i;
CSR_STVAL: stval_n = csr_wdata_i;
// supervisor address translation and protection
CSR_SATP: satp_n = sapt_t'(csr_wdata_i);
CSR_MSTATUS: begin
mstatus_n = csr_wdata;
// hardwired zero register
mstatus_n.sd = 1'b0;
mstatus.xs = 2'b0;
mstatus.fs = 2'b0;
mstatus.upie = 1'b0;
mstatus.uie = 1'b0;
end
// machine exception delegation register
// 0 - 12 exceptions supported
CSR_MEDELEG: medeleg_n = csr_wdata & (~64'hBFF);
// machine interrupt delegation register
// we do not support user interrupt delegation
CSR_MIDELEG: mideleg_n = csr_wdata & (~64'hAAA);
// mask the register so that user interrupts can never be set
CSR_MIE: mie_n = csr_wdata & (~64'h111);
CSR_MIP: mip_n = csr_wdata & (~64'h111);
CSR_MTVEC: mtvec_n = {csr_wdata[63:2], 1'b0, csr_wdata[0]};
CSR_MSCRATCH: mscratch_n = csr_wdata_i;
CSR_MEPC: mepc_n = csr_wdata_i[63:1];
CSR_MCAUSE: mcause_n = csr_wdata_i;
CSR_MTVAL: mtval_n = csr_wdata_i;
default: update_access_exception = 1'b1;
endcase
end else begin
update_access_exception = 1'b1;
end
// we got an exception update cause, pc and stval register
if (ex_i.valid) begin
// TODO
// set cause
// set epc
// set mtval or stval
end
end
// ---------------------------
// CSR Op Select Logic
// ---------------------------
always_comb begin : csr_op_logic
csr_wdata = csr_wdata_i;
csr_we = 1'b1;
unique case (csr_op_i)
CSR_WRITE: csr_wdata = csr_wdata_i;
CSR_SET: csr_wdata = csr_wdata_i | csr_rdata;
CSR_CLEAR: csr_wdata = (~csr_wdata_i) & csr_rdata;
default: csr_we = 1'b0;
endcase
end
// -------------------
// Exception Control
// -------------------
always_comb begin : exception_ctrl
csr_exception_o = {
64'b0, 64'b0, 1'b0
};
// we got an exception in one of the processes above
// throw an illegal instruction exception
if (update_access_exception || read_access_exception) begin
csr_exception_o = {
pc_i, ILLEGAL_INSTR, 1'b1
};
end
end
// -------------------
// Output Assignments
// -------------------
assign csr_rdata_o = csr_rdata;
assign priv_lvl_o = priv_lvl_q;
assign pd_ppn_o = satp_q.ppn;
assign asid_o = satp_q.asid;
// output assignments dependent on privilege mode
always_comb begin : priv_output
trap_vector_base_o = mtvec_q;
// output user mode stvec
if (priv_lvl_q == PRIV_LVL_S) begin
trap_vector_base_o = stvec_q;
end
end
// sequential process
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
priv_lvl_q <= PRIV_LVL_M;
prev_priv_lvl_q <= PRIV_LVL_M;
mstatus_q <= 64'b0;
mtvec_q <= {boot_addr_i[63:2], 2'b0}; // set to boot address + direct mode
medeleg_q <= 64'b0;
mideleg_q <= 64'b0;
mepc_q <= 64'b0;
mcause_q <= 64'b0;
mscratch_q <= 64'b0;
mtval_q <= 64'b0;
sepc_q <= 64'b0;
scause_q <= 64'b0;
stvec_q <= 64'b0;
sscratch_q <= 64'b0;
stval_q <= 64'b0;
end else begin
priv_lvl_q <= priv_lvl_n;
prev_priv_lvl_q <= prev_priv_lvl_n;
mstatus_q <= mstatus_n;
mtvec_q <= mtvec_n;
medeleg_q <= medeleg_n;
mideleg_q <= mideleg_n;
mip_q <= mip_n;
mie_q <= mie_n;
mepc_q <= mepc_n;
mcause_q <= mcause_n;
mscratch_q <= mscratch_n;
mtval_q <= mtval_n;
sepc_q <= sepc_n;
scause_q <= scause_n;
stvec_q <= stvec_n;
sscratch_q <= sscratch_n;
stval_q <= stval_n;
end
end
endmodule