diff --git a/rocket/src/main/scala/consts.scala b/rocket/src/main/scala/consts.scala index f8069c4e..344eace5 100644 --- a/rocket/src/main/scala/consts.scala +++ b/rocket/src/main/scala/consts.scala @@ -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); } -} +} \ No newline at end of file diff --git a/rocket/src/main/scala/cpu.scala b/rocket/src/main/scala/cpu.scala index 2f54d775..efec38ef 100644 --- a/rocket/src/main/scala/cpu.scala +++ b/rocket/src/main/scala/cpu.scala @@ -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); diff --git a/rocket/src/main/scala/ctrl.scala b/rocket/src/main/scala/ctrl.scala index 5a7ea713..dfffc8ba 100644 --- a/rocket/src/main/scala/ctrl.scala +++ b/rocket/src/main/scala/ctrl.scala @@ -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 diff --git a/rocket/src/main/scala/dcache.scala b/rocket/src/main/scala/dcache.scala index 91a90ea3..fcd10394 100644 --- a/rocket/src/main/scala/dcache.scala +++ b/rocket/src/main/scala/dcache.scala @@ -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)); diff --git a/rocket/src/main/scala/dpath.scala b/rocket/src/main/scala/dpath.scala index 55ca866d..ce6e651a 100644 --- a/rocket/src/main/scala/dpath.scala +++ b/rocket/src/main/scala/dpath.scala @@ -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; diff --git a/rocket/src/main/scala/dpath_util.scala b/rocket/src/main/scala/dpath_util.scala index 4c53db11..7011d88b 100644 --- a/rocket/src/main/scala/dpath_util.scala +++ b/rocket/src/main/scala/dpath_util.scala @@ -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); } } } diff --git a/rocket/src/main/scala/icache.scala b/rocket/src/main/scala/icache.scala index 30e4fc17..9b68556a 100644 --- a/rocket/src/main/scala/icache.scala +++ b/rocket/src/main/scala/icache.scala @@ -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; diff --git a/rocket/src/main/scala/itlb.scala b/rocket/src/main/scala/itlb.scala new file mode 100644 index 00000000..71f6073d --- /dev/null +++ b/rocket/src/main/scala/itlb.scala @@ -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; + } + } + } +} +} \ No newline at end of file diff --git a/rocket/src/main/scala/ptw.scala b/rocket/src/main/scala/ptw.scala new file mode 100644 index 00000000..92cb219e --- /dev/null +++ b/rocket/src/main/scala/ptw.scala @@ -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; + } + } +} + +} \ No newline at end of file diff --git a/rocket/src/main/scala/top.scala b/rocket/src/main/scala/top.scala index bb035340..26f27010 100644 --- a/rocket/src/main/scala/top.scala +++ b/rocket/src/main/scala/top.scala @@ -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; diff --git a/rocket/src/main/scala/util.scala b/rocket/src/main/scala/util.scala new file mode 100644 index 00000000..9c60d726 --- /dev/null +++ b/rocket/src/main/scala/util.scala @@ -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; +} + +} \ No newline at end of file