From c29d2821b47f5e7babf5f270b1909692336b0ead Mon Sep 17 00:00:00 2001 From: Rimas Avizienis Date: Wed, 9 Nov 2011 21:54:11 -0800 Subject: [PATCH] cleanup, fixes, initial commit for dtlb.scala --- rocket/src/main/scala/cpu.scala | 9 +- rocket/src/main/scala/ctrl.scala | 18 ++- rocket/src/main/scala/dpath.scala | 15 ++- rocket/src/main/scala/dpath_util.scala | 2 +- rocket/src/main/scala/dtlb.scala | 166 +++++++++++++++++++++++++ rocket/src/main/scala/icache.scala | 4 +- rocket/src/main/scala/itlb.scala | 40 ++++-- rocket/src/main/scala/ptw.scala | 9 +- 8 files changed, 230 insertions(+), 33 deletions(-) create mode 100644 rocket/src/main/scala/dtlb.scala diff --git a/rocket/src/main/scala/cpu.scala b/rocket/src/main/scala/cpu.scala index efec38ef..3b09b0f1 100644 --- a/rocket/src/main/scala/cpu.scala +++ b/rocket/src/main/scala/cpu.scala @@ -4,7 +4,7 @@ import Chisel._; import Node._; import Constants._; -class ioDebug extends Bundle() +class ioDebug(view: List[String] = null) extends Bundle(view) { val error_mode = Bool('output); val log_control = Bool('output); @@ -66,13 +66,14 @@ class rocketProc extends Component 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); +// itlb.io.cpu.req_vpn := dpath.io.imem.req_addr(VADDR_BITS-1,PGIDX_BITS); + itlb.io.cpu.req_addr := dpath.io.imem.req_addr; 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; + io.imem.req_addr := itlb.io.cpu.resp_addr; ctrl.io.imem.resp_val := io.imem.resp_val; - dpath.io.itlb_xcpt := itlb.io.cpu.exception; + ctrl.io.itlb_xcpt := itlb.io.cpu.exception; ptw.io.itlb <> itlb.io.ptw; ptw.io.ptbr := dpath.io.ptbr; diff --git a/rocket/src/main/scala/ctrl.scala b/rocket/src/main/scala/ctrl.scala index dfffc8ba..cef554f7 100644 --- a/rocket/src/main/scala/ctrl.scala +++ b/rocket/src/main/scala/ctrl.scala @@ -37,6 +37,7 @@ class ioCtrlDpath extends Bundle() val xcpt_privileged = Bool('output); val xcpt_fpu = Bool('output); val xcpt_syscall = Bool('output); + val xcpt_itlb = Bool('output); val eret = Bool('output); val mem_load = Bool('output); val wen = Bool('output); @@ -65,9 +66,9 @@ class ioCtrlAll extends Bundle() val dpath = new ioCtrlDpath(); val console = new ioConsole(List("rdy", "valid")); 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 dmem = new ioDmem(List("req_val", "req_rdy", "req_cmd", "req_type", "resp_miss")).flip(); val host = new ioHost(List("start")); -// val itlb_xcpt = Bool('input); + val itlb_xcpt = Bool('input); } class rocketCtrl extends Component @@ -226,7 +227,8 @@ class rocketCtrl extends Component val id_stall_waddr = sboard.io.stallc; val id_stall_ra = sboard.io.stallra; - val id_reg_btb_hit = Reg(width = 1, resetVal = Bool(false)); + val id_reg_btb_hit = Reg(resetVal = Bool(false)); + val id_reg_itlb_xcpt = Reg(resetVal = Bool(false)); val ex_reg_br_type = Reg(){UFix(width = 4)}; val ex_reg_btb_hit = Reg(){Bool()}; val ex_reg_div_mul_val = Reg(){Bool()}; @@ -235,12 +237,15 @@ class rocketCtrl extends Component val ex_reg_mem_type = Reg(){UFix(width = 3)}; val ex_reg_eret = Reg(resetVal = Bool(false)); val ex_reg_privileged = Reg(resetVal = Bool(false)); +// val id_reg_itlb_xcpt = Reg(resetVal = Bool(false)); when (!io.dpath.stalld) { when (io.dpath.killf) { + id_reg_itlb_xcpt <== Bool(false); id_reg_btb_hit <== Bool(false); } otherwise{ + id_reg_itlb_xcpt <== io.itlb_xcpt; id_reg_btb_hit <== io.dpath.btb_hit; } } @@ -254,6 +259,7 @@ class rocketCtrl extends Component ex_reg_mem_type <== UFix(0, 3); ex_reg_eret <== Bool(false); ex_reg_privileged <== Bool(false); +// ex_reg_itlb_xcpt <== Bool(false); } otherwise { ex_reg_br_type <== id_br_type; @@ -264,6 +270,7 @@ class rocketCtrl extends Component ex_reg_mem_type <== id_mem_type; ex_reg_eret <== id_eret.toBool; ex_reg_privileged <== id_privileged.toBool; +// ex_reg_itlb_xcpt <== id_reg_itlb_xcpt; } val beq = io.dpath.br_eq; @@ -284,7 +291,7 @@ class rocketCtrl extends Component val jr_taken = (ex_reg_br_type === BR_JR); val j_taken = (ex_reg_br_type === BR_J); - io.imem.req_val := io.host.start; + io.imem.req_val := io.host.start; // FIXME // io.imem.req_val := Bool(true); io.dmem.req_val := ex_reg_mem_val && ~io.dpath.killx; @@ -330,7 +337,7 @@ class rocketCtrl extends Component val replay_mem = io.dmem.resp_miss; val kill_ex = replay_ex | replay_mem | mem_reg_privileged; - val kill_mem = io.dpath.exception; + val kill_mem = io.dpath.exception; // TODO: add load/store related exceptions dcache_miss <== io.dmem.resp_miss; @@ -461,6 +468,7 @@ class rocketCtrl extends Component io.dpath.xcpt_privileged := (id_privileged & ~io.dpath.status(5)).toBool; io.dpath.xcpt_fpu := Bool(false); io.dpath.xcpt_syscall := id_syscall.toBool; + io.dpath.xcpt_itlb := id_reg_itlb_xcpt; } } diff --git a/rocket/src/main/scala/dpath.scala b/rocket/src/main/scala/dpath.scala index ce6e651a..d687bb8d 100644 --- a/rocket/src/main/scala/dpath.scala +++ b/rocket/src/main/scala/dpath.scala @@ -5,14 +5,20 @@ import Node._; import Constants._ import Instructions._ +class ioDpathImem extends Bundle() +{ + val req_addr = UFix(VADDR_BITS, 'output); + val resp_data = Bits(32, 'input); +} + class ioDpathAll extends Bundle() { val host = new ioHost(); val ctrl = new ioCtrlDpath().flip(); 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 imem = new ioImem(List("req_addr", "resp_data")).flip(); + val imem = new ioDpathImem(); val ptbr = UFix(PADDR_BITS, 'output); } @@ -243,13 +249,14 @@ class rocketDpath extends Component id_rdata2))))); // write value to cause register based on exception type - val id_exception = io.ctrl.xcpt_illegal || io.ctrl.xcpt_privileged || io.ctrl.xcpt_fpu || io.ctrl.xcpt_syscall; + val id_exception = io.ctrl.xcpt_illegal || io.ctrl.xcpt_privileged || io.ctrl.xcpt_fpu || io.ctrl.xcpt_syscall || io.ctrl.xcpt_itlb; val id_cause = + Mux(io.ctrl.xcpt_itlb, UFix(1,5), Mux(io.ctrl.xcpt_illegal, UFix(2,5), Mux(io.ctrl.xcpt_privileged, UFix(3,5), Mux(io.ctrl.xcpt_fpu, UFix(4,5), Mux(io.ctrl.xcpt_syscall, UFix(6,5), - UFix(0,5))))); + UFix(0,5)))))); io.ctrl.inst := id_reg_inst; diff --git a/rocket/src/main/scala/dpath_util.scala b/rocket/src/main/scala/dpath_util.scala index 7011d88b..b9de3dab 100644 --- a/rocket/src/main/scala/dpath_util.scala +++ b/rocket/src/main/scala/dpath_util.scala @@ -34,7 +34,7 @@ class rocketDpathBTB extends Component class ioDpathPCR extends Bundle() { val host = new ioHost(List("from", "from_wen", "to")); - val debug = new ioDebug(); + val debug = new ioDebug(List("error_mode", "log_control")); val r = new ioReadPort(); val w = new ioWritePort(); diff --git a/rocket/src/main/scala/dtlb.scala b/rocket/src/main/scala/dtlb.scala new file mode 100644 index 00000000..961e6041 --- /dev/null +++ b/rocket/src/main/scala/dtlb.scala @@ -0,0 +1,166 @@ +package Top +{ + +import Chisel._; +import Node._; +import Constants._; +import scala.math._; + +// interface between DTLB and fetch stage of pipeline +class ioDTLB_CPU(view: List[String] = null) extends Bundle(view) +{ + // 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_cmd = Bits(4, 'input); // load/store/amo + val req_rdy = Bool('output); + val req_asid = Bits(ASID_BITS, 'input); + val req_addr = UFix(VADDR_BITS, 'input); + // lookup responses + val resp_val = Bool('output); + val resp_addr = UFix(PADDR_BITS, 'output); + val exception = Bool('output); +} + +class ioDTLB extends Bundle +{ + val cpu = new ioDTLB_CPU(); + val ptw = new ioTLB_PTW(); +} + +class rocketDTLB(entries: Int) extends Component +{ + val addr_bits = ceil(log10(entries)/log10(2)).toInt; + val io = new ioDTLB(); + + 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 req_vpn = io.cpu.req_addr(VADDR_BITS-1,PGIDX_BITS); + val req_idx = io.cpu.req_addr(PGIDX_BITS-1,0); + val req_load = (io.cpu.req_cmd === M_XRD); + val req_store = (io.cpu.req_cmd === M_XWR); +// val req_amo = io.cpu.req_cmd(3).toBool; + + val lookup_tag = Cat(io.cpu.req_asid, 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; // user/supervisor mode + val status_vm = io.cpu.status(16).toBool // virtual memory enable + + // extract fields from PT permission bits +// val ptw_perm_ux = io.ptw.resp_perm(0); + val ptw_perm_ur = io.ptw.resp_perm(1); + val ptw_perm_uw = io.ptw.resp_perm(2); +// val ptw_perm_sx = io.ptw.resp_perm(3); + val ptw_perm_sr = io.ptw.resp_perm(4); + val ptw_perm_sw = io.ptw.resp_perm(5); + + // 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 ur_array = Reg(resetVal = Bits(0, entries)); // user execute permission + val uw_array = Reg(resetVal = Bits(0, entries)); // user execute permission + val sr_array = Reg(resetVal = Bits(0, entries)); // supervisor execute permission + val sw_array = Reg(resetVal = Bits(0, entries)); // supervisor execute permission + when (io.ptw.resp_val) { + ur_array <== ur_array.bitSet(r_refill_waddr, ptw_perm_ur); + uw_array <== ur_array.bitSet(r_refill_waddr, ptw_perm_uw); + sr_array <== sr_array.bitSet(r_refill_waddr, ptw_perm_sr); + sw_array <== sw_array.bitSet(r_refill_waddr, ptw_perm_sw); + } + + // when the page table lookup reports an error, set all permission + // bits to 0 so the next access will cause an exception + when (io.ptw.resp_err) { + ur_array <== ur_array.bitSet(r_refill_waddr, Bool(false)); + uw_array <== ur_array.bitSet(r_refill_waddr, Bool(false)); + sr_array <== sr_array.bitSet(r_refill_waddr, Bool(false)); + sw_array <== sw_array.bitSet(r_refill_waddr, Bool(false)); + } + + // high if there are any unused (invalid) entries in the TLB + 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 dtlb_st_xcpt = + tag_hit && req_load && + ((status_mode && !sw_array(tag_hit_addr).toBool) || + (!status_mode && !uw_array(tag_hit_addr).toBool)); + + val dtlb_ld_xcpt = + tag_hit && req_store && + ((status_mode && !sr_array(tag_hit_addr).toBool) || + (!status_mode && !ur_array(tag_hit_addr).toBool)); + + val dtlb_exception = dtlb_st_xcpt || dtlb_ld_xcpt; + + 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.resp_addr := + Mux(status_vm, Cat(tag_ram(tag_hit_addr), req_idx), + io.cpu.req_addr(PADDR_BITS-1,0)).toUFix; + io.cpu.exception := dtlb_exception; + + io.ptw.req_val := (state === s_request); + io.ptw.req_vpn := r_refill_tag(VPN_BITS-1,0); + + // 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 || io.ptw.resp_err) { + state <== s_ready; + } + } + } +} +} \ No newline at end of file diff --git a/rocket/src/main/scala/icache.scala b/rocket/src/main/scala/icache.scala index 9b68556a..c72c7ca8 100644 --- a/rocket/src/main/scala/icache.scala +++ b/rocket/src/main/scala/icache.scala @@ -5,10 +5,10 @@ import Node._; import Constants._; import scala.math._; -// interface between I$ and processor (32 bits wide) +// interface between I$ and pipeline/ITLB (32 bits wide) class ioImem(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(32, 'output); diff --git a/rocket/src/main/scala/itlb.scala b/rocket/src/main/scala/itlb.scala index 71f6073d..5d80c4cb 100644 --- a/rocket/src/main/scala/itlb.scala +++ b/rocket/src/main/scala/itlb.scala @@ -52,7 +52,7 @@ class ioTLB_PTW extends Bundle } // interface between ITLB and fetch stage of pipeline -class ioITLB_CPU extends Bundle +class ioITLB_CPU(view: List[String] = null) extends Bundle(view) { // status bits (from PCR), to check current permission and whether VM is enabled val status = Bits(17, 'input); @@ -62,10 +62,12 @@ class ioITLB_CPU extends Bundle val req_val = Bool('input); val req_rdy = Bool('output); val req_asid = Bits(ASID_BITS, 'input); - val req_vpn = Bits(VPN_BITS, 'input); +// val req_vpn = Bits(VPN_BITS, 'input); + val req_addr = UFix(VADDR_BITS, 'input); // lookup responses val resp_val = Bool('output); - val resp_ppn = Bits(PPN_BITS, 'output); +// val resp_ppn = Bits(PPN_BITS, 'output); + val resp_addr = UFix(PADDR_BITS, 'output); val exception = Bool('output); } @@ -85,7 +87,9 @@ class rocketITLB(entries: Int) extends Component 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 req_vpn = io.cpu.req_addr(VADDR_BITS-1,PGIDX_BITS); + val req_idx = io.cpu.req_addr(PGIDX_BITS-1,0); + val lookup_tag = Cat(io.cpu.req_asid, 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)); @@ -99,12 +103,12 @@ class rocketITLB(entries: Int) extends Component 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 + val status_mode = io.cpu.status(6).toBool; // user/supervisor mode + val status_vm = io.cpu.status(16).toBool // virtual memory enable // extract fields from PT permission bits - val ptw_perm_ux = io.ptw.resp_perm(4); - val ptw_perm_sx = io.ptw.resp_perm(7); + val ptw_perm_ux = io.ptw.resp_perm(0); + val ptw_perm_sx = io.ptw.resp_perm(3); // valid bit array val vb_array = Reg(resetVal = Bits(0, entries)); @@ -120,7 +124,14 @@ class rocketITLB(entries: Int) extends Component 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); + sx_array <== sx_array.bitSet(r_refill_waddr, ptw_perm_sx); + } + + // when the page table lookup reports an error, set both execute permission + // bits to 0 so the next access will cause an exceptions + when (io.ptw.resp_err) { + ux_array <== ux_array.bitSet(r_refill_waddr, Bool(false)); + sx_array <== sx_array.bitSet(r_refill_waddr, Bool(false)); } // high if there are any unused (invalid) entries in the ITLB @@ -150,11 +161,14 @@ class rocketITLB(entries: Int) extends Component 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.cpu.resp_ppn := Mux(status_vm, io.cpu.req_vpn(PPN_BITS-1, 0), tag_ram(tag_hit_addr)); + io.cpu.resp_addr := + Mux(status_vm, Cat(tag_ram(tag_hit_addr), req_idx), + io.cpu.req_addr(PADDR_BITS-1,0)).toUFix; + io.cpu.exception := status_vm && itlb_exception; io.ptw.req_val := (state === s_request); - io.ptw.req_vpn := r_refill_tag; + io.ptw.req_vpn := r_refill_tag(VPN_BITS-1,0); // control state machine switch (state) { @@ -169,7 +183,7 @@ class rocketITLB(entries: Int) extends Component } } is (s_wait) { - when (io.ptw.resp_val) { + when (io.ptw.resp_val || io.ptw.resp_err) { state <== s_ready; } } diff --git a/rocket/src/main/scala/ptw.scala b/rocket/src/main/scala/ptw.scala index 92cb219e..18fc8912 100644 --- a/rocket/src/main/scala/ptw.scala +++ b/rocket/src/main/scala/ptw.scala @@ -66,7 +66,7 @@ class rocketPTW extends Component 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); + r_resp_ppn <== io.dmem.resp_data(PADDR_BITS-1, PGIDX_BITS); } io.dmem.req_val := @@ -77,13 +77,14 @@ class rocketPTW extends Component io.dmem.req_cmd := M_PRD; io.dmem.req_type := MT_D; io.dmem.req_addr := req_addr; - + + io.itlb.req_rdy := (state === s_ready); 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)), + Mux(state === s_l1_fake, Cat(r_resp_ppn(PPN_BITS-1, PPN_BITS-7), r_req_vpn(VPN_BITS-8, 0)), + Mux(state === s_l2_fake, Cat(r_resp_ppn(PPN_BITS-1, PPN_BITS-17), r_req_vpn(VPN_BITS-18, 0)), r_resp_ppn)); val resp_ptd = (io.dmem.resp_data(1,0) === Bits(1,2));