integrating ITLB & PTW
This commit is contained in:
parent
7130edac8d
commit
e96430d862
@ -128,6 +128,7 @@ object Constants
|
||||
val M_FRD = Bits("b0010", 4); // fp load
|
||||
val M_FWR = Bits("b0011", 4); // fp store
|
||||
val M_FLA = Bits("b0100", 4); // flush cache
|
||||
val M_PRD = Bits("b0101", 4); // PTW load
|
||||
val M_XA_ADD = Bits("b1000", 4);
|
||||
val M_XA_SWAP = Bits("b1001", 4);
|
||||
val M_XA_AND = Bits("b1010", 4);
|
||||
@ -145,12 +146,26 @@ object Constants
|
||||
val PCR_COMPARE = UFix( 5, 5);
|
||||
val PCR_CAUSE = UFix( 6, 5);
|
||||
val PCR_MEMSIZE = UFix( 8, 5);
|
||||
val PCR_PTBR = UFix( 9, 5);
|
||||
val PCR_LOG = UFix(10, 5);
|
||||
val PCR_TOHOST = UFix(16, 5);
|
||||
val PCR_FROMHOST = UFix(17, 5);
|
||||
val PCR_CONSOLE = UFix(18, 5);
|
||||
val PCR_K0 = UFix(24, 5);
|
||||
val PCR_K1 = UFix(25, 5);
|
||||
|
||||
val PADDR_BITS = 40;
|
||||
val VADDR_BITS = 43;
|
||||
val PGIDX_BITS = 13;
|
||||
val PPN_BITS = PADDR_BITS-PGIDX_BITS;
|
||||
val VPN_BITS = VADDR_BITS-PGIDX_BITS;
|
||||
val ASID_BITS = 7;
|
||||
val PERM_BITS = 6;
|
||||
|
||||
val ITLB_ENTRIES = 8;
|
||||
|
||||
val HAVE_FPU = Bool(false);
|
||||
val HAVE_VEC = Bool(false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package Top {
|
||||
|
||||
import Chisel._
|
||||
import Chisel._;
|
||||
import Node._;
|
||||
import Constants._;
|
||||
|
||||
@ -41,21 +41,60 @@ class ioRocket extends Bundle()
|
||||
class rocketProc extends Component
|
||||
{
|
||||
val io = new ioRocket();
|
||||
|
||||
|
||||
val ctrl = new rocketCtrl();
|
||||
val dpath = new rocketDpath();
|
||||
|
||||
val itlb = new rocketITLB(ITLB_ENTRIES);
|
||||
val ptw = new rocketPTW();
|
||||
val arb = new rocketDmemArbiter();
|
||||
|
||||
ctrl.io.dpath <> dpath.io.ctrl;
|
||||
ctrl.io.dmem ^^ io.dmem;
|
||||
// ctrl.io.dmem ^^ io.dmem;
|
||||
ctrl.io.host.start ^^ io.host.start;
|
||||
ctrl.io.imem ^^ io.imem;
|
||||
// ctrl.io.imem ^^ io.imem;
|
||||
|
||||
dpath.io.dmem ^^ io.dmem;
|
||||
dpath.io.imem.req_addr ^^ io.imem.req_addr;
|
||||
// dpath.io.dmem ^^ io.dmem;
|
||||
// dpath.io.imem.req_addr ^^ io.imem.req_addr;
|
||||
dpath.io.imem.resp_data ^^ io.imem.resp_data;
|
||||
dpath.io.host ^^ io.host;
|
||||
dpath.io.debug ^^ io.debug;
|
||||
|
||||
itlb.io.cpu.invalidate := Bool(false);
|
||||
itlb.io.cpu.status := dpath.io.ctrl.status;
|
||||
itlb.io.cpu.req_val := ctrl.io.imem.req_val;
|
||||
ctrl.io.imem.req_rdy := itlb.io.cpu.req_rdy && io.imem.req_rdy;
|
||||
|
||||
itlb.io.cpu.req_asid := Bits(0,ASID_BITS); // FIXME: connect to PCR
|
||||
itlb.io.cpu.req_vpn := dpath.io.imem.req_addr(VADDR_BITS-1,PGIDX_BITS);
|
||||
|
||||
io.imem.req_val := itlb.io.cpu.resp_val;
|
||||
io.imem.req_addr := Cat(itlb.io.cpu.resp_ppn, dpath.io.imem.req_addr(PGIDX_BITS-1,0)).toUFix;
|
||||
|
||||
ctrl.io.imem.resp_val := io.imem.resp_val;
|
||||
dpath.io.itlb_xcpt := itlb.io.cpu.exception;
|
||||
|
||||
ptw.io.itlb <> itlb.io.ptw;
|
||||
ptw.io.ptbr := dpath.io.ptbr;
|
||||
|
||||
arb.io.ptw <> ptw.io.dmem;
|
||||
arb.io.mem ^^ io.dmem
|
||||
|
||||
arb.io.cpu.req_val := ctrl.io.dmem.req_val;
|
||||
arb.io.cpu.req_cmd := ctrl.io.dmem.req_cmd;
|
||||
arb.io.cpu.req_type := ctrl.io.dmem.req_type;
|
||||
arb.io.cpu.req_addr := dpath.io.dmem.req_addr;
|
||||
arb.io.cpu.req_data := dpath.io.dmem.req_data;
|
||||
arb.io.cpu.req_tag := dpath.io.dmem.req_tag;
|
||||
|
||||
ctrl.io.dmem.req_rdy := arb.io.cpu.req_rdy;
|
||||
ctrl.io.dmem.resp_miss := arb.io.cpu.resp_miss;
|
||||
ctrl.io.dmem.resp_val := arb.io.cpu.resp_val;
|
||||
|
||||
dpath.io.dmem.resp_val := arb.io.cpu.resp_val;
|
||||
dpath.io.dmem.resp_tag := arb.io.cpu.resp_tag;
|
||||
dpath.io.dmem.resp_data := arb.io.cpu.resp_data;
|
||||
|
||||
// FIXME: console disconnected
|
||||
// io.console.bits := dpath.io.dpath.rs1(7,0);
|
||||
io.console.bits := Bits(0,8);
|
||||
|
@ -53,7 +53,7 @@ class ioCtrlDpath extends Bundle()
|
||||
val mem_waddr = UFix(5,'input); // write addr from memory stage
|
||||
val wb_waddr = UFix(5,'input); // write addr from writeback stage
|
||||
val exception = Bool('input);
|
||||
val status = Bits(8, 'input);
|
||||
val status = Bits(17, 'input);
|
||||
val sboard_clr0 = Bool('input);
|
||||
val sboard_clr0a = UFix(5, 'input);
|
||||
val sboard_clr1 = Bool('input);
|
||||
@ -67,6 +67,7 @@ class ioCtrlAll extends Bundle()
|
||||
val imem = new ioImem(List("req_val", "req_rdy", "resp_val")).flip();
|
||||
val dmem = new ioDmem(List("req_val", "req_rdy", "req_cmd", "req_type", "resp_miss", "resp_val")).flip();
|
||||
val host = new ioHost(List("start"));
|
||||
// val itlb_xcpt = Bool('input);
|
||||
}
|
||||
|
||||
class rocketCtrl extends Component
|
||||
|
@ -5,24 +5,24 @@ import Node._;
|
||||
import Constants._;
|
||||
import scala.math._;
|
||||
|
||||
// interface between D$ and processor
|
||||
// interface between D$ and processor pipeline
|
||||
class ioDmem(view: List[String] = null) extends Bundle(view) {
|
||||
val req_val = Bool('input);
|
||||
val req_rdy = Bool('output);
|
||||
val req_cmd = Bits(4, 'input);
|
||||
val req_type = Bits(3, 'input);
|
||||
val req_addr = UFix(32, 'input);
|
||||
val req_addr = UFix(PADDR_BITS, 'input);
|
||||
val req_data = Bits(64, 'input);
|
||||
val req_tag = Bits(5, 'input);
|
||||
val resp_miss = Bool('output);
|
||||
val resp_val = Bool('output);
|
||||
val resp_data = Bits(64, 'output);
|
||||
val resp_tag = Bits(12, 'output);
|
||||
val resp_tag = Bits(13, 'output);
|
||||
}
|
||||
|
||||
// interface between D$ and memory
|
||||
// interface between D$ and next level in memory hierarchy
|
||||
class ioDcache(view: List[String] = null) extends Bundle(view) {
|
||||
val req_addr = UFix(32, 'input);
|
||||
val req_addr = UFix(PADDR_BITS, 'input);
|
||||
val req_tag = UFix(3, 'input);
|
||||
val req_val = Bool('input);
|
||||
val req_rdy = Bool('output);
|
||||
@ -39,10 +39,11 @@ class ioDCacheDM extends Bundle() {
|
||||
}
|
||||
|
||||
// state machine to flush (write back dirty lines, invalidate clean ones) the D$
|
||||
class rocketDCacheDM_flush(lines: Int, addrbits: Int) extends Component {
|
||||
class rocketDCacheDM_flush(lines: Int) extends Component {
|
||||
val io = new ioDCacheDM();
|
||||
val dcache = new rocketDCacheDM(lines, addrbits);
|
||||
val dcache = new rocketDCacheDM(lines);
|
||||
|
||||
val addrbits = PADDR_BITS;
|
||||
val indexbits = ceil(log10(lines)/log10(2)).toInt;
|
||||
val offsetbits = 6;
|
||||
val tagmsb = addrbits - 1;
|
||||
@ -65,18 +66,22 @@ class rocketDCacheDM_flush(lines: Int, addrbits: Int) extends Component {
|
||||
flush_waiting <== Bool(true);
|
||||
}
|
||||
|
||||
when (dcache.io.cpu.req_rdy &&
|
||||
(flush_count === ~Bits(0, indexbits))) { flushing <== Bool(false); }
|
||||
when (dcache.io.cpu.resp_val &&
|
||||
(dcache.io.cpu.resp_tag === r_cpu_req_tag) &&
|
||||
(flush_resp_count === ~Bits(0, indexbits))) { flush_waiting <== Bool(false); }
|
||||
when (dcache.io.cpu.req_rdy && (flush_count === ~Bits(0, indexbits))) {
|
||||
flushing <== Bool(false);
|
||||
}
|
||||
when (dcache.io.cpu.resp_val && (dcache.io.cpu.resp_tag === r_cpu_req_tag) && (flush_resp_count === ~Bits(0, indexbits))) {
|
||||
flush_waiting <== Bool(false);
|
||||
}
|
||||
|
||||
when (flushing && dcache.io.cpu.req_rdy) { flush_count <== flush_count + UFix(1,1); }
|
||||
when (flush_waiting && dcache.io.cpu.resp_val && (dcache.io.cpu.resp_tag === r_cpu_req_tag))
|
||||
{ flush_resp_count <== flush_resp_count + UFix(1,1); }
|
||||
when (flushing && dcache.io.cpu.req_rdy) {
|
||||
flush_count <== flush_count + UFix(1,1);
|
||||
}
|
||||
when (flush_waiting && dcache.io.cpu.resp_val && (dcache.io.cpu.resp_tag(5,0) === r_cpu_req_tag)) {
|
||||
flush_resp_count <== flush_resp_count + UFix(1,1);
|
||||
}
|
||||
|
||||
dcache.io.cpu.req_val := (io.cpu.req_val && (io.cpu.req_cmd != M_FLA) && !flush_waiting) || flushing;
|
||||
dcache.io.cpu.req_cmd := Mux(flushing, M_FLA, io.cpu.req_cmd);
|
||||
dcache.io.cpu.req_cmd := Mux(flushing, M_FLA, io.cpu.req_cmd);
|
||||
dcache.io.cpu.req_addr := Mux(flushing, Cat(Bits(0,tagmsb-taglsb+1), flush_count, Bits(0,offsetbits)).toUFix, io.cpu.req_addr);
|
||||
dcache.io.cpu.req_tag := Mux(flushing, r_cpu_req_tag, io.cpu.req_tag);
|
||||
dcache.io.cpu.req_type := io.cpu.req_type;
|
||||
@ -92,9 +97,10 @@ class rocketDCacheDM_flush(lines: Int, addrbits: Int) extends Component {
|
||||
|
||||
}
|
||||
|
||||
class rocketDCacheDM(lines: Int, addrbits: Int) extends Component {
|
||||
class rocketDCacheDM(lines: Int) extends Component {
|
||||
val io = new ioDCacheDM();
|
||||
|
||||
val addrbits = PADDR_BITS;
|
||||
val indexbits = ceil(log10(lines)/log10(2)).toInt;
|
||||
val offsetbits = 6;
|
||||
val tagmsb = addrbits - 1;
|
||||
@ -119,9 +125,10 @@ class rocketDCacheDM(lines: Int, addrbits: Int) extends Component {
|
||||
val p_store_type = Reg(resetVal = Bits(0,3));
|
||||
val p_store_valid = Reg(resetVal = Bool(false));
|
||||
|
||||
val req_load = (r_cpu_req_cmd === M_XRD);
|
||||
val req_load = (r_cpu_req_cmd === M_XRD) || (r_cpu_req_cmd === M_PRD);
|
||||
val req_store = (r_cpu_req_cmd === M_XWR);
|
||||
val req_flush = (r_cpu_req_cmd === M_FLA);
|
||||
val req_ptw_load = (r_cpu_req_cmd === M_PRD);
|
||||
|
||||
when (io.cpu.req_val && io.cpu.req_rdy) {
|
||||
r_cpu_req_addr <== io.cpu.req_addr;
|
||||
@ -288,7 +295,8 @@ class rocketDCacheDM(lines: Int, addrbits: Int) extends Component {
|
||||
((state === s_resolve_miss) && req_flush);
|
||||
|
||||
io.cpu.resp_miss := miss;
|
||||
io.cpu.resp_tag := Cat(Bits(0,1), r_cpu_req_type, r_cpu_req_addr(2,0), r_cpu_req_tag);
|
||||
// io.cpu.resp_tag := Cat(Bits(0,1), r_cpu_req_type, r_cpu_req_addr(2,0), r_cpu_req_tag);
|
||||
io.cpu.resp_tag := Cat(req_ptw_load, r_cpu_req_type, r_cpu_req_addr(2,0), r_cpu_req_tag);
|
||||
io.cpu.resp_data :=
|
||||
Mux(r_cpu_req_addr(offsetlsb).toBool, data_array_rdata(127, 64),
|
||||
data_array_rdata(63,0));
|
||||
|
@ -12,6 +12,8 @@ class ioDpathAll extends Bundle()
|
||||
val debug = new ioDebug();
|
||||
val dmem = new ioDmem(List("req_addr", "req_data", "req_tag", "resp_val", "resp_tag", "resp_data")).flip();
|
||||
val imem = new ioImem(List("req_addr", "resp_data")).flip();
|
||||
val itlb_xcpt = Bool('input);
|
||||
val ptbr = UFix(PADDR_BITS, 'output);
|
||||
}
|
||||
|
||||
class rocketDpath extends Component
|
||||
@ -44,15 +46,15 @@ class rocketDpath extends Component
|
||||
val if_reg_pc = Reg(width = 32, resetVal = UFix(0, 32));
|
||||
|
||||
// instruction decode definitions
|
||||
val id_reg_valid = Reg(resetVal = Bool(false));
|
||||
val id_reg_pc = Reg(resetVal = UFix(0,32));
|
||||
val id_reg_pc_plus4 = Reg(resetVal = UFix(0,32));
|
||||
val id_reg_valid = Reg(resetVal = Bool(false));
|
||||
val id_reg_pc = Reg(resetVal = UFix(0,VADDR_BITS));
|
||||
val id_reg_pc_plus4 = Reg(resetVal = UFix(0,VADDR_BITS));
|
||||
val id_reg_inst = Reg(resetVal = NOP);
|
||||
|
||||
// execute definitions
|
||||
val ex_reg_valid = Reg(resetVal = Bool(false));
|
||||
val ex_reg_pc = Reg(resetVal = UFix(0,32));
|
||||
val ex_reg_pc_plus4 = Reg(resetVal = UFix(0,32));
|
||||
val ex_reg_pc = Reg(resetVal = UFix(0,VADDR_BITS));
|
||||
val ex_reg_pc_plus4 = Reg(resetVal = UFix(0,VADDR_BITS));
|
||||
val ex_reg_inst = Reg(resetVal = Bits(0,32));
|
||||
val ex_reg_raddr2 = Reg(resetVal = UFix(0,5));
|
||||
val ex_reg_raddr1 = Reg(resetVal = UFix(0,5));
|
||||
@ -79,8 +81,8 @@ class rocketDpath extends Component
|
||||
|
||||
// memory definitions
|
||||
val mem_reg_valid = Reg(resetVal = Bool(false));
|
||||
val mem_reg_pc = Reg(resetVal = UFix(0,32));
|
||||
val mem_reg_pc_plus4 = Reg(resetVal = UFix(0,32));
|
||||
val mem_reg_pc = Reg(resetVal = UFix(0,VADDR_BITS));
|
||||
val mem_reg_pc_plus4 = Reg(resetVal = UFix(0,VADDR_BITS));
|
||||
val mem_reg_waddr = Reg(resetVal = UFix(0,5));
|
||||
val mem_reg_wdata = Reg(resetVal = Bits(0,64));
|
||||
val mem_reg_raddr2 = Reg(resetVal = UFix(0,5));
|
||||
@ -94,7 +96,7 @@ class rocketDpath extends Component
|
||||
|
||||
// writeback definitions
|
||||
val wb_reg_valid = Reg(resetVal = Bool(false));
|
||||
val wb_reg_pc = Reg(resetVal = UFix(0,32));
|
||||
val wb_reg_pc = Reg(resetVal = UFix(0,VADDR_BITS));
|
||||
val wb_reg_waddr = Reg(resetVal = UFix(0,5));
|
||||
val wb_reg_wdata = Reg(resetVal = Bits(0,64));
|
||||
val wb_reg_ctrl_ll_wb = Reg(resetVal = Bool(false));
|
||||
@ -112,7 +114,7 @@ class rocketDpath extends Component
|
||||
val r_dmem_resp_data = Reg(resetVal = Bits(0,64));
|
||||
|
||||
// instruction fetch stage
|
||||
val if_pc_plus4 = if_reg_pc + UFix(4, 32);
|
||||
val if_pc_plus4 = if_reg_pc + UFix(4);
|
||||
|
||||
val ex_sign_extend =
|
||||
Cat(Fill(52, ex_reg_inst(21)), ex_reg_inst(21,10));
|
||||
@ -135,16 +137,17 @@ class rocketDpath extends Component
|
||||
Mux(io.ctrl.sel_pc === PC_BR, ex_branch_target,
|
||||
Mux(io.ctrl.sel_pc === PC_J, ex_branch_target,
|
||||
Mux(io.ctrl.sel_pc === PC_JR, ex_jr_target.toUFix,
|
||||
Mux(io.ctrl.sel_pc === PC_PCR, mem_reg_pcr(31,0).toUFix,
|
||||
Mux(io.ctrl.sel_pc === PC_PCR, mem_reg_pcr(VADDR_BITS-1,0).toUFix,
|
||||
Mux(io.ctrl.sel_pc === PC_MEM, mem_reg_pc,
|
||||
UFix(0, 32))))))))));
|
||||
UFix(0, VADDR_BITS))))))))));
|
||||
|
||||
when (!io.host.start){
|
||||
if_reg_pc <== UFix(0, 32); //32'hFFFF_FFFC;
|
||||
if_reg_pc <== UFix(0, VADDR_BITS); //32'hFFFF_FFFC;
|
||||
}
|
||||
when (!io.ctrl.stallf) {
|
||||
if_reg_pc <== if_next_pc;
|
||||
}
|
||||
|
||||
|
||||
io.imem.req_addr :=
|
||||
Mux(io.ctrl.stallf, if_reg_pc,
|
||||
@ -334,7 +337,7 @@ class rocketDpath extends Component
|
||||
|
||||
// D$ request interface (registered inside D$ module)
|
||||
// other signals (req_val, req_rdy) connect to control module
|
||||
io.dmem.req_addr := ex_alu_out;
|
||||
io.dmem.req_addr := ex_alu_out(PADDR_BITS-1,0);
|
||||
io.dmem.req_data := ex_reg_rs2;
|
||||
io.dmem.req_tag := ex_reg_waddr;
|
||||
|
||||
@ -354,7 +357,8 @@ class rocketDpath extends Component
|
||||
// pcr.io.cause := ex_reg_ctrl_cause;
|
||||
// pcr.io.pc := ex_reg_pc;
|
||||
|
||||
io.ctrl.status := pcr.io.status;
|
||||
io.ctrl.status := pcr.io.status;
|
||||
io.ptbr := pcr.io.ptbr;
|
||||
io.debug.error_mode := pcr.io.debug.error_mode;
|
||||
io.debug.log_control := pcr.io.debug.log_control;
|
||||
|
||||
|
@ -1,19 +1,18 @@
|
||||
package Top
|
||||
{
|
||||
|
||||
import Chisel._
|
||||
import Chisel._;
|
||||
import Node._;
|
||||
|
||||
import Constants._;
|
||||
|
||||
class ioDpathBTB extends Bundle()
|
||||
{
|
||||
val current_pc4 = UFix(32, 'input);
|
||||
val current_pc4 = UFix(VADDR_BITS, 'input);
|
||||
val hit = Bool('output);
|
||||
val target = UFix(32, 'output);
|
||||
val target = UFix(VADDR_BITS, 'output);
|
||||
val wen = Bool('input);
|
||||
val correct_pc4 = UFix(32, 'input);
|
||||
val correct_target = UFix(32, 'input);
|
||||
val correct_pc4 = UFix(VADDR_BITS, 'input);
|
||||
val correct_target = UFix(VADDR_BITS, 'input);
|
||||
}
|
||||
|
||||
class rocketDpathBTB extends Component
|
||||
@ -21,11 +20,15 @@ class rocketDpathBTB extends Component
|
||||
override val io = new ioDpathBTB();
|
||||
val rst_lwlr_pf = Mem(4, io.wen, io.correct_pc4(3, 2), UFix(1, 1), resetVal = UFix(0, 1));
|
||||
val lwlr_pf = Mem(4, io.wen, io.correct_pc4(3, 2),
|
||||
Cat(io.correct_pc4(31,4), io.correct_target(31,2)), resetVal = UFix(0, 1));
|
||||
Cat(io.correct_pc4(VADDR_BITS-1,4), io.correct_target(VADDR_BITS-1,2)), resetVal = UFix(0, 1));
|
||||
// Cat(io.correct_pc4(31,4), io.correct_target(31,2)), resetVal = UFix(0, 1));
|
||||
val is_val = rst_lwlr_pf(io.current_pc4(3, 2));
|
||||
val tag_target = lwlr_pf(io.current_pc4(3, 2));
|
||||
io.hit := (is_val & (tag_target(57,30) === io.current_pc4(31, 4))).toBool;
|
||||
io.target := Cat(tag_target(29, 0), Bits(0,2)).toUFix;
|
||||
io.hit := (is_val & (tag_target(2*VADDR_BITS-7,VADDR_BITS-2) === io.current_pc4(VADDR_BITS-1, 4))).toBool;
|
||||
io.target := Cat(tag_target(VADDR_BITS-3, 0), Bits(0,2)).toUFix;
|
||||
|
||||
// io.hit := (is_val & (tag_target(57,30) === io.current_pc4(31, 4))).toBool;
|
||||
// io.target := Cat(tag_target(29, 0), Bits(0,2)).toUFix;
|
||||
}
|
||||
|
||||
class ioDpathPCR extends Bundle()
|
||||
@ -35,20 +38,19 @@ class ioDpathPCR extends Bundle()
|
||||
val r = new ioReadPort();
|
||||
val w = new ioWritePort();
|
||||
|
||||
val status = Bits(8, 'output);
|
||||
val status = Bits(17, 'output);
|
||||
val ptbr = UFix(PADDR_BITS, 'output);
|
||||
val exception = Bool('input);
|
||||
val cause = UFix(5, 'input);
|
||||
val pc = UFix(32, 'input);
|
||||
val pc = UFix(VADDR_BITS, 'input);
|
||||
val eret = Bool('input);
|
||||
}
|
||||
|
||||
class rocketDpathPCR extends Component
|
||||
{
|
||||
override val io = new ioDpathPCR();
|
||||
|
||||
val HAVE_FPU = Bool(false);
|
||||
val HAVE_VEC = Bool(false);
|
||||
val io = new ioDpathPCR();
|
||||
val w = 32;
|
||||
|
||||
val reg_epc = Reg(resetVal = Bits(0, w));
|
||||
val reg_badvaddr = Reg(resetVal = Bits(0, w));
|
||||
val reg_ebase = Reg(resetVal = Bits(0, w));
|
||||
@ -59,9 +61,11 @@ class rocketDpathPCR extends Component
|
||||
val reg_fromhost = Reg(resetVal = Bits(0, w));
|
||||
val reg_k0 = Reg(resetVal = Bits(0, 2*w));
|
||||
val reg_k1 = Reg(resetVal = Bits(0, 2*w));
|
||||
val reg_ptbr = Reg(resetVal = UFix(0, PADDR_BITS));
|
||||
|
||||
val reg_error_mode = Reg(resetVal = Bool(false));
|
||||
val reg_log_control = Reg(resetVal = Bool(false));
|
||||
val reg_status_vm = Reg(resetVal = Bool(false));
|
||||
val reg_status_im = Reg(resetVal = Bits(0,8));
|
||||
val reg_status_sx = Reg(resetVal = Bool(true));
|
||||
val reg_status_ux = Reg(resetVal = Bool(true));
|
||||
@ -74,7 +78,8 @@ class rocketDpathPCR extends Component
|
||||
val reg_status = Cat(reg_status_sx, reg_status_ux, reg_status_s, reg_status_ps, Bits(0,1), reg_status_ev, reg_status_ef, reg_status_et);
|
||||
val rdata = Wire() { Bits() };
|
||||
|
||||
io.status := reg_status;
|
||||
io.status := Cat(reg_status_vm, reg_status_im, reg_status);
|
||||
io.ptbr := reg_ptbr;
|
||||
io.host.to := Mux(io.host.from_wen, Bits(0, w), reg_tohost);
|
||||
io.debug.error_mode := reg_error_mode;
|
||||
io.debug.log_control := reg_log_control;
|
||||
@ -110,6 +115,7 @@ class rocketDpathPCR extends Component
|
||||
|
||||
when (!io.exception && !io.eret && io.w.en) {
|
||||
when (io.w.addr === PCR_STATUS) {
|
||||
reg_status_vm <== io.w.data(16).toBool;
|
||||
reg_status_im <== io.w.data(15,8);
|
||||
reg_status_sx <== io.w.data(7).toBool;
|
||||
reg_status_ux <== io.w.data(6).toBool;
|
||||
@ -129,11 +135,12 @@ class rocketDpathPCR extends Component
|
||||
when (io.w.addr === PCR_FROMHOST) { reg_fromhost <== io.w.data(w-1,0); }
|
||||
when (io.w.addr === PCR_K0) { reg_k0 <== io.w.data; }
|
||||
when (io.w.addr === PCR_K1) { reg_k1 <== io.w.data; }
|
||||
when (io.w.addr === PCR_PTBR) { reg_ptbr <== Cat(io.w.data(PADDR_BITS-1, PGIDX_BITS), Bits(0, PGIDX_BITS)).toUFix; }
|
||||
}
|
||||
|
||||
when (!io.r.en) { rdata <== Bits(0,2*w); }
|
||||
switch (io.r.addr) {
|
||||
is (PCR_STATUS) { rdata <== Cat(Bits(0,w+16), reg_status_im, reg_status); }
|
||||
is (PCR_STATUS) { rdata <== Cat(Bits(0,w+15), reg_status_vm, reg_status_im, reg_status); }
|
||||
is (PCR_EPC) { rdata <== Cat(Fill(w, reg_epc(w-1)), reg_epc); }
|
||||
is (PCR_BADVADDR) { rdata <== Cat(Fill(w, reg_badvaddr(w-1)), reg_badvaddr); }
|
||||
is (PCR_EVEC) { rdata <== Cat(Fill(w, reg_ebase(w-1)), reg_ebase); }
|
||||
@ -146,6 +153,7 @@ class rocketDpathPCR extends Component
|
||||
is (PCR_TOHOST) { rdata <== Cat(Fill(w, reg_tohost(w-1)), reg_tohost); }
|
||||
is (PCR_K0) { rdata <== reg_k0; }
|
||||
is (PCR_K1) { rdata <== reg_k1; }
|
||||
is (PCR_PTBR) { rdata <== Cat(Bits(0,2*w-PADDR_BITS), reg_ptbr); }
|
||||
otherwise { rdata <== Bits(0,2*w); }
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
package Top {
|
||||
|
||||
import Chisel._
|
||||
import Chisel._;
|
||||
import Node._;
|
||||
import Constants._;
|
||||
import scala.math._;
|
||||
|
||||
// interface between I$ and processor (32 bits wide)
|
||||
@ -17,7 +18,7 @@ class ioImem(view: List[String] = null) extends Bundle (view)
|
||||
// interface between I$ and memory (128 bits wide)
|
||||
class ioIcache(view: List[String] = null) extends Bundle (view)
|
||||
{
|
||||
val req_addr = UFix(32, 'input);
|
||||
val req_addr = UFix(PADDR_BITS, 'input);
|
||||
val req_val = Bool('input);
|
||||
val req_rdy = Bool('output);
|
||||
val resp_data = Bits(128, 'output);
|
||||
@ -55,9 +56,10 @@ class rocketSRAMsp(entries: Int, width: Int) extends Component {
|
||||
// addr_bits = address width (word addressable) bits
|
||||
// 32 bit wide cpu port, 128 bit wide memory port, 64 byte cachelines
|
||||
|
||||
class rocketICacheDM(lines: Int, addrbits : Int) extends Component {
|
||||
class rocketICacheDM(lines: Int) extends Component {
|
||||
val io = new ioICacheDM();
|
||||
|
||||
val addrbits = PADDR_BITS;
|
||||
val indexbits = ceil(log10(lines)/log10(2)).toInt;
|
||||
val offsetbits = 6;
|
||||
val tagmsb = addrbits - 1;
|
||||
|
178
rocket/src/main/scala/itlb.scala
Normal file
178
rocket/src/main/scala/itlb.scala
Normal file
@ -0,0 +1,178 @@
|
||||
package Top
|
||||
{
|
||||
|
||||
import Chisel._;
|
||||
import Node._;
|
||||
import Constants._;
|
||||
import scala.math._;
|
||||
|
||||
class ioCAM(addr_bits: Int, tag_bits: Int) extends Bundle {
|
||||
val tag = Bits(tag_bits, 'input);
|
||||
val hit = Bool('output);
|
||||
val hit_addr = UFix(addr_bits, 'output);
|
||||
|
||||
val write = Bool('input);
|
||||
val write_tag = Bits(tag_bits, 'input);
|
||||
val write_addr = UFix(addr_bits, 'input);
|
||||
}
|
||||
|
||||
class rocketCAM(entries: Int, addr_bits: Int, tag_bits: Int) extends Component {
|
||||
val io = new ioCAM(addr_bits, tag_bits);
|
||||
val cam_tags = Mem(entries, io.write, io.write_addr, io.write_tag);
|
||||
|
||||
val l_hit = Wire() { Bool() };
|
||||
val l_hit_addr = Wire() { UFix() };
|
||||
|
||||
for (i <- 0 to entries-1) {
|
||||
when (cam_tags(UFix(i)) === io.tag) {
|
||||
l_hit <== Bool(true);
|
||||
l_hit_addr <== UFix(i,addr_bits);
|
||||
}
|
||||
}
|
||||
|
||||
l_hit <== Bool(false);
|
||||
l_hit_addr <== UFix(0, addr_bits);
|
||||
|
||||
io.hit := l_hit;
|
||||
io.hit_addr := l_hit_addr;
|
||||
}
|
||||
|
||||
// interface between TLB and PTW
|
||||
class ioTLB_PTW extends Bundle
|
||||
{
|
||||
// requests
|
||||
val req_val = Bool('output);
|
||||
val req_rdy = Bool('input);
|
||||
val req_vpn = Bits(VPN_BITS, 'output);
|
||||
// responses
|
||||
val resp_val = Bool('input);
|
||||
val resp_err = Bool('input);
|
||||
val resp_ppn = Bits(PPN_BITS, 'input);
|
||||
val resp_perm = Bits(PERM_BITS, 'input);
|
||||
}
|
||||
|
||||
// interface between ITLB and fetch stage of pipeline
|
||||
class ioITLB_CPU extends Bundle
|
||||
{
|
||||
// status bits (from PCR), to check current permission and whether VM is enabled
|
||||
val status = Bits(17, 'input);
|
||||
// invalidate all TLB entries
|
||||
val invalidate = Bool('input);
|
||||
// lookup requests
|
||||
val req_val = Bool('input);
|
||||
val req_rdy = Bool('output);
|
||||
val req_asid = Bits(ASID_BITS, 'input);
|
||||
val req_vpn = Bits(VPN_BITS, 'input);
|
||||
// lookup responses
|
||||
val resp_val = Bool('output);
|
||||
val resp_ppn = Bits(PPN_BITS, 'output);
|
||||
val exception = Bool('output);
|
||||
}
|
||||
|
||||
class ioITLB extends Bundle
|
||||
{
|
||||
val cpu = new ioITLB_CPU();
|
||||
val ptw = new ioTLB_PTW();
|
||||
}
|
||||
|
||||
class rocketITLB(entries: Int) extends Component
|
||||
{
|
||||
val addr_bits = ceil(log10(entries)/log10(2)).toInt;
|
||||
val io = new ioITLB();
|
||||
|
||||
val s_ready :: s_request :: s_wait :: Nil = Enum(3) { UFix() };
|
||||
val state = Reg(resetVal = s_ready);
|
||||
|
||||
val tag_cam = new rocketCAM(entries, addr_bits, ASID_BITS+VPN_BITS);
|
||||
|
||||
val lookup_tag = Cat(io.cpu.req_asid, io.cpu.req_vpn);
|
||||
val r_refill_tag = Reg(resetVal = Bits(0, ASID_BITS+VPN_BITS));
|
||||
val r_refill_waddr = Reg(resetVal = UFix(0, addr_bits));
|
||||
val repl_count = Reg(resetVal = UFix(0, addr_bits));
|
||||
|
||||
val tag_ram = Mem(entries, io.ptw.resp_val, r_refill_waddr.toUFix, io.ptw.resp_ppn);
|
||||
|
||||
tag_cam.io.tag := lookup_tag;
|
||||
tag_cam.io.write := io.ptw.resp_val;
|
||||
tag_cam.io.write_tag := r_refill_tag;
|
||||
tag_cam.io.write_addr := r_refill_waddr;
|
||||
val tag_hit_addr = tag_cam.io.hit_addr;
|
||||
|
||||
// extract fields from status register
|
||||
val status_mode = io.cpu.status(6).toBool;
|
||||
val status_vm = io.cpu.status(16).toBool
|
||||
|
||||
// extract fields from PT permission bits
|
||||
val ptw_perm_ux = io.ptw.resp_perm(4);
|
||||
val ptw_perm_sx = io.ptw.resp_perm(7);
|
||||
|
||||
// valid bit array
|
||||
val vb_array = Reg(resetVal = Bits(0, entries));
|
||||
when (io.cpu.invalidate) {
|
||||
vb_array <== Bits(0, entries);
|
||||
}
|
||||
when (io.ptw.resp_val) {
|
||||
vb_array <== vb_array.bitSet(r_refill_waddr, Bool(true));
|
||||
}
|
||||
|
||||
// permission bit arrays
|
||||
val ux_array = Reg(resetVal = Bits(0, entries)); // user execute permission
|
||||
val sx_array = Reg(resetVal = Bits(0, entries)); // supervisor execute permission
|
||||
when (io.ptw.resp_val) {
|
||||
ux_array <== ux_array.bitSet(r_refill_waddr, ptw_perm_ux);
|
||||
sx_array <== ux_array.bitSet(r_refill_waddr, ptw_perm_sx);
|
||||
}
|
||||
|
||||
// high if there are any unused (invalid) entries in the ITLB
|
||||
// val invalid_entry = orR(~vb_array);
|
||||
val invalid_entry = ~vb_array.toUFix.orR();
|
||||
val ie_enc = new priorityEncoder(entries);
|
||||
ie_enc.io.in := vb_array.toUFix;
|
||||
val ie_addr = ie_enc.io.out;
|
||||
|
||||
val repl_waddr = Mux(invalid_entry, ie_addr, repl_count).toUFix;
|
||||
|
||||
val tag_hit = tag_cam.io.hit && vb_array(tag_hit_addr).toBool;
|
||||
val lookup_miss = (state === s_ready) && status_vm && io.cpu.req_val && !tag_hit;
|
||||
|
||||
when (lookup_miss) {
|
||||
r_refill_tag <== lookup_tag;
|
||||
r_refill_waddr <== repl_waddr;
|
||||
when (!invalid_entry) {
|
||||
repl_count <== repl_count + UFix(1);
|
||||
}
|
||||
}
|
||||
|
||||
val itlb_exception =
|
||||
tag_hit &&
|
||||
((status_mode && !sx_array(tag_hit_addr).toBool) ||
|
||||
(!status_mode && !ux_array(tag_hit_addr).toBool));
|
||||
|
||||
io.cpu.req_rdy := (state === s_ready);
|
||||
io.cpu.resp_val := Mux(status_vm, tag_hit, io.cpu.req_val);
|
||||
io.cpu.resp_ppn := Mux(status_vm, io.cpu.req_vpn(PPN_BITS-1, 0), tag_ram(tag_hit_addr));
|
||||
io.cpu.exception := itlb_exception;
|
||||
|
||||
io.ptw.req_val := (state === s_request);
|
||||
io.ptw.req_vpn := r_refill_tag;
|
||||
|
||||
// control state machine
|
||||
switch (state) {
|
||||
is (s_ready) {
|
||||
when (status_vm && io.cpu.req_val && !tag_hit) {
|
||||
state <== s_request;
|
||||
}
|
||||
}
|
||||
is (s_request) {
|
||||
when (io.ptw.req_rdy) {
|
||||
state <== s_wait;
|
||||
}
|
||||
}
|
||||
is (s_wait) {
|
||||
when (io.ptw.resp_val) {
|
||||
state <== s_ready;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
168
rocket/src/main/scala/ptw.scala
Normal file
168
rocket/src/main/scala/ptw.scala
Normal file
@ -0,0 +1,168 @@
|
||||
package Top {
|
||||
|
||||
import Chisel._;
|
||||
import Node._;
|
||||
import Constants._;
|
||||
import scala.math._;
|
||||
|
||||
class ioDmemArbiter extends Bundle
|
||||
{
|
||||
val ptw = new ioDmem(List("req_val", "req_rdy", "req_cmd", "req_type", "req_addr", "resp_data", "resp_val"));
|
||||
val cpu = new ioDmem();
|
||||
val mem = new ioDmem().flip();
|
||||
}
|
||||
|
||||
class rocketDmemArbiter extends Component
|
||||
{
|
||||
val io = new ioDmemArbiter();
|
||||
|
||||
io.mem.req_val := io.ptw.req_val || io.cpu.req_val;
|
||||
io.mem.req_cmd := Mux(io.ptw.req_val, io.ptw.req_cmd, io.cpu.req_cmd);
|
||||
io.mem.req_type := Mux(io.ptw.req_val, io.ptw.req_type, io.cpu.req_type);
|
||||
io.mem.req_addr := Mux(io.ptw.req_val, io.ptw.req_addr, io.cpu.req_addr);
|
||||
io.mem.req_data := io.cpu.req_data;
|
||||
io.mem.req_tag := Mux(io.ptw.req_val, Bits(0,5), io.cpu.req_tag);
|
||||
|
||||
io.ptw.req_rdy := io.mem.req_rdy;
|
||||
io.cpu.req_rdy := io.mem.req_rdy && !io.ptw.req_val;
|
||||
io.cpu.resp_miss := io.mem.resp_miss; // FIXME
|
||||
|
||||
io.cpu.resp_val := io.mem.resp_val && !io.mem.resp_tag(12).toBool;
|
||||
io.ptw.resp_val := io.mem.resp_val && io.mem.resp_tag(12).toBool;
|
||||
|
||||
io.ptw.resp_data := io.mem.resp_data;
|
||||
io.cpu.resp_data := io.mem.resp_data;
|
||||
io.cpu.resp_tag := io.mem.resp_tag;
|
||||
|
||||
}
|
||||
|
||||
class ioPTW extends Bundle
|
||||
{
|
||||
val itlb = new ioTLB_PTW().flip();
|
||||
// val dtlb = new ioTLB_PTW.flip();
|
||||
val dmem = new ioDmem(List("req_val", "req_rdy", "req_cmd", "req_type", "req_addr", "resp_data", "resp_val")).flip();
|
||||
val ptbr = UFix(PADDR_BITS, 'input);
|
||||
}
|
||||
|
||||
class rocketPTW extends Component
|
||||
{
|
||||
val io = new ioPTW();
|
||||
|
||||
val s_ready :: s_l1_req :: s_l1_wait :: s_l1_fake :: s_l2_req :: s_l2_wait :: s_l2_fake:: s_l3_req :: s_l3_wait :: s_done :: s_error :: Nil = Enum(11) { UFix() };
|
||||
val state = Reg(resetVal = s_ready);
|
||||
|
||||
val r_req_vpn = Reg(resetVal = Bits(0,VPN_BITS));
|
||||
|
||||
val req_addr = Reg(resetVal = UFix(0,PPN_BITS+PGIDX_BITS));
|
||||
val r_resp_ppn = Reg(resetVal = Bits(0,PPN_BITS));
|
||||
val r_resp_perm = Reg(resetVal = Bits(0,PERM_BITS));
|
||||
|
||||
val vpn_idx = Mux(state === s_l2_wait, r_req_vpn(9,0), r_req_vpn(19,10));
|
||||
|
||||
when ((state === s_ready) && io.itlb.req_val) {
|
||||
r_req_vpn <== io.itlb.req_vpn;
|
||||
req_addr <== Cat(io.ptbr(PADDR_BITS-1,PGIDX_BITS), io.itlb.req_vpn(VPN_BITS-1,VPN_BITS-10)).toUFix;
|
||||
}
|
||||
when (io.dmem.resp_val) {
|
||||
req_addr <== Cat(io.dmem.resp_data(PADDR_BITS-1, PGIDX_BITS), vpn_idx).toUFix;
|
||||
r_resp_perm <== io.dmem.resp_data(9,4);
|
||||
r_resp_ppn <== io.dmem.resp_data(PPN_BITS-1, PGIDX_BITS);
|
||||
}
|
||||
|
||||
io.dmem.req_val :=
|
||||
(state === s_l1_req) ||
|
||||
(state === s_l2_req) ||
|
||||
(state === s_l3_req);
|
||||
|
||||
io.dmem.req_cmd := M_PRD;
|
||||
io.dmem.req_type := MT_D;
|
||||
io.dmem.req_addr := req_addr;
|
||||
|
||||
io.itlb.resp_val := (state === s_done) || (state === s_l1_fake) || (state === s_l2_fake);
|
||||
io.itlb.resp_err := (state === s_error);
|
||||
io.itlb.resp_perm := r_resp_perm;
|
||||
io.itlb.resp_ppn :=
|
||||
Mux(state === s_l1_fake, Cat(r_resp_ppn(PADDR_BITS-1, PADDR_BITS-7), r_req_vpn(VPN_BITS-8, 0)),
|
||||
Mux(state === s_l2_fake, Cat(r_resp_ppn(PADDR_BITS-1, PADDR_BITS-17), r_req_vpn(VPN_BITS-18, 0)),
|
||||
r_resp_ppn));
|
||||
|
||||
val resp_ptd = (io.dmem.resp_data(1,0) === Bits(1,2));
|
||||
val resp_pte = (io.dmem.resp_data(1,0) === Bits(2,2));
|
||||
|
||||
// control state machine
|
||||
switch (state) {
|
||||
is (s_ready) {
|
||||
when (io.itlb.req_val) {
|
||||
state <== s_l1_req;
|
||||
}
|
||||
}
|
||||
// level 1
|
||||
is (s_l1_req) {
|
||||
when (io.dmem.req_rdy) {
|
||||
state <== s_l1_wait;
|
||||
}
|
||||
}
|
||||
is (s_l1_wait) {
|
||||
when (io.dmem.resp_val) {
|
||||
when (resp_ptd) { // page table descriptor
|
||||
state <== s_l2_req;
|
||||
}
|
||||
when (resp_pte) { // page table entry
|
||||
state <== s_l1_fake;
|
||||
}
|
||||
otherwise {
|
||||
state <== s_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
is (s_l1_fake) {
|
||||
state <== s_ready;
|
||||
}
|
||||
// level 2
|
||||
is (s_l2_req) {
|
||||
when (io.dmem.req_rdy) {
|
||||
state <== s_l2_wait;
|
||||
}
|
||||
}
|
||||
is (s_l2_wait) {
|
||||
when (io.dmem.resp_val) {
|
||||
when (resp_ptd) { // page table descriptor
|
||||
state <== s_l3_req;
|
||||
}
|
||||
when (resp_pte) { // page table entry
|
||||
state <== s_l2_fake;
|
||||
}
|
||||
otherwise {
|
||||
state <== s_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
is (s_l2_fake) {
|
||||
state <== s_ready;
|
||||
}
|
||||
// level 3
|
||||
is (s_l3_req) {
|
||||
when (io.dmem.req_rdy) {
|
||||
state <== s_l3_wait;
|
||||
}
|
||||
}
|
||||
is (s_l3_wait) {
|
||||
when (io.dmem.resp_val) {
|
||||
when (resp_pte) { // page table entry
|
||||
state <== s_done;
|
||||
}
|
||||
otherwise {
|
||||
state <== s_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
is (s_done) {
|
||||
state <== s_ready;
|
||||
}
|
||||
is (s_error) {
|
||||
state <== s_ready;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -15,9 +15,9 @@ class Top() extends Component {
|
||||
val io = new ioTop();
|
||||
|
||||
val cpu = new rocketProc();
|
||||
val icache = new rocketICacheDM(128, 32); // lines, address bits
|
||||
val icache = new rocketICacheDM(128); // # 64 byte cache lines
|
||||
val icache_pf = new rocketIPrefetcher();
|
||||
val dcache = new rocketDCacheDM_flush(128, 32);
|
||||
val dcache = new rocketDCacheDM_flush(128);
|
||||
val arbiter = new rocketMemArbiter();
|
||||
|
||||
arbiter.io.mem ^^ io.mem;
|
||||
|
52
rocket/src/main/scala/util.scala
Normal file
52
rocket/src/main/scala/util.scala
Normal file
@ -0,0 +1,52 @@
|
||||
package Top
|
||||
{
|
||||
|
||||
import Chisel._
|
||||
import Node._;
|
||||
import scala.math._;
|
||||
|
||||
class ioPriorityDecoder(in_width: Int, out_width: Int) extends Bundle
|
||||
{
|
||||
val in = UFix(in_width, 'input);
|
||||
val out = Bits(out_width, 'output);
|
||||
}
|
||||
|
||||
class priorityDecoder(width: Int) extends Component
|
||||
{
|
||||
val in_width = ceil(log10(width)/log10(2)).toInt;
|
||||
val io = new ioPriorityEncoder(in_width, width);
|
||||
val l_out = Wire() { Bits() };
|
||||
|
||||
for (i <- 0 to width-1) {
|
||||
when (io.in === UFix(i, in_width)) {
|
||||
l_out <== Bits(1,1) << UFix(i);
|
||||
}
|
||||
}
|
||||
|
||||
l_out <== Bits(0, width);
|
||||
io.out := l_out;
|
||||
}
|
||||
|
||||
class ioPriorityEncoder(in_width: Int, out_width: Int) extends Bundle
|
||||
{
|
||||
val in = Bits(in_width, 'input);
|
||||
val out = UFix(out_width, 'output);
|
||||
}
|
||||
|
||||
class priorityEncoder(width: Int) extends Component
|
||||
{
|
||||
val out_width = ceil(log10(width)/log10(2)).toInt;
|
||||
val io = new ioPriorityDecoder(width, out_width);
|
||||
val l_out = Wire() { UFix() };
|
||||
|
||||
for (i <- 0 to width-1) {
|
||||
when (io.in(i).toBool) {
|
||||
l_out <== UFix(i, out_width);
|
||||
}
|
||||
}
|
||||
|
||||
l_out <== UFix(0, out_width);
|
||||
io.out := l_out;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user