2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * Copyright (c) 2007 MIPS Technologies, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "arch/riscv/tlb.hh"
35 #include "arch/riscv/faults.hh"
36 #include "arch/riscv/fs_workload.hh"
37 #include "arch/riscv/pagetable.hh"
38 #include "arch/riscv/pra_constants.hh"
39 #include "arch/riscv/utility.hh"
40 #include "base/inifile.hh"
41 #include "base/str.hh"
42 #include "base/trace.hh"
43 #include "cpu/thread_context.hh"
44 #include "debug/RiscvTLB.hh"
45 #include "debug/TLB.hh"
46 #include "mem/page_table.hh"
47 #include "params/RiscvTLB.hh"
48 #include "sim/full_system.hh"
49 #include "sim/process.hh"
50 #include "sim/system.hh"
53 using namespace RiscvISA
;
55 ///////////////////////////////////////////////////////////////////////
60 TLB::TLB(const Params
*p
)
61 : BaseTLB(p
), size(p
->size
), nlu(0)
63 table
= new PTE
[size
];
64 memset(table
, 0, sizeof(PTE
[size
]));
74 // look up an entry in the TLB
76 TLB::lookup(Addr vpn
, uint8_t asn
) const
78 // assume not found...
79 PTE
*retval
= nullptr;
80 PageTable::const_iterator i
= lookupTable
.find(vpn
);
81 if (i
!= lookupTable
.end()) {
82 while (i
->first
== vpn
) {
83 int index
= i
->second
;
84 PTE
*pte
= &table
[index
];
86 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
87 Addr Mask
= pte
->Mask
;
90 if (((vpn
& InvMask
) == (VPN
& InvMask
)) &&
91 (pte
->G
|| (asn
== pte
->asid
))) {
92 // We have a VPN + ASID Match
100 DPRINTF(TLB
, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn
, (int)asn
,
101 retval
? "hit" : "miss", retval
? retval
->PFN1
: 0);
106 TLB::getEntry(unsigned Index
) const
108 // Make sure that Index is valid
110 return &table
[Index
];
114 TLB::probeEntry(Addr vpn
, uint8_t asn
) const
116 // assume not found...
118 PageTable::const_iterator i
= lookupTable
.find(vpn
);
119 if (i
!= lookupTable
.end()) {
120 while (i
->first
== vpn
) {
121 int index
= i
->second
;
122 PTE
*pte
= &table
[index
];
124 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */
125 Addr Mask
= pte
->Mask
;
126 Addr InvMask
= ~Mask
;
128 if (((vpn
& InvMask
) == (VPN
& InvMask
)) &&
129 (pte
->G
|| (asn
== pte
->asid
))) {
130 // We have a VPN + ASID Match
137 DPRINTF(RiscvTLB
,"VPN: %x, asid: %d, Result of TLBP: %d\n",vpn
,asn
,Ind
);
142 TLB::checkCacheability(const RequestPtr
&req
)
144 Addr VAddrUncacheable
= 0xA0000000;
145 // In MIPS, cacheability is controlled by certain bits of the virtual
146 // address or by the TLB entry
147 if ((req
->getVaddr() & VAddrUncacheable
) == VAddrUncacheable
) {
148 // mark request as uncacheable
149 req
->setFlags(Request::UNCACHEABLE
| Request::STRICT_ORDER
);
155 TLB::insertAt(PTE
&pte
, unsigned Index
, int _smallPages
)
157 smallPages
= _smallPages
;
159 warn("Attempted to write at index (%d) beyond TLB size (%d)",
163 DPRINTF(TLB
, "TLB[%d]: %x %x %x %x\n",
164 Index
, pte
.Mask
<< 11,
165 ((pte
.VPN
<< 11) | pte
.asid
),
166 ((pte
.PFN0
<< 6) | (pte
.C0
<< 3) |
167 (pte
.D0
<< 2) | (pte
.V0
<<1) | pte
.G
),
168 ((pte
.PFN1
<<6) | (pte
.C1
<< 3) |
169 (pte
.D1
<< 2) | (pte
.V1
<<1) | pte
.G
));
170 if (table
[Index
].V0
|| table
[Index
].V1
) {
171 // Previous entry is valid
172 PageTable::iterator i
= lookupTable
.find(table
[Index
].VPN
);
173 lookupTable
.erase(i
);
176 // Update fast lookup table
177 lookupTable
.insert(make_pair(table
[Index
].VPN
, Index
));
181 // insert a new TLB entry
183 TLB::insert(Addr addr
, PTE
&pte
)
185 fatal("TLB Insert not yet implemented\n");
191 DPRINTF(TLB
, "flushAll\n");
192 memset(table
, 0, sizeof(PTE
[size
]));
198 TLB::serialize(CheckpointOut
&cp
) const
200 SERIALIZE_SCALAR(size
);
201 SERIALIZE_SCALAR(nlu
);
203 for (int i
= 0; i
< size
; i
++) {
204 ScopedCheckpointSection
sec(cp
, csprintf("PTE%d", i
));
205 table
[i
].serialize(cp
);
210 TLB::unserialize(CheckpointIn
&cp
)
212 UNSERIALIZE_SCALAR(size
);
213 UNSERIALIZE_SCALAR(nlu
);
215 for (int i
= 0; i
< size
; i
++) {
216 ScopedCheckpointSection
sec(cp
, csprintf("PTE%d", i
));
217 table
[i
].unserialize(cp
);
218 if (table
[i
].V0
|| table
[i
].V1
) {
219 lookupTable
.insert(make_pair(table
[i
].VPN
, i
));
230 .name(name() + ".read_hits")
231 .desc("DTB read hits")
235 .name(name() + ".read_misses")
236 .desc("DTB read misses")
241 .name(name() + ".read_accesses")
242 .desc("DTB read accesses")
246 .name(name() + ".write_hits")
247 .desc("DTB write hits")
251 .name(name() + ".write_misses")
252 .desc("DTB write misses")
257 .name(name() + ".write_accesses")
258 .desc("DTB write accesses")
262 .name(name() + ".hits")
267 .name(name() + ".misses")
272 .name(name() + ".accesses")
273 .desc("DTB accesses")
276 hits
= read_hits
+ write_hits
;
277 misses
= read_misses
+ write_misses
;
278 accesses
= read_accesses
+ write_accesses
;
282 TLB::translateInst(const RequestPtr
&req
, ThreadContext
*tc
)
286 * check if we simulate a bare metal system
287 * if so, we have no tlb, phys addr == virt addr
289 auto *workload
= dynamic_cast<FsWorkload
*>(
290 tc
->getSystemPtr()->workload
);
291 if (workload
->isBareMetal())
292 req
->setFlags(Request::PHYSICAL
);
294 if (req
->getFlags() & Request::PHYSICAL
) {
296 * we simply set the virtual address to physical address
298 req
->setPaddr(req
->getVaddr());
299 return checkCacheability(req
);
302 * as we currently support bare metal only, we throw a panic,
303 * if it is not a bare metal system
305 panic("translateInst not implemented in RISC-V.\n");
308 Process
* p
= tc
->getProcessPtr();
310 Fault fault
= p
->pTable
->translate(req
);
311 if (fault
!= NoFault
)
319 TLB::translateData(const RequestPtr
&req
, ThreadContext
*tc
, bool write
)
323 * check if we simulate a bare metal system
324 * if so, we have no tlb, phys addr == virt addr
326 auto *workload
= dynamic_cast<FsWorkload
*>(
327 tc
->getSystemPtr()->workload
);
328 if (workload
->isBareMetal())
329 req
->setFlags(Request::PHYSICAL
);
331 if (req
->getFlags() & Request::PHYSICAL
) {
333 * we simply set the virtual address to physical address
335 req
->setPaddr(req
->getVaddr());
336 return checkCacheability(req
);
339 * as we currently support bare metal only, we throw a panic,
340 * if it is not a bare metal system
342 panic("translateData not implemented in RISC-V.\n");
345 // In the O3 CPU model, sometimes a memory access will be speculatively
346 // executed along a branch that will end up not being taken where the
347 // address is invalid. In that case, return a fault rather than trying
348 // to translate it (which will cause a panic). Since RISC-V allows
349 // unaligned memory accesses, this should only happen if the request's
350 // length is long enough to wrap around from the end of the memory to
352 assert(req
->getSize() > 0);
353 if (req
->getVaddr() + req
->getSize() - 1 < req
->getVaddr())
354 return make_shared
<GenericPageTableFault
>(req
->getVaddr());
356 Process
* p
= tc
->getProcessPtr();
358 Fault fault
= p
->pTable
->translate(req
);
359 if (fault
!= NoFault
)
367 TLB::translateAtomic(const RequestPtr
&req
, ThreadContext
*tc
, Mode mode
)
370 return translateInst(req
, tc
);
372 return translateData(req
, tc
, mode
== Write
);
376 TLB::translateTiming(const RequestPtr
&req
, ThreadContext
*tc
,
377 Translation
*translation
, Mode mode
)
380 translation
->finish(translateAtomic(req
, tc
, mode
), req
, tc
, mode
);
384 TLB::translateFunctional(const RequestPtr
&req
, ThreadContext
*tc
, Mode mode
)
387 "translateFunctional not implemented for full system.");
389 const Addr vaddr
= req
->getVaddr();
390 Process
*process
= tc
->getProcessPtr();
391 const auto *pte
= process
->pTable
->lookup(vaddr
);
393 if (!pte
&& mode
!= Execute
) {
394 // Check if we just need to grow the stack.
395 if (process
->fixupFault(vaddr
)) {
396 // If we did, lookup the entry for the new page.
397 pte
= process
->pTable
->lookup(vaddr
);
402 return std::make_shared
<GenericPageTableFault
>(req
->getVaddr());
404 Addr paddr
= pte
->paddr
| process
->pTable
->pageOffset(vaddr
);
406 DPRINTF(TLB
, "Translated (functional) %#x -> %#x.\n", vaddr
, paddr
);
407 req
->setPaddr(paddr
);
412 TLB::finalizePhysical(const RequestPtr
&req
,
413 ThreadContext
*tc
, Mode mode
) const
420 TLB::index(bool advance
)
422 PTE
*pte
= &table
[nlu
];
431 RiscvTLBParams::create()
433 return new TLB(this);