1
0

integrating ITLB & PTW

This commit is contained in:
Rimas Avizienis 2011-11-09 14:52:17 -08:00
parent 7130edac8d
commit e96430d862
11 changed files with 538 additions and 63 deletions

View File

@ -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);
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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); }
}
}

View File

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

View 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;
}
}
}
}
}

View 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;
}
}
}
}

View File

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

View 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;
}
}