2012-02-26 02:09:26 +01:00
|
|
|
package rocket
|
2011-11-10 06:54:11 +01:00
|
|
|
|
|
|
|
import Chisel._;
|
|
|
|
import Node._;
|
|
|
|
import Constants._;
|
|
|
|
import scala.math._;
|
2012-02-26 07:05:30 +01:00
|
|
|
import hwacha._
|
2011-11-10 06:54:11 +01:00
|
|
|
|
2012-02-26 07:05:30 +01:00
|
|
|
// ioDTLB_CPU also located in hwacha/src/vuVXU-Interface.scala
|
|
|
|
// should keep them in sync
|
|
|
|
|
2012-02-27 08:46:51 +01:00
|
|
|
class ioDTLB_CPU_req_bundle extends Bundle
|
2011-11-10 06:54:11 +01:00
|
|
|
{
|
|
|
|
// lookup requests
|
2012-02-26 07:05:30 +01:00
|
|
|
val kill = Bool()
|
|
|
|
val cmd = Bits(width=4) // load/store/amo
|
|
|
|
val asid = Bits(width=ASID_BITS)
|
2012-02-26 11:54:16 +01:00
|
|
|
val vpn = Bits(width=VPN_BITS+1)
|
2012-02-26 07:05:30 +01:00
|
|
|
}
|
2012-06-07 03:22:56 +02:00
|
|
|
class ioDTLB_CPU_req extends FIFOIO()( { new ioDTLB_CPU_req_bundle() } )
|
2012-02-26 07:05:30 +01:00
|
|
|
|
|
|
|
class ioDTLB_CPU_resp extends Bundle
|
|
|
|
{
|
2011-11-10 06:54:11 +01:00
|
|
|
// lookup responses
|
2012-02-26 07:05:30 +01:00
|
|
|
val miss = Bool(OUTPUT)
|
2012-07-13 03:12:49 +02:00
|
|
|
val ppn = Bits(OUTPUT, PPN_BITS)
|
2012-02-26 07:05:30 +01:00
|
|
|
val xcpt_ld = Bool(OUTPUT)
|
|
|
|
val xcpt_st = Bool(OUTPUT)
|
2012-03-18 23:06:39 +01:00
|
|
|
val xcpt_pf = Bool(OUTPUT)
|
2011-11-10 06:54:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
class ioDTLB extends Bundle
|
|
|
|
{
|
2012-02-26 07:05:30 +01:00
|
|
|
// status bits (from PCR), to check current permission and whether VM is enabled
|
2012-07-13 03:12:49 +02:00
|
|
|
val status = Bits(INPUT, 32)
|
2012-02-26 07:05:30 +01:00
|
|
|
// invalidate all TLB entries
|
|
|
|
val invalidate = Bool(INPUT)
|
2012-03-02 05:48:46 +01:00
|
|
|
val cpu_req = new ioDTLB_CPU_req().flip
|
2012-02-26 07:05:30 +01:00
|
|
|
val cpu_resp = new ioDTLB_CPU_resp()
|
|
|
|
val ptw = new ioTLB_PTW()
|
2011-11-10 06:54:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
class rocketDTLB(entries: Int) extends Component
|
|
|
|
{
|
|
|
|
val io = new ioDTLB();
|
|
|
|
|
2011-11-12 03:18:47 +01:00
|
|
|
val addr_bits = ceil(log10(entries)/log10(2)).toInt;
|
|
|
|
|
2011-11-10 06:54:11 +01:00
|
|
|
val s_ready :: s_request :: s_wait :: Nil = Enum(3) { UFix() };
|
|
|
|
val state = Reg(resetVal = s_ready);
|
|
|
|
|
2011-11-12 03:18:47 +01:00
|
|
|
val r_cpu_req_val = Reg(resetVal = Bool(false));
|
2012-01-02 01:09:40 +01:00
|
|
|
val r_cpu_req_vpn = Reg() { Bits() }
|
|
|
|
val r_cpu_req_cmd = Reg() { Bits() }
|
|
|
|
val r_cpu_req_asid = Reg() { Bits() }
|
|
|
|
val r_refill_tag = Reg() { Bits() }
|
|
|
|
val r_refill_waddr = Reg() { UFix() }
|
2011-11-12 03:18:47 +01:00
|
|
|
|
2012-02-26 07:05:30 +01:00
|
|
|
when (io.cpu_req.valid && io.cpu_req.ready) {
|
|
|
|
r_cpu_req_vpn := io.cpu_req.bits.vpn;
|
|
|
|
r_cpu_req_cmd := io.cpu_req.bits.cmd;
|
|
|
|
r_cpu_req_asid := io.cpu_req.bits.asid;
|
2012-02-12 02:20:33 +01:00
|
|
|
r_cpu_req_val := Bool(true);
|
2011-11-12 03:18:47 +01:00
|
|
|
}
|
2012-02-12 02:20:33 +01:00
|
|
|
.otherwise {
|
|
|
|
r_cpu_req_val := Bool(false);
|
2011-11-12 03:18:47 +01:00
|
|
|
}
|
2011-11-10 06:54:11 +01:00
|
|
|
|
2011-11-12 03:18:47 +01:00
|
|
|
val req_load = (r_cpu_req_cmd === M_XRD);
|
|
|
|
val req_store = (r_cpu_req_cmd === M_XWR);
|
2011-12-17 12:26:11 +01:00
|
|
|
val req_amo = r_cpu_req_cmd(3).toBool;
|
2012-02-26 07:05:30 +01:00
|
|
|
val req_pf = (r_cpu_req_cmd === M_PFR) || (r_cpu_req_cmd === M_PFW)
|
2011-11-10 06:54:11 +01:00
|
|
|
|
2012-01-24 09:15:17 +01:00
|
|
|
val bad_va = r_cpu_req_vpn(VPN_BITS) != r_cpu_req_vpn(VPN_BITS-1);
|
2011-11-12 03:18:47 +01:00
|
|
|
|
2011-12-06 00:45:44 +01:00
|
|
|
val tag_cam = new rocketCAM(entries, ASID_BITS+VPN_BITS);
|
2012-06-06 11:47:22 +02:00
|
|
|
val tag_ram = Mem(entries) { io.ptw.resp_ppn.clone }
|
|
|
|
when (io.ptw.resp_val) { tag_ram(r_refill_waddr) := io.ptw.resp_ppn }
|
2011-11-10 06:54:11 +01:00
|
|
|
|
2012-01-24 09:15:17 +01:00
|
|
|
val lookup_tag = Cat(r_cpu_req_asid, r_cpu_req_vpn);
|
2012-02-26 07:05:30 +01:00
|
|
|
tag_cam.io.clear := io.invalidate;
|
2012-04-17 07:28:00 +02:00
|
|
|
tag_cam.io.clear_hit := io.cpu_resp.xcpt_ld || io.cpu_resp.xcpt_st || io.cpu_resp.xcpt_pf
|
2011-11-10 06:54:11 +01:00
|
|
|
tag_cam.io.tag := lookup_tag;
|
2011-11-13 00:47:47 +01:00
|
|
|
tag_cam.io.write := io.ptw.resp_val || io.ptw.resp_err;
|
2011-11-10 06:54:11 +01:00
|
|
|
tag_cam.io.write_tag := r_refill_tag;
|
|
|
|
tag_cam.io.write_addr := r_refill_waddr;
|
2012-01-24 09:15:17 +01:00
|
|
|
val tag_hit = tag_cam.io.hit || bad_va;
|
2011-11-11 02:41:22 +01:00
|
|
|
val tag_hit_addr = tag_cam.io.hit_addr;
|
2011-11-10 06:54:11 +01:00
|
|
|
|
|
|
|
// extract fields from status register
|
2012-02-26 07:05:30 +01:00
|
|
|
val status_s = io.status(SR_S).toBool; // user/supervisor mode
|
2011-11-11 02:41:22 +01:00
|
|
|
val status_u = !status_s;
|
2012-02-26 07:05:30 +01:00
|
|
|
val status_vm = io.status(SR_VM).toBool // virtual memory enable
|
2011-11-10 06:54:11 +01:00
|
|
|
|
|
|
|
// extract fields from PT permission bits
|
2011-11-17 20:17:37 +01:00
|
|
|
val ptw_perm_ur = io.ptw.resp_perm(2);
|
|
|
|
val ptw_perm_uw = io.ptw.resp_perm(1);
|
|
|
|
val ptw_perm_sr = io.ptw.resp_perm(5);
|
|
|
|
val ptw_perm_sw = io.ptw.resp_perm(4);
|
2011-11-10 06:54:11 +01:00
|
|
|
|
|
|
|
// permission bit arrays
|
2011-11-12 03:18:47 +01:00
|
|
|
val ur_array = Reg(resetVal = Bits(0, entries)); // user read permission
|
|
|
|
val uw_array = Reg(resetVal = Bits(0, entries)); // user write permission
|
|
|
|
val sr_array = Reg(resetVal = Bits(0, entries)); // supervisor read permission
|
|
|
|
val sw_array = Reg(resetVal = Bits(0, entries)); // supervisor write permission
|
2011-11-10 06:54:11 +01:00
|
|
|
when (io.ptw.resp_val) {
|
2012-02-12 02:20:33 +01:00
|
|
|
ur_array := ur_array.bitSet(r_refill_waddr, ptw_perm_ur);
|
|
|
|
uw_array := uw_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);
|
2011-11-10 06:54:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
2012-02-12 02:20:33 +01:00
|
|
|
ur_array := ur_array.bitSet(r_refill_waddr, Bool(false));
|
|
|
|
uw_array := uw_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));
|
2011-11-10 06:54:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// high if there are any unused (invalid) entries in the TLB
|
2012-03-01 01:13:14 +01:00
|
|
|
val has_invalid_entry = !tag_cam.io.valid_bits.andR
|
|
|
|
val invalid_entry = PriorityEncoder(~tag_cam.io.valid_bits)
|
2012-04-17 07:28:56 +02:00
|
|
|
val plru = new PseudoLRU(entries)
|
|
|
|
val repl_waddr = Mux(has_invalid_entry, invalid_entry, plru.replace).toUFix;
|
2011-11-10 06:54:11 +01:00
|
|
|
|
2012-02-26 07:05:30 +01:00
|
|
|
val lookup = (state === s_ready) && r_cpu_req_val && !io.cpu_req.bits.kill && (req_load || req_store || req_amo || req_pf);
|
2011-11-13 08:39:43 +01:00
|
|
|
val lookup_hit = lookup && tag_hit;
|
|
|
|
val lookup_miss = lookup && !tag_hit;
|
2011-11-11 02:41:22 +01:00
|
|
|
val tlb_hit = status_vm && lookup_hit;
|
|
|
|
val tlb_miss = status_vm && lookup_miss;
|
|
|
|
|
2011-11-12 03:18:47 +01:00
|
|
|
// currently replace TLB entries in LIFO order
|
|
|
|
// TODO: implement LRU replacement policy
|
2011-11-11 02:41:22 +01:00
|
|
|
when (tlb_miss) {
|
2012-02-12 02:20:33 +01:00
|
|
|
r_refill_tag := lookup_tag;
|
|
|
|
r_refill_waddr := repl_waddr;
|
2012-04-17 07:28:56 +02:00
|
|
|
}
|
|
|
|
when (tlb_hit) {
|
|
|
|
plru.access(tag_hit_addr)
|
2011-11-10 06:54:11 +01:00
|
|
|
}
|
|
|
|
|
2012-04-17 06:20:25 +02:00
|
|
|
val load_fault_common = tlb_hit &&
|
2012-03-18 23:06:39 +01:00
|
|
|
((status_s && !sr_array(tag_hit_addr)) ||
|
|
|
|
(status_u && !ur_array(tag_hit_addr)) ||
|
|
|
|
bad_va)
|
2012-04-17 06:20:25 +02:00
|
|
|
val store_fault_common = tlb_hit &&
|
|
|
|
((status_s && !sw_array(tag_hit_addr)) ||
|
|
|
|
(status_u && !uw_array(tag_hit_addr)) ||
|
|
|
|
bad_va)
|
2011-11-10 06:54:11 +01:00
|
|
|
|
2012-04-17 06:20:25 +02:00
|
|
|
io.cpu_resp.xcpt_ld := load_fault_common && (req_load || req_amo)
|
|
|
|
io.cpu_resp.xcpt_st := store_fault_common && (req_store || req_amo)
|
|
|
|
io.cpu_resp.xcpt_pf := load_fault_common && req_pf
|
2011-11-13 08:39:43 +01:00
|
|
|
|
2012-02-26 07:05:30 +01:00
|
|
|
io.cpu_req.ready := (state === s_ready) && !tlb_miss;
|
|
|
|
io.cpu_resp.miss := tlb_miss;
|
|
|
|
io.cpu_resp.ppn :=
|
2012-02-26 11:54:16 +01:00
|
|
|
Mux(status_vm, tag_ram(tag_hit_addr), r_cpu_req_vpn(PPN_BITS-1,0));
|
2011-11-10 06:54:11 +01:00
|
|
|
|
|
|
|
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) {
|
2011-11-11 02:41:22 +01:00
|
|
|
when (tlb_miss) {
|
2012-02-12 02:20:33 +01:00
|
|
|
state := s_request;
|
2011-11-10 06:54:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
is (s_request) {
|
|
|
|
when (io.ptw.req_rdy) {
|
2012-02-12 02:20:33 +01:00
|
|
|
state := s_wait;
|
2011-11-10 06:54:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
is (s_wait) {
|
|
|
|
when (io.ptw.resp_val || io.ptw.resp_err) {
|
2012-02-12 02:20:33 +01:00
|
|
|
state := s_ready;
|
2011-11-10 06:54:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|