tlb.cc (3906:4cf7d8d42349) tlb.cc (3907:00f18b4eedb5)
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Ali Saidi
29 */
30
31#include "arch/sparc/asi.hh"
32#include "arch/sparc/miscregfile.hh"
33#include "arch/sparc/tlb.hh"
34#include "base/bitfield.hh"
35#include "base/trace.hh"
36#include "cpu/thread_context.hh"
37#include "cpu/base.hh"
38#include "mem/packet_access.hh"
39#include "mem/request.hh"
40#include "sim/builder.hh"
41
42/* @todo remove some of the magic constants. -- ali
43 * */
44namespace SparcISA
45{
46
47TLB::TLB(const std::string &name, int s)
48 : SimObject(name), size(s), usedEntries(0), lastReplaced(0),
49 cacheValid(false)
50{
51 // To make this work you'll have to change the hypervisor and OS
52 if (size > 64)
53 fatal("SPARC T1 TLB registers don't support more than 64 TLB entries.");
54
55 tlb = new TlbEntry[size];
56 memset(tlb, 0, sizeof(TlbEntry) * size);
57
58 for (int x = 0; x < size; x++)
59 freeList.push_back(&tlb[x]);
60}
61
62void
63TLB::clearUsedBits()
64{
65 MapIter i;
66 for (i = lookupTable.begin(); i != lookupTable.end(); i++) {
67 TlbEntry *t = i->second;
68 if (!t->pte.locked()) {
69 t->used = false;
70 usedEntries--;
71 }
72 }
73}
74
75
76void
77TLB::insert(Addr va, int partition_id, int context_id, bool real,
78 const PageTableEntry& PTE, int entry)
79{
80
81
82 MapIter i;
83 TlbEntry *new_entry = NULL;
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Ali Saidi
29 */
30
31#include "arch/sparc/asi.hh"
32#include "arch/sparc/miscregfile.hh"
33#include "arch/sparc/tlb.hh"
34#include "base/bitfield.hh"
35#include "base/trace.hh"
36#include "cpu/thread_context.hh"
37#include "cpu/base.hh"
38#include "mem/packet_access.hh"
39#include "mem/request.hh"
40#include "sim/builder.hh"
41
42/* @todo remove some of the magic constants. -- ali
43 * */
44namespace SparcISA
45{
46
47TLB::TLB(const std::string &name, int s)
48 : SimObject(name), size(s), usedEntries(0), lastReplaced(0),
49 cacheValid(false)
50{
51 // To make this work you'll have to change the hypervisor and OS
52 if (size > 64)
53 fatal("SPARC T1 TLB registers don't support more than 64 TLB entries.");
54
55 tlb = new TlbEntry[size];
56 memset(tlb, 0, sizeof(TlbEntry) * size);
57
58 for (int x = 0; x < size; x++)
59 freeList.push_back(&tlb[x]);
60}
61
62void
63TLB::clearUsedBits()
64{
65 MapIter i;
66 for (i = lookupTable.begin(); i != lookupTable.end(); i++) {
67 TlbEntry *t = i->second;
68 if (!t->pte.locked()) {
69 t->used = false;
70 usedEntries--;
71 }
72 }
73}
74
75
76void
77TLB::insert(Addr va, int partition_id, int context_id, bool real,
78 const PageTableEntry& PTE, int entry)
79{
80
81
82 MapIter i;
83 TlbEntry *new_entry = NULL;
84 TlbRange tr;
84// TlbRange tr;
85 int x;
86
87 cacheValid = false;
85 int x;
86
87 cacheValid = false;
88 tr.va = va;
88 /* tr.va = va;
89 tr.size = PTE.size() - 1;
90 tr.contextId = context_id;
91 tr.partitionId = partition_id;
92 tr.real = real;
89 tr.size = PTE.size() - 1;
90 tr.contextId = context_id;
91 tr.partitionId = partition_id;
92 tr.real = real;
93*/
93
94
94
95 DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n",
96 va, PTE.paddr(), partition_id, context_id, (int)real, entry);
97
98 // Demap any entry that conflicts
95 DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n",
96 va, PTE.paddr(), partition_id, context_id, (int)real, entry);
97
98 // Demap any entry that conflicts
99 for (x = 0; x < size; x++) {
100 if (tlb[x].range.real == real &&
101 tlb[x].range.partitionId == partition_id &&
102 tlb[x].range.va < va + PTE.size() - 1 &&
103 tlb[x].range.va + tlb[x].range.size >= va &&
104 (real || tlb[x].range.contextId == context_id ))
105 {
106 if (tlb[x].valid) {
107 freeList.push_front(&tlb[x]);
108 DPRINTF(TLB, "TLB: Conflicting entry %#X , deleting it\n", x);
109
110 tlb[x].valid = false;
111 if (tlb[x].used) {
112 tlb[x].used = false;
113 usedEntries--;
114 }
115 lookupTable.erase(tlb[x].range);
116 }
117 }
118 }
119
120
121/*
99 i = lookupTable.find(tr);
100 if (i != lookupTable.end()) {
101 i->second->valid = false;
102 if (i->second->used) {
103 i->second->used = false;
104 usedEntries--;
105 }
106 freeList.push_front(i->second);
107 DPRINTF(TLB, "TLB: Found conflicting entry %#X , deleting it\n",
108 i->second);
109 lookupTable.erase(i);
110 }
122 i = lookupTable.find(tr);
123 if (i != lookupTable.end()) {
124 i->second->valid = false;
125 if (i->second->used) {
126 i->second->used = false;
127 usedEntries--;
128 }
129 freeList.push_front(i->second);
130 DPRINTF(TLB, "TLB: Found conflicting entry %#X , deleting it\n",
131 i->second);
132 lookupTable.erase(i);
133 }
134*/
111
135
112
113 if (entry != -1) {
114 assert(entry < size && entry >= 0);
115 new_entry = &tlb[entry];
116 } else {
117 if (!freeList.empty()) {
118 new_entry = freeList.front();
119 } else {
120 x = lastReplaced;
121 do {
122 ++x;
123 if (x == size)
124 x = 0;
125 if (x == lastReplaced)
126 goto insertAllLocked;
127 } while (tlb[x].pte.locked());
128 lastReplaced = x;
129 new_entry = &tlb[x];
136 if (entry != -1) {
137 assert(entry < size && entry >= 0);
138 new_entry = &tlb[entry];
139 } else {
140 if (!freeList.empty()) {
141 new_entry = freeList.front();
142 } else {
143 x = lastReplaced;
144 do {
145 ++x;
146 if (x == size)
147 x = 0;
148 if (x == lastReplaced)
149 goto insertAllLocked;
150 } while (tlb[x].pte.locked());
151 lastReplaced = x;
152 new_entry = &tlb[x];
130 lookupTable.erase(new_entry->range);
131 }
132 /*
133 for (x = 0; x < size; x++) {
134 if (!tlb[x].valid || !tlb[x].used) {
135 new_entry = &tlb[x];
136 break;
137 }
138 }*/
139 }
140
141insertAllLocked:
142 // Update the last ently if their all locked
143 if (!new_entry) {
144 new_entry = &tlb[size-1];
153 }
154 /*
155 for (x = 0; x < size; x++) {
156 if (!tlb[x].valid || !tlb[x].used) {
157 new_entry = &tlb[x];
158 break;
159 }
160 }*/
161 }
162
163insertAllLocked:
164 // Update the last ently if their all locked
165 if (!new_entry) {
166 new_entry = &tlb[size-1];
145 lookupTable.erase(new_entry->range);
146 }
147
148 freeList.remove(new_entry);
167 }
168
169 freeList.remove(new_entry);
170 if (new_entry->valid && new_entry->used)
171 usedEntries--;
172
173 lookupTable.erase(new_entry->range);
174
175
149 DPRINTF(TLB, "Using entry: %#X\n", new_entry);
150
151 assert(PTE.valid());
152 new_entry->range.va = va;
153 new_entry->range.size = PTE.size() - 1;
154 new_entry->range.partitionId = partition_id;
155 new_entry->range.contextId = context_id;
156 new_entry->range.real = real;
157 new_entry->pte = PTE;
158 new_entry->used = true;;
159 new_entry->valid = true;
160 usedEntries++;
161
162
163
164 i = lookupTable.insert(new_entry->range, new_entry);
165 assert(i != lookupTable.end());
166
167 // If all entries have there used bit set, clear it on them all, but the
168 // one we just inserted
169 if (usedEntries == size) {
170 clearUsedBits();
171 new_entry->used = true;
172 usedEntries++;
173 }
174
175}
176
177
178TlbEntry*
179TLB::lookup(Addr va, int partition_id, bool real, int context_id)
180{
181 MapIter i;
182 TlbRange tr;
183 TlbEntry *t;
184
185 DPRINTF(TLB, "TLB: Looking up entry va=%#x pid=%d cid=%d r=%d\n",
186 va, partition_id, context_id, real);
187 // Assemble full address structure
188 tr.va = va;
189 tr.size = MachineBytes;
190 tr.contextId = context_id;
191 tr.partitionId = partition_id;
192 tr.real = real;
193
194 // Try to find the entry
195 i = lookupTable.find(tr);
196 if (i == lookupTable.end()) {
197 DPRINTF(TLB, "TLB: No valid entry found\n");
198 return NULL;
199 }
200
201 // Mark the entries used bit and clear other used bits in needed
202 t = i->second;
203 DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(),
204 t->pte.size());
205 if (!t->used) {
206 t->used = true;
207 usedEntries++;
208 if (usedEntries == size) {
209 clearUsedBits();
210 t->used = true;
211 usedEntries++;
212 }
213 }
214
215 return t;
216}
217
218void
219TLB::dumpAll()
220{
221 MapIter i;
222 for (int x = 0; x < size; x++) {
223 if (tlb[x].valid) {
224 DPRINTFN("%4d: %#2x:%#2x %c %#4x %#8x %#8x %#16x\n",
225 x, tlb[x].range.partitionId, tlb[x].range.contextId,
226 tlb[x].range.real ? 'R' : ' ', tlb[x].range.size,
227 tlb[x].range.va, tlb[x].pte.paddr(), tlb[x].pte());
228 }
229 }
230}
231
232void
233TLB::demapPage(Addr va, int partition_id, bool real, int context_id)
234{
235 TlbRange tr;
236 MapIter i;
237
238 DPRINTF(IPR, "TLB: Demapping Page va=%#x pid=%#d cid=%d r=%d\n",
239 va, partition_id, context_id, real);
240
241 cacheValid = false;
242
243 // Assemble full address structure
244 tr.va = va;
245 tr.size = MachineBytes;
246 tr.contextId = context_id;
247 tr.partitionId = partition_id;
248 tr.real = real;
249
250 // Demap any entry that conflicts
251 i = lookupTable.find(tr);
252 if (i != lookupTable.end()) {
253 DPRINTF(IPR, "TLB: Demapped page\n");
254 i->second->valid = false;
255 if (i->second->used) {
256 i->second->used = false;
257 usedEntries--;
258 }
259 freeList.push_front(i->second);
260 DPRINTF(TLB, "Freeing TLB entry : %#X\n", i->second);
261 lookupTable.erase(i);
262 }
263}
264
265void
266TLB::demapContext(int partition_id, int context_id)
267{
268 int x;
269 DPRINTF(IPR, "TLB: Demapping Context pid=%#d cid=%d\n",
270 partition_id, context_id);
271 cacheValid = false;
272 for (x = 0; x < size; x++) {
273 if (tlb[x].range.contextId == context_id &&
274 tlb[x].range.partitionId == partition_id) {
275 if (tlb[x].valid == true) {
276 freeList.push_front(&tlb[x]);
277 DPRINTF(TLB, "Freeing TLB entry : %#X\n", &tlb[x]);
278 }
279 tlb[x].valid = false;
280 if (tlb[x].used) {
281 tlb[x].used = false;
282 usedEntries--;
283 }
284 lookupTable.erase(tlb[x].range);
285 }
286 }
287}
288
289void
290TLB::demapAll(int partition_id)
291{
292 int x;
293 DPRINTF(TLB, "TLB: Demapping All pid=%#d\n", partition_id);
294 cacheValid = false;
295 for (x = 0; x < size; x++) {
296 if (!tlb[x].pte.locked() && tlb[x].range.partitionId == partition_id) {
297 if (tlb[x].valid == true){
298 freeList.push_front(&tlb[x]);
299 DPRINTF(TLB, "Freeing TLB entry : %#X\n", &tlb[x]);
300 }
301 tlb[x].valid = false;
302 if (tlb[x].used) {
303 tlb[x].used = false;
304 usedEntries--;
305 }
306 lookupTable.erase(tlb[x].range);
307 }
308 }
309}
310
311void
312TLB::invalidateAll()
313{
314 int x;
315 cacheValid = false;
316
317 freeList.clear();
176 DPRINTF(TLB, "Using entry: %#X\n", new_entry);
177
178 assert(PTE.valid());
179 new_entry->range.va = va;
180 new_entry->range.size = PTE.size() - 1;
181 new_entry->range.partitionId = partition_id;
182 new_entry->range.contextId = context_id;
183 new_entry->range.real = real;
184 new_entry->pte = PTE;
185 new_entry->used = true;;
186 new_entry->valid = true;
187 usedEntries++;
188
189
190
191 i = lookupTable.insert(new_entry->range, new_entry);
192 assert(i != lookupTable.end());
193
194 // If all entries have there used bit set, clear it on them all, but the
195 // one we just inserted
196 if (usedEntries == size) {
197 clearUsedBits();
198 new_entry->used = true;
199 usedEntries++;
200 }
201
202}
203
204
205TlbEntry*
206TLB::lookup(Addr va, int partition_id, bool real, int context_id)
207{
208 MapIter i;
209 TlbRange tr;
210 TlbEntry *t;
211
212 DPRINTF(TLB, "TLB: Looking up entry va=%#x pid=%d cid=%d r=%d\n",
213 va, partition_id, context_id, real);
214 // Assemble full address structure
215 tr.va = va;
216 tr.size = MachineBytes;
217 tr.contextId = context_id;
218 tr.partitionId = partition_id;
219 tr.real = real;
220
221 // Try to find the entry
222 i = lookupTable.find(tr);
223 if (i == lookupTable.end()) {
224 DPRINTF(TLB, "TLB: No valid entry found\n");
225 return NULL;
226 }
227
228 // Mark the entries used bit and clear other used bits in needed
229 t = i->second;
230 DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(),
231 t->pte.size());
232 if (!t->used) {
233 t->used = true;
234 usedEntries++;
235 if (usedEntries == size) {
236 clearUsedBits();
237 t->used = true;
238 usedEntries++;
239 }
240 }
241
242 return t;
243}
244
245void
246TLB::dumpAll()
247{
248 MapIter i;
249 for (int x = 0; x < size; x++) {
250 if (tlb[x].valid) {
251 DPRINTFN("%4d: %#2x:%#2x %c %#4x %#8x %#8x %#16x\n",
252 x, tlb[x].range.partitionId, tlb[x].range.contextId,
253 tlb[x].range.real ? 'R' : ' ', tlb[x].range.size,
254 tlb[x].range.va, tlb[x].pte.paddr(), tlb[x].pte());
255 }
256 }
257}
258
259void
260TLB::demapPage(Addr va, int partition_id, bool real, int context_id)
261{
262 TlbRange tr;
263 MapIter i;
264
265 DPRINTF(IPR, "TLB: Demapping Page va=%#x pid=%#d cid=%d r=%d\n",
266 va, partition_id, context_id, real);
267
268 cacheValid = false;
269
270 // Assemble full address structure
271 tr.va = va;
272 tr.size = MachineBytes;
273 tr.contextId = context_id;
274 tr.partitionId = partition_id;
275 tr.real = real;
276
277 // Demap any entry that conflicts
278 i = lookupTable.find(tr);
279 if (i != lookupTable.end()) {
280 DPRINTF(IPR, "TLB: Demapped page\n");
281 i->second->valid = false;
282 if (i->second->used) {
283 i->second->used = false;
284 usedEntries--;
285 }
286 freeList.push_front(i->second);
287 DPRINTF(TLB, "Freeing TLB entry : %#X\n", i->second);
288 lookupTable.erase(i);
289 }
290}
291
292void
293TLB::demapContext(int partition_id, int context_id)
294{
295 int x;
296 DPRINTF(IPR, "TLB: Demapping Context pid=%#d cid=%d\n",
297 partition_id, context_id);
298 cacheValid = false;
299 for (x = 0; x < size; x++) {
300 if (tlb[x].range.contextId == context_id &&
301 tlb[x].range.partitionId == partition_id) {
302 if (tlb[x].valid == true) {
303 freeList.push_front(&tlb[x]);
304 DPRINTF(TLB, "Freeing TLB entry : %#X\n", &tlb[x]);
305 }
306 tlb[x].valid = false;
307 if (tlb[x].used) {
308 tlb[x].used = false;
309 usedEntries--;
310 }
311 lookupTable.erase(tlb[x].range);
312 }
313 }
314}
315
316void
317TLB::demapAll(int partition_id)
318{
319 int x;
320 DPRINTF(TLB, "TLB: Demapping All pid=%#d\n", partition_id);
321 cacheValid = false;
322 for (x = 0; x < size; x++) {
323 if (!tlb[x].pte.locked() && tlb[x].range.partitionId == partition_id) {
324 if (tlb[x].valid == true){
325 freeList.push_front(&tlb[x]);
326 DPRINTF(TLB, "Freeing TLB entry : %#X\n", &tlb[x]);
327 }
328 tlb[x].valid = false;
329 if (tlb[x].used) {
330 tlb[x].used = false;
331 usedEntries--;
332 }
333 lookupTable.erase(tlb[x].range);
334 }
335 }
336}
337
338void
339TLB::invalidateAll()
340{
341 int x;
342 cacheValid = false;
343
344 freeList.clear();
345 lookupTable.clear();
318 for (x = 0; x < size; x++) {
319 if (tlb[x].valid == true)
320 freeList.push_back(&tlb[x]);
321 tlb[x].valid = false;
346 for (x = 0; x < size; x++) {
347 if (tlb[x].valid == true)
348 freeList.push_back(&tlb[x]);
349 tlb[x].valid = false;
350 tlb[x].used = false;
322 }
323 usedEntries = 0;
324}
325
326uint64_t
327TLB::TteRead(int entry) {
328 if (entry >= size)
329 panic("entry: %d\n", entry);
330
331 assert(entry < size);
332 if (tlb[entry].valid)
333 return tlb[entry].pte();
334 else
335 return (uint64_t)-1ll;
336}
337
338uint64_t
339TLB::TagRead(int entry) {
340 assert(entry < size);
341 uint64_t tag;
342 if (!tlb[entry].valid)
343 return (uint64_t)-1ll;
344
345 tag = tlb[entry].range.contextId;
346 tag |= tlb[entry].range.va;
347 tag |= (uint64_t)tlb[entry].range.partitionId << 61;
348 tag |= tlb[entry].range.real ? ULL(1) << 60 : 0;
349 tag |= (uint64_t)~tlb[entry].pte._size() << 56;
350 return tag;
351}
352
353bool
354TLB::validVirtualAddress(Addr va, bool am)
355{
356 if (am)
357 return true;
358 if (va >= StartVAddrHole && va <= EndVAddrHole)
359 return false;
360 return true;
361}
362
363void
364TLB::writeSfsr(ThreadContext *tc, int reg, bool write, ContextType ct,
365 bool se, FaultTypes ft, int asi)
366{
367 uint64_t sfsr;
368 sfsr = tc->readMiscReg(reg);
369
370 if (sfsr & 0x1)
371 sfsr = 0x3;
372 else
373 sfsr = 1;
374
375 if (write)
376 sfsr |= 1 << 2;
377 sfsr |= ct << 4;
378 if (se)
379 sfsr |= 1 << 6;
380 sfsr |= ft << 7;
381 sfsr |= asi << 16;
382 tc->setMiscRegWithEffect(reg, sfsr);
383}
384
385void
386TLB::writeTagAccess(ThreadContext *tc, int reg, Addr va, int context)
387{
388 tc->setMiscRegWithEffect(reg, mbits(va, 63,13) | mbits(context,12,0));
389}
390
391void
392ITB::writeSfsr(ThreadContext *tc, bool write, ContextType ct,
393 bool se, FaultTypes ft, int asi)
394{
395 DPRINTF(TLB, "TLB: ITB Fault: w=%d ct=%d ft=%d asi=%d\n",
396 (int)write, ct, ft, asi);
397 TLB::writeSfsr(tc, MISCREG_MMU_ITLB_SFSR, write, ct, se, ft, asi);
398}
399
400void
401ITB::writeTagAccess(ThreadContext *tc, Addr va, int context)
402{
403 TLB::writeTagAccess(tc, MISCREG_MMU_ITLB_TAG_ACCESS, va, context);
404}
405
406void
407DTB::writeSfr(ThreadContext *tc, Addr a, bool write, ContextType ct,
408 bool se, FaultTypes ft, int asi)
409{
410 DPRINTF(TLB, "TLB: DTB Fault: A=%#x w=%d ct=%d ft=%d asi=%d\n",
411 a, (int)write, ct, ft, asi);
412 TLB::writeSfsr(tc, MISCREG_MMU_DTLB_SFSR, write, ct, se, ft, asi);
413 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_SFAR, a);
414}
415
416void
417DTB::writeTagAccess(ThreadContext *tc, Addr va, int context)
418{
419 TLB::writeTagAccess(tc, MISCREG_MMU_DTLB_TAG_ACCESS, va, context);
420}
421
422
423
424Fault
425ITB::translate(RequestPtr &req, ThreadContext *tc)
426{
427 uint64_t tlbdata = tc->readMiscReg(MISCREG_TLB_DATA);
428
429 Addr vaddr = req->getVaddr();
430 TlbEntry *e;
431
432 assert(req->getAsi() == ASI_IMPLICIT);
433
434 DPRINTF(TLB, "TLB: ITB Request to translate va=%#x size=%d\n",
435 vaddr, req->getSize());
436
437 // Be fast if we can!
438 if (cacheValid && cacheState == tlbdata) {
439 if (cacheEntry) {
440 if (cacheEntry->range.va < vaddr + sizeof(MachInst) &&
441 cacheEntry->range.va + cacheEntry->range.size >= vaddr) {
442 req->setPaddr(cacheEntry->pte.paddr() & ~(cacheEntry->pte.size()-1) |
443 vaddr & cacheEntry->pte.size()-1 );
444 return NoFault;
445 }
446 } else {
447 req->setPaddr(vaddr & PAddrImplMask);
448 return NoFault;
449 }
450 }
451
452 bool hpriv = bits(tlbdata,0,0);
453 bool red = bits(tlbdata,1,1);
454 bool priv = bits(tlbdata,2,2);
455 bool addr_mask = bits(tlbdata,3,3);
456 bool lsu_im = bits(tlbdata,4,4);
457
458 int part_id = bits(tlbdata,15,8);
459 int tl = bits(tlbdata,18,16);
460 int pri_context = bits(tlbdata,47,32);
461 int context;
462 ContextType ct;
463 int asi;
464 bool real = false;
465
466 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsuim:%d part_id: %#X\n",
467 priv, hpriv, red, lsu_im, part_id);
468
469 if (tl > 0) {
470 asi = ASI_N;
471 ct = Nucleus;
472 context = 0;
473 } else {
474 asi = ASI_P;
475 ct = Primary;
476 context = pri_context;
477 }
478
479 if ( hpriv || red ) {
480 cacheValid = true;
481 cacheState = tlbdata;
482 cacheEntry = NULL;
483 req->setPaddr(vaddr & PAddrImplMask);
484 return NoFault;
485 }
486
487 // If the access is unaligned trap
488 if (vaddr & 0x3) {
489 writeSfsr(tc, false, ct, false, OtherFault, asi);
490 return new MemAddressNotAligned;
491 }
492
493 if (addr_mask)
494 vaddr = vaddr & VAddrAMask;
495
496 if (!validVirtualAddress(vaddr, addr_mask)) {
497 writeSfsr(tc, false, ct, false, VaOutOfRange, asi);
498 return new InstructionAccessException;
499 }
500
501 if (!lsu_im) {
502 e = lookup(vaddr, part_id, true);
503 real = true;
504 context = 0;
505 } else {
506 e = lookup(vaddr, part_id, false, context);
507 }
508
509 if (e == NULL || !e->valid) {
510 tc->setMiscReg(MISCREG_MMU_ITLB_TAG_ACCESS,
511 vaddr & ~BytesInPageMask | context);
512 if (real)
513 return new InstructionRealTranslationMiss;
514 else
515 return new FastInstructionAccessMMUMiss;
516 }
517
518 // were not priviledged accesing priv page
519 if (!priv && e->pte.priv()) {
520 writeSfsr(tc, false, ct, false, PrivViolation, asi);
521 return new InstructionAccessException;
522 }
523
524 // cache translation date for next translation
525 cacheValid = true;
526 cacheState = tlbdata;
527 cacheEntry = e;
528
529 req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
530 vaddr & e->pte.size()-1 );
531 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
532 return NoFault;
533}
534
535
536
537Fault
538DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
539{
540 /* @todo this could really use some profiling and fixing to make it faster! */
541 uint64_t tlbdata = tc->readMiscReg(MISCREG_TLB_DATA);
542 Addr vaddr = req->getVaddr();
543 Addr size = req->getSize();
544 ASI asi;
545 asi = (ASI)req->getAsi();
546 bool implicit = false;
547 bool hpriv = bits(tlbdata,0,0);
548
549 DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n",
550 vaddr, size, asi);
551
552 if (asi == ASI_IMPLICIT)
553 implicit = true;
554
555 if (hpriv && implicit) {
556 req->setPaddr(vaddr & PAddrImplMask);
557 return NoFault;
558 }
559
560 // Be fast if we can!
561 if (cacheValid && cacheState == tlbdata) {
562 if (cacheEntry[0] && cacheAsi[0] == asi && cacheEntry[0]->range.va < vaddr + size &&
563 cacheEntry[0]->range.va + cacheEntry[0]->range.size > vaddr) {
564 req->setPaddr(cacheEntry[0]->pte.paddr() & ~(cacheEntry[0]->pte.size()-1) |
565 vaddr & cacheEntry[0]->pte.size()-1 );
566 return NoFault;
567 }
568 if (cacheEntry[1] && cacheAsi[1] == asi && cacheEntry[1]->range.va < vaddr + size &&
569 cacheEntry[1]->range.va + cacheEntry[1]->range.size > vaddr) {
570 req->setPaddr(cacheEntry[1]->pte.paddr() & ~(cacheEntry[1]->pte.size()-1) |
571 vaddr & cacheEntry[1]->pte.size()-1 );
572 return NoFault;
573 }
574 }
575
576 bool red = bits(tlbdata,1,1);
577 bool priv = bits(tlbdata,2,2);
578 bool addr_mask = bits(tlbdata,3,3);
579 bool lsu_dm = bits(tlbdata,5,5);
580
581 int part_id = bits(tlbdata,15,8);
582 int tl = bits(tlbdata,18,16);
583 int pri_context = bits(tlbdata,47,32);
584 int sec_context = bits(tlbdata,47,32);
585
586 bool real = false;
587 ContextType ct = Primary;
588 int context = 0;
589
590 TlbEntry *e;
591
592 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n",
593 priv, hpriv, red, lsu_dm, part_id);
594
595 if (implicit) {
596 if (tl > 0) {
597 asi = ASI_N;
598 ct = Nucleus;
599 context = 0;
600 } else {
601 asi = ASI_P;
602 ct = Primary;
603 context = pri_context;
604 }
605 } else if (!hpriv && !red) {
606 if (tl > 0 || AsiIsNucleus(asi)) {
607 ct = Nucleus;
608 context = 0;
609 } else if (AsiIsSecondary(asi)) {
610 ct = Secondary;
611 context = sec_context;
612 } else {
613 context = pri_context;
614 ct = Primary; //???
615 }
616
617 // We need to check for priv level/asi priv
618 if (!priv && !AsiIsUnPriv(asi)) {
619 // It appears that context should be Nucleus in these cases?
620 writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
621 return new PrivilegedAction;
622 }
623 if (priv && AsiIsHPriv(asi)) {
624 writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
625 return new DataAccessException;
626 }
627
628 }
629 if (asi == ASI_P || asi == ASI_LDTX_P) {
630 ct = Primary;
631 context = pri_context;
632 goto continueDtbFlow;
633 }
634
635 if (!implicit) {
636 if (AsiIsLittle(asi))
637 panic("Little Endian ASIs not supported\n");
638 if (AsiIsBlock(asi))
639 panic("Block ASIs not supported\n");
640 if (AsiIsNoFault(asi))
641 panic("No Fault ASIs not supported\n");
642 if (!write && asi == ASI_QUAD_LDD)
643 goto continueDtbFlow;
644
645 if (AsiIsTwin(asi))
646 panic("Twin ASIs not supported\n");
647 if (AsiIsPartialStore(asi))
648 panic("Partial Store ASIs not supported\n");
649 if (AsiIsInterrupt(asi))
650 panic("Interrupt ASIs not supported\n");
651
652 if (AsiIsMmu(asi))
653 goto handleMmuRegAccess;
654 if (AsiIsScratchPad(asi))
655 goto handleScratchRegAccess;
656 if (AsiIsQueue(asi))
657 goto handleQueueRegAccess;
658 if (AsiIsSparcError(asi))
659 goto handleSparcErrorRegAccess;
660
661 if (!AsiIsReal(asi) && !AsiIsNucleus(asi))
662 panic("Accessing ASI %#X. Should we?\n", asi);
663 }
664
665continueDtbFlow:
666 // If the asi is unaligned trap
667 if (vaddr & size-1) {
668 writeSfr(tc, vaddr, false, ct, false, OtherFault, asi);
669 return new MemAddressNotAligned;
670 }
671
672 if (addr_mask)
673 vaddr = vaddr & VAddrAMask;
674
675 if (!validVirtualAddress(vaddr, addr_mask)) {
676 writeSfr(tc, vaddr, false, ct, true, VaOutOfRange, asi);
677 return new DataAccessException;
678 }
679
680
681 if ((!lsu_dm && !hpriv) || AsiIsReal(asi)) {
682 real = true;
683 context = 0;
684 };
685
686 if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {
687 req->setPaddr(vaddr & PAddrImplMask);
688 return NoFault;
689 }
690
691 e = lookup(vaddr, part_id, real, context);
692
693 if (e == NULL || !e->valid) {
694 tc->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS,
695 vaddr & ~BytesInPageMask | context);
696 DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n");
697 if (real)
698 return new DataRealTranslationMiss;
699 else
700 return new FastDataAccessMMUMiss;
701
702 }
703
704
705 if (write && !e->pte.writable()) {
706 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);
707 return new FastDataAccessProtection;
708 }
709
710 if (e->pte.nofault() && !AsiIsNoFault(asi)) {
711 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);
712 return new DataAccessException;
713 }
714
715 if (e->pte.sideffect())
716 req->setFlags(req->getFlags() | UNCACHEABLE);
717
718
719 if (!priv && e->pte.priv()) {
720 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);
721 return new DataAccessException;
722 }
723
724 // cache translation date for next translation
725 cacheState = tlbdata;
726 if (!cacheValid) {
727 cacheEntry[1] = NULL;
728 cacheEntry[0] = NULL;
729 }
730
731 if (cacheEntry[0] != e && cacheEntry[1] != e) {
732 cacheEntry[1] = cacheEntry[0];
733 cacheEntry[0] = e;
734 cacheAsi[1] = cacheAsi[0];
735 cacheAsi[0] = asi;
736 if (implicit)
737 cacheAsi[0] = (ASI)0;
738 }
739 cacheValid = true;
740 req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
741 vaddr & e->pte.size()-1);
742 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
743 return NoFault;
744 /** Normal flow ends here. */
745
746handleScratchRegAccess:
747 if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) {
748 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
749 return new DataAccessException;
750 }
751 goto regAccessOk;
752
753handleQueueRegAccess:
754 if (!priv && !hpriv) {
755 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
756 return new PrivilegedAction;
757 }
758 if (!hpriv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {
759 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
760 return new DataAccessException;
761 }
762 goto regAccessOk;
763
764handleSparcErrorRegAccess:
765 if (!hpriv) {
766 if (priv) {
767 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
768 return new DataAccessException;
769 } else {
770 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
771 return new PrivilegedAction;
772 }
773 }
774 goto regAccessOk;
775
776
777regAccessOk:
778handleMmuRegAccess:
779 DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n");
780 req->setMmapedIpr(true);
781 req->setPaddr(req->getVaddr());
782 return NoFault;
783};
784
785Tick
786DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
787{
788 Addr va = pkt->getAddr();
789 ASI asi = (ASI)pkt->req->getAsi();
790 uint64_t temp, data;
791 uint64_t tsbtemp, cnftemp;
792
793 DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",
794 (uint32_t)pkt->req->getAsi(), pkt->getAddr());
795
796 switch (asi) {
797 case ASI_LSU_CONTROL_REG:
798 assert(va == 0);
799 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_LSU_CTRL));
800 break;
801 case ASI_MMU:
802 switch (va) {
803 case 0x8:
804 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT));
805 break;
806 case 0x10:
807 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT));
808 break;
809 default:
810 goto doMmuReadError;
811 }
812 break;
813 case ASI_QUEUE:
814 pkt->set(tc->readMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
815 (va >> 4) - 0x3c));
816 break;
817 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
818 assert(va == 0);
819 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0));
820 break;
821 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
822 assert(va == 0);
823 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1));
824 break;
825 case ASI_DMMU_CTXT_ZERO_CONFIG:
826 assert(va == 0);
827 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG));
828 break;
829 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
830 assert(va == 0);
831 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0));
832 break;
833 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
834 assert(va == 0);
835 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1));
836 break;
837 case ASI_IMMU_CTXT_ZERO_CONFIG:
838 assert(va == 0);
839 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG));
840 break;
841 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
842 assert(va == 0);
843 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0));
844 break;
845 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
846 assert(va == 0);
847 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1));
848 break;
849 case ASI_DMMU_CTXT_NONZERO_CONFIG:
850 assert(va == 0);
851 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG));
852 break;
853 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
854 assert(va == 0);
855 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0));
856 break;
857 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
858 assert(va == 0);
859 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1));
860 break;
861 case ASI_IMMU_CTXT_NONZERO_CONFIG:
862 assert(va == 0);
863 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG));
864 break;
865 case ASI_SPARC_ERROR_STATUS_REG:
866 warn("returning 0 for SPARC ERROR regsiter read\n");
867 pkt->set(0);
868 break;
869 case ASI_HYP_SCRATCHPAD:
870 case ASI_SCRATCHPAD:
871 pkt->set(tc->readMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3)));
872 break;
873 case ASI_IMMU:
874 switch (va) {
875 case 0x0:
876 temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
877 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
878 break;
879 case 0x18:
880 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_SFSR));
881 break;
882 case 0x30:
883 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS));
884 break;
885 default:
886 goto doMmuReadError;
887 }
888 break;
889 case ASI_DMMU:
890 switch (va) {
891 case 0x0:
892 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
893 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
894 break;
895 case 0x18:
896 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_SFSR));
897 break;
898 case 0x20:
899 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_SFAR));
900 break;
901 case 0x30:
902 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS));
903 break;
904 case 0x80:
905 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID));
906 break;
907 default:
908 goto doMmuReadError;
909 }
910 break;
911 case ASI_DMMU_TSB_PS0_PTR_REG:
912 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
913 if (bits(temp,12,0) == 0) {
914 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0);
915 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG);
916 } else {
917 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0);
918 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG);
919 }
920 data = mbits(tsbtemp,63,13);
921 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
922 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
923 pkt->set(data);
924 break;
925 case ASI_DMMU_TSB_PS1_PTR_REG:
926 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
927 if (bits(temp,12,0) == 0) {
928 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1);
929 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG);
930 } else {
931 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1);
932 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG);
933 }
934 data = mbits(tsbtemp,63,13);
935 if (bits(tsbtemp,12,12))
936 data |= ULL(1) << (13+bits(tsbtemp,3,0));
937 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
938 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
939 pkt->set(data);
940 break;
941 case ASI_IMMU_TSB_PS0_PTR_REG:
942 temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
943 if (bits(temp,12,0) == 0) {
944 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0);
945 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG);
946 } else {
947 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0);
948 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG);
949 }
950 data = mbits(tsbtemp,63,13);
951 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
952 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
953 pkt->set(data);
954 break;
955 case ASI_IMMU_TSB_PS1_PTR_REG:
956 temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
957 if (bits(temp,12,0) == 0) {
958 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1);
959 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG);
960 } else {
961 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1);
962 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG);
963 }
964 data = mbits(tsbtemp,63,13);
965 if (bits(tsbtemp,12,12))
966 data |= ULL(1) << (13+bits(tsbtemp,3,0));
967 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
968 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
969 pkt->set(data);
970 break;
971
972 default:
973doMmuReadError:
974 panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n",
975 (uint32_t)asi, va);
976 }
977 pkt->result = Packet::Success;
978 return tc->getCpuPtr()->cycles(1);
979}
980
981Tick
982DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
983{
984 uint64_t data = gtoh(pkt->get<uint64_t>());
985 Addr va = pkt->getAddr();
986 ASI asi = (ASI)pkt->req->getAsi();
987
988 Addr ta_insert;
989 Addr va_insert;
990 Addr ct_insert;
991 int part_insert;
992 int entry_insert = -1;
993 bool real_insert;
994 bool ignore;
995 int part_id;
996 int ctx_id;
997 PageTableEntry pte;
998
999 DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
1000 (uint32_t)asi, va, data);
1001
1002 switch (asi) {
1003 case ASI_LSU_CONTROL_REG:
1004 assert(va == 0);
1005 tc->setMiscRegWithEffect(MISCREG_MMU_LSU_CTRL, data);
1006 break;
1007 case ASI_MMU:
1008 switch (va) {
1009 case 0x8:
1010 tc->setMiscRegWithEffect(MISCREG_MMU_P_CONTEXT, data);
1011 break;
1012 case 0x10:
1013 tc->setMiscRegWithEffect(MISCREG_MMU_S_CONTEXT, data);
1014 break;
1015 default:
1016 goto doMmuWriteError;
1017 }
1018 break;
1019 case ASI_QUEUE:
1020 assert(mbits(data,13,6) == data);
1021 tc->setMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
1022 (va >> 4) - 0x3c, data);
1023 break;
1024 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
1025 assert(va == 0);
1026 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0, data);
1027 break;
1028 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
1029 assert(va == 0);
1030 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1, data);
1031 break;
1032 case ASI_DMMU_CTXT_ZERO_CONFIG:
1033 assert(va == 0);
1034 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG, data);
1035 break;
1036 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
1037 assert(va == 0);
1038 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0, data);
1039 break;
1040 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
1041 assert(va == 0);
1042 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1, data);
1043 break;
1044 case ASI_IMMU_CTXT_ZERO_CONFIG:
1045 assert(va == 0);
1046 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG, data);
1047 break;
1048 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
1049 assert(va == 0);
1050 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0, data);
1051 break;
1052 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
1053 assert(va == 0);
1054 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1, data);
1055 break;
1056 case ASI_DMMU_CTXT_NONZERO_CONFIG:
1057 assert(va == 0);
1058 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG, data);
1059 break;
1060 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
1061 assert(va == 0);
1062 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0, data);
1063 break;
1064 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
1065 assert(va == 0);
1066 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1, data);
1067 break;
1068 case ASI_IMMU_CTXT_NONZERO_CONFIG:
1069 assert(va == 0);
1070 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG, data);
1071 break;
1072 case ASI_SPARC_ERROR_EN_REG:
1073 case ASI_SPARC_ERROR_STATUS_REG:
1074 warn("Ignoring write to SPARC ERROR regsiter\n");
1075 break;
1076 case ASI_HYP_SCRATCHPAD:
1077 case ASI_SCRATCHPAD:
1078 tc->setMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3), data);
1079 break;
1080 case ASI_IMMU:
1081 switch (va) {
1082 case 0x18:
1083 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_SFSR, data);
1084 break;
1085 case 0x30:
1086 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS, data);
1087 break;
1088 default:
1089 goto doMmuWriteError;
1090 }
1091 break;
1092 case ASI_ITLB_DATA_ACCESS_REG:
1093 entry_insert = bits(va, 8,3);
1094 case ASI_ITLB_DATA_IN_REG:
1095 assert(entry_insert != -1 || mbits(va,10,9) == va);
1096 ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
1097 va_insert = mbits(ta_insert, 63,13);
1098 ct_insert = mbits(ta_insert, 12,0);
1099 part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1100 real_insert = bits(va, 9,9);
1101 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1102 PageTableEntry::sun4u);
1103 tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert,
1104 pte, entry_insert);
1105 break;
1106 case ASI_DTLB_DATA_ACCESS_REG:
1107 entry_insert = bits(va, 8,3);
1108 case ASI_DTLB_DATA_IN_REG:
1109 assert(entry_insert != -1 || mbits(va,10,9) == va);
1110 ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
1111 va_insert = mbits(ta_insert, 63,13);
1112 ct_insert = mbits(ta_insert, 12,0);
1113 part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1114 real_insert = bits(va, 9,9);
1115 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1116 PageTableEntry::sun4u);
1117 insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert);
1118 break;
1119 case ASI_IMMU_DEMAP:
1120 ignore = false;
1121 ctx_id = -1;
1122 part_id = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1123 switch (bits(va,5,4)) {
1124 case 0:
1125 ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT);
1126 break;
1127 case 1:
1128 ignore = true;
1129 break;
1130 case 3:
1131 ctx_id = 0;
1132 break;
1133 default:
1134 ignore = true;
1135 }
1136
1137 switch(bits(va,7,6)) {
1138 case 0: // demap page
1139 if (!ignore)
1140 tc->getITBPtr()->demapPage(mbits(va,63,13), part_id,
1141 bits(va,9,9), ctx_id);
1142 break;
1143 case 1: //demap context
1144 if (!ignore)
1145 tc->getITBPtr()->demapContext(part_id, ctx_id);
1146 break;
1147 case 2:
1148 tc->getITBPtr()->demapAll(part_id);
1149 break;
1150 default:
1151 panic("Invalid type for IMMU demap\n");
1152 }
1153 break;
1154 case ASI_DMMU:
1155 switch (va) {
1156 case 0x18:
1157 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_SFSR, data);
1158 break;
1159 case 0x30:
1160 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS, data);
1161 break;
1162 case 0x80:
1163 tc->setMiscRegWithEffect(MISCREG_MMU_PART_ID, data);
1164 break;
1165 default:
1166 goto doMmuWriteError;
1167 }
1168 break;
1169 case ASI_DMMU_DEMAP:
1170 ignore = false;
1171 ctx_id = -1;
1172 part_id = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1173 switch (bits(va,5,4)) {
1174 case 0:
1175 ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT);
1176 break;
1177 case 1:
1178 ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT);
1179 break;
1180 case 3:
1181 ctx_id = 0;
1182 break;
1183 default:
1184 ignore = true;
1185 }
1186
1187 switch(bits(va,7,6)) {
1188 case 0: // demap page
1189 if (!ignore)
1190 demapPage(mbits(va,63,13), part_id, bits(va,9,9), ctx_id);
1191 break;
1192 case 1: //demap context
1193 if (!ignore)
1194 demapContext(part_id, ctx_id);
1195 break;
1196 case 2:
1197 demapAll(part_id);
1198 break;
1199 default:
1200 panic("Invalid type for IMMU demap\n");
1201 }
1202 break;
1203 default:
1204doMmuWriteError:
1205 panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
1206 (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
1207 }
1208 pkt->result = Packet::Success;
1209 return tc->getCpuPtr()->cycles(1);
1210}
1211
1212void
1213TLB::serialize(std::ostream &os)
1214{
1215 panic("Need to implement serialize tlb for SPARC\n");
1216}
1217
1218void
1219TLB::unserialize(Checkpoint *cp, const std::string &section)
1220{
1221 panic("Need to implement unserialize tlb for SPARC\n");
1222}
1223
1224
1225DEFINE_SIM_OBJECT_CLASS_NAME("SparcTLB", TLB)
1226
1227BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB)
1228
1229 Param<int> size;
1230
1231END_DECLARE_SIM_OBJECT_PARAMS(ITB)
1232
1233BEGIN_INIT_SIM_OBJECT_PARAMS(ITB)
1234
1235 INIT_PARAM_DFLT(size, "TLB size", 48)
1236
1237END_INIT_SIM_OBJECT_PARAMS(ITB)
1238
1239
1240CREATE_SIM_OBJECT(ITB)
1241{
1242 return new ITB(getInstanceName(), size);
1243}
1244
1245REGISTER_SIM_OBJECT("SparcITB", ITB)
1246
1247BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB)
1248
1249 Param<int> size;
1250
1251END_DECLARE_SIM_OBJECT_PARAMS(DTB)
1252
1253BEGIN_INIT_SIM_OBJECT_PARAMS(DTB)
1254
1255 INIT_PARAM_DFLT(size, "TLB size", 64)
1256
1257END_INIT_SIM_OBJECT_PARAMS(DTB)
1258
1259
1260CREATE_SIM_OBJECT(DTB)
1261{
1262 return new DTB(getInstanceName(), size);
1263}
1264
1265REGISTER_SIM_OBJECT("SparcDTB", DTB)
1266}
351 }
352 usedEntries = 0;
353}
354
355uint64_t
356TLB::TteRead(int entry) {
357 if (entry >= size)
358 panic("entry: %d\n", entry);
359
360 assert(entry < size);
361 if (tlb[entry].valid)
362 return tlb[entry].pte();
363 else
364 return (uint64_t)-1ll;
365}
366
367uint64_t
368TLB::TagRead(int entry) {
369 assert(entry < size);
370 uint64_t tag;
371 if (!tlb[entry].valid)
372 return (uint64_t)-1ll;
373
374 tag = tlb[entry].range.contextId;
375 tag |= tlb[entry].range.va;
376 tag |= (uint64_t)tlb[entry].range.partitionId << 61;
377 tag |= tlb[entry].range.real ? ULL(1) << 60 : 0;
378 tag |= (uint64_t)~tlb[entry].pte._size() << 56;
379 return tag;
380}
381
382bool
383TLB::validVirtualAddress(Addr va, bool am)
384{
385 if (am)
386 return true;
387 if (va >= StartVAddrHole && va <= EndVAddrHole)
388 return false;
389 return true;
390}
391
392void
393TLB::writeSfsr(ThreadContext *tc, int reg, bool write, ContextType ct,
394 bool se, FaultTypes ft, int asi)
395{
396 uint64_t sfsr;
397 sfsr = tc->readMiscReg(reg);
398
399 if (sfsr & 0x1)
400 sfsr = 0x3;
401 else
402 sfsr = 1;
403
404 if (write)
405 sfsr |= 1 << 2;
406 sfsr |= ct << 4;
407 if (se)
408 sfsr |= 1 << 6;
409 sfsr |= ft << 7;
410 sfsr |= asi << 16;
411 tc->setMiscRegWithEffect(reg, sfsr);
412}
413
414void
415TLB::writeTagAccess(ThreadContext *tc, int reg, Addr va, int context)
416{
417 tc->setMiscRegWithEffect(reg, mbits(va, 63,13) | mbits(context,12,0));
418}
419
420void
421ITB::writeSfsr(ThreadContext *tc, bool write, ContextType ct,
422 bool se, FaultTypes ft, int asi)
423{
424 DPRINTF(TLB, "TLB: ITB Fault: w=%d ct=%d ft=%d asi=%d\n",
425 (int)write, ct, ft, asi);
426 TLB::writeSfsr(tc, MISCREG_MMU_ITLB_SFSR, write, ct, se, ft, asi);
427}
428
429void
430ITB::writeTagAccess(ThreadContext *tc, Addr va, int context)
431{
432 TLB::writeTagAccess(tc, MISCREG_MMU_ITLB_TAG_ACCESS, va, context);
433}
434
435void
436DTB::writeSfr(ThreadContext *tc, Addr a, bool write, ContextType ct,
437 bool se, FaultTypes ft, int asi)
438{
439 DPRINTF(TLB, "TLB: DTB Fault: A=%#x w=%d ct=%d ft=%d asi=%d\n",
440 a, (int)write, ct, ft, asi);
441 TLB::writeSfsr(tc, MISCREG_MMU_DTLB_SFSR, write, ct, se, ft, asi);
442 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_SFAR, a);
443}
444
445void
446DTB::writeTagAccess(ThreadContext *tc, Addr va, int context)
447{
448 TLB::writeTagAccess(tc, MISCREG_MMU_DTLB_TAG_ACCESS, va, context);
449}
450
451
452
453Fault
454ITB::translate(RequestPtr &req, ThreadContext *tc)
455{
456 uint64_t tlbdata = tc->readMiscReg(MISCREG_TLB_DATA);
457
458 Addr vaddr = req->getVaddr();
459 TlbEntry *e;
460
461 assert(req->getAsi() == ASI_IMPLICIT);
462
463 DPRINTF(TLB, "TLB: ITB Request to translate va=%#x size=%d\n",
464 vaddr, req->getSize());
465
466 // Be fast if we can!
467 if (cacheValid && cacheState == tlbdata) {
468 if (cacheEntry) {
469 if (cacheEntry->range.va < vaddr + sizeof(MachInst) &&
470 cacheEntry->range.va + cacheEntry->range.size >= vaddr) {
471 req->setPaddr(cacheEntry->pte.paddr() & ~(cacheEntry->pte.size()-1) |
472 vaddr & cacheEntry->pte.size()-1 );
473 return NoFault;
474 }
475 } else {
476 req->setPaddr(vaddr & PAddrImplMask);
477 return NoFault;
478 }
479 }
480
481 bool hpriv = bits(tlbdata,0,0);
482 bool red = bits(tlbdata,1,1);
483 bool priv = bits(tlbdata,2,2);
484 bool addr_mask = bits(tlbdata,3,3);
485 bool lsu_im = bits(tlbdata,4,4);
486
487 int part_id = bits(tlbdata,15,8);
488 int tl = bits(tlbdata,18,16);
489 int pri_context = bits(tlbdata,47,32);
490 int context;
491 ContextType ct;
492 int asi;
493 bool real = false;
494
495 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsuim:%d part_id: %#X\n",
496 priv, hpriv, red, lsu_im, part_id);
497
498 if (tl > 0) {
499 asi = ASI_N;
500 ct = Nucleus;
501 context = 0;
502 } else {
503 asi = ASI_P;
504 ct = Primary;
505 context = pri_context;
506 }
507
508 if ( hpriv || red ) {
509 cacheValid = true;
510 cacheState = tlbdata;
511 cacheEntry = NULL;
512 req->setPaddr(vaddr & PAddrImplMask);
513 return NoFault;
514 }
515
516 // If the access is unaligned trap
517 if (vaddr & 0x3) {
518 writeSfsr(tc, false, ct, false, OtherFault, asi);
519 return new MemAddressNotAligned;
520 }
521
522 if (addr_mask)
523 vaddr = vaddr & VAddrAMask;
524
525 if (!validVirtualAddress(vaddr, addr_mask)) {
526 writeSfsr(tc, false, ct, false, VaOutOfRange, asi);
527 return new InstructionAccessException;
528 }
529
530 if (!lsu_im) {
531 e = lookup(vaddr, part_id, true);
532 real = true;
533 context = 0;
534 } else {
535 e = lookup(vaddr, part_id, false, context);
536 }
537
538 if (e == NULL || !e->valid) {
539 tc->setMiscReg(MISCREG_MMU_ITLB_TAG_ACCESS,
540 vaddr & ~BytesInPageMask | context);
541 if (real)
542 return new InstructionRealTranslationMiss;
543 else
544 return new FastInstructionAccessMMUMiss;
545 }
546
547 // were not priviledged accesing priv page
548 if (!priv && e->pte.priv()) {
549 writeSfsr(tc, false, ct, false, PrivViolation, asi);
550 return new InstructionAccessException;
551 }
552
553 // cache translation date for next translation
554 cacheValid = true;
555 cacheState = tlbdata;
556 cacheEntry = e;
557
558 req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
559 vaddr & e->pte.size()-1 );
560 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
561 return NoFault;
562}
563
564
565
566Fault
567DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
568{
569 /* @todo this could really use some profiling and fixing to make it faster! */
570 uint64_t tlbdata = tc->readMiscReg(MISCREG_TLB_DATA);
571 Addr vaddr = req->getVaddr();
572 Addr size = req->getSize();
573 ASI asi;
574 asi = (ASI)req->getAsi();
575 bool implicit = false;
576 bool hpriv = bits(tlbdata,0,0);
577
578 DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n",
579 vaddr, size, asi);
580
581 if (asi == ASI_IMPLICIT)
582 implicit = true;
583
584 if (hpriv && implicit) {
585 req->setPaddr(vaddr & PAddrImplMask);
586 return NoFault;
587 }
588
589 // Be fast if we can!
590 if (cacheValid && cacheState == tlbdata) {
591 if (cacheEntry[0] && cacheAsi[0] == asi && cacheEntry[0]->range.va < vaddr + size &&
592 cacheEntry[0]->range.va + cacheEntry[0]->range.size > vaddr) {
593 req->setPaddr(cacheEntry[0]->pte.paddr() & ~(cacheEntry[0]->pte.size()-1) |
594 vaddr & cacheEntry[0]->pte.size()-1 );
595 return NoFault;
596 }
597 if (cacheEntry[1] && cacheAsi[1] == asi && cacheEntry[1]->range.va < vaddr + size &&
598 cacheEntry[1]->range.va + cacheEntry[1]->range.size > vaddr) {
599 req->setPaddr(cacheEntry[1]->pte.paddr() & ~(cacheEntry[1]->pte.size()-1) |
600 vaddr & cacheEntry[1]->pte.size()-1 );
601 return NoFault;
602 }
603 }
604
605 bool red = bits(tlbdata,1,1);
606 bool priv = bits(tlbdata,2,2);
607 bool addr_mask = bits(tlbdata,3,3);
608 bool lsu_dm = bits(tlbdata,5,5);
609
610 int part_id = bits(tlbdata,15,8);
611 int tl = bits(tlbdata,18,16);
612 int pri_context = bits(tlbdata,47,32);
613 int sec_context = bits(tlbdata,47,32);
614
615 bool real = false;
616 ContextType ct = Primary;
617 int context = 0;
618
619 TlbEntry *e;
620
621 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n",
622 priv, hpriv, red, lsu_dm, part_id);
623
624 if (implicit) {
625 if (tl > 0) {
626 asi = ASI_N;
627 ct = Nucleus;
628 context = 0;
629 } else {
630 asi = ASI_P;
631 ct = Primary;
632 context = pri_context;
633 }
634 } else if (!hpriv && !red) {
635 if (tl > 0 || AsiIsNucleus(asi)) {
636 ct = Nucleus;
637 context = 0;
638 } else if (AsiIsSecondary(asi)) {
639 ct = Secondary;
640 context = sec_context;
641 } else {
642 context = pri_context;
643 ct = Primary; //???
644 }
645
646 // We need to check for priv level/asi priv
647 if (!priv && !AsiIsUnPriv(asi)) {
648 // It appears that context should be Nucleus in these cases?
649 writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
650 return new PrivilegedAction;
651 }
652 if (priv && AsiIsHPriv(asi)) {
653 writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
654 return new DataAccessException;
655 }
656
657 }
658 if (asi == ASI_P || asi == ASI_LDTX_P) {
659 ct = Primary;
660 context = pri_context;
661 goto continueDtbFlow;
662 }
663
664 if (!implicit) {
665 if (AsiIsLittle(asi))
666 panic("Little Endian ASIs not supported\n");
667 if (AsiIsBlock(asi))
668 panic("Block ASIs not supported\n");
669 if (AsiIsNoFault(asi))
670 panic("No Fault ASIs not supported\n");
671 if (!write && asi == ASI_QUAD_LDD)
672 goto continueDtbFlow;
673
674 if (AsiIsTwin(asi))
675 panic("Twin ASIs not supported\n");
676 if (AsiIsPartialStore(asi))
677 panic("Partial Store ASIs not supported\n");
678 if (AsiIsInterrupt(asi))
679 panic("Interrupt ASIs not supported\n");
680
681 if (AsiIsMmu(asi))
682 goto handleMmuRegAccess;
683 if (AsiIsScratchPad(asi))
684 goto handleScratchRegAccess;
685 if (AsiIsQueue(asi))
686 goto handleQueueRegAccess;
687 if (AsiIsSparcError(asi))
688 goto handleSparcErrorRegAccess;
689
690 if (!AsiIsReal(asi) && !AsiIsNucleus(asi))
691 panic("Accessing ASI %#X. Should we?\n", asi);
692 }
693
694continueDtbFlow:
695 // If the asi is unaligned trap
696 if (vaddr & size-1) {
697 writeSfr(tc, vaddr, false, ct, false, OtherFault, asi);
698 return new MemAddressNotAligned;
699 }
700
701 if (addr_mask)
702 vaddr = vaddr & VAddrAMask;
703
704 if (!validVirtualAddress(vaddr, addr_mask)) {
705 writeSfr(tc, vaddr, false, ct, true, VaOutOfRange, asi);
706 return new DataAccessException;
707 }
708
709
710 if ((!lsu_dm && !hpriv) || AsiIsReal(asi)) {
711 real = true;
712 context = 0;
713 };
714
715 if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {
716 req->setPaddr(vaddr & PAddrImplMask);
717 return NoFault;
718 }
719
720 e = lookup(vaddr, part_id, real, context);
721
722 if (e == NULL || !e->valid) {
723 tc->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS,
724 vaddr & ~BytesInPageMask | context);
725 DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n");
726 if (real)
727 return new DataRealTranslationMiss;
728 else
729 return new FastDataAccessMMUMiss;
730
731 }
732
733
734 if (write && !e->pte.writable()) {
735 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);
736 return new FastDataAccessProtection;
737 }
738
739 if (e->pte.nofault() && !AsiIsNoFault(asi)) {
740 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);
741 return new DataAccessException;
742 }
743
744 if (e->pte.sideffect())
745 req->setFlags(req->getFlags() | UNCACHEABLE);
746
747
748 if (!priv && e->pte.priv()) {
749 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);
750 return new DataAccessException;
751 }
752
753 // cache translation date for next translation
754 cacheState = tlbdata;
755 if (!cacheValid) {
756 cacheEntry[1] = NULL;
757 cacheEntry[0] = NULL;
758 }
759
760 if (cacheEntry[0] != e && cacheEntry[1] != e) {
761 cacheEntry[1] = cacheEntry[0];
762 cacheEntry[0] = e;
763 cacheAsi[1] = cacheAsi[0];
764 cacheAsi[0] = asi;
765 if (implicit)
766 cacheAsi[0] = (ASI)0;
767 }
768 cacheValid = true;
769 req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
770 vaddr & e->pte.size()-1);
771 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
772 return NoFault;
773 /** Normal flow ends here. */
774
775handleScratchRegAccess:
776 if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) {
777 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
778 return new DataAccessException;
779 }
780 goto regAccessOk;
781
782handleQueueRegAccess:
783 if (!priv && !hpriv) {
784 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
785 return new PrivilegedAction;
786 }
787 if (!hpriv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {
788 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
789 return new DataAccessException;
790 }
791 goto regAccessOk;
792
793handleSparcErrorRegAccess:
794 if (!hpriv) {
795 if (priv) {
796 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
797 return new DataAccessException;
798 } else {
799 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
800 return new PrivilegedAction;
801 }
802 }
803 goto regAccessOk;
804
805
806regAccessOk:
807handleMmuRegAccess:
808 DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n");
809 req->setMmapedIpr(true);
810 req->setPaddr(req->getVaddr());
811 return NoFault;
812};
813
814Tick
815DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
816{
817 Addr va = pkt->getAddr();
818 ASI asi = (ASI)pkt->req->getAsi();
819 uint64_t temp, data;
820 uint64_t tsbtemp, cnftemp;
821
822 DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",
823 (uint32_t)pkt->req->getAsi(), pkt->getAddr());
824
825 switch (asi) {
826 case ASI_LSU_CONTROL_REG:
827 assert(va == 0);
828 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_LSU_CTRL));
829 break;
830 case ASI_MMU:
831 switch (va) {
832 case 0x8:
833 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT));
834 break;
835 case 0x10:
836 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT));
837 break;
838 default:
839 goto doMmuReadError;
840 }
841 break;
842 case ASI_QUEUE:
843 pkt->set(tc->readMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
844 (va >> 4) - 0x3c));
845 break;
846 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
847 assert(va == 0);
848 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0));
849 break;
850 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
851 assert(va == 0);
852 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1));
853 break;
854 case ASI_DMMU_CTXT_ZERO_CONFIG:
855 assert(va == 0);
856 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG));
857 break;
858 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
859 assert(va == 0);
860 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0));
861 break;
862 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
863 assert(va == 0);
864 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1));
865 break;
866 case ASI_IMMU_CTXT_ZERO_CONFIG:
867 assert(va == 0);
868 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG));
869 break;
870 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
871 assert(va == 0);
872 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0));
873 break;
874 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
875 assert(va == 0);
876 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1));
877 break;
878 case ASI_DMMU_CTXT_NONZERO_CONFIG:
879 assert(va == 0);
880 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG));
881 break;
882 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
883 assert(va == 0);
884 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0));
885 break;
886 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
887 assert(va == 0);
888 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1));
889 break;
890 case ASI_IMMU_CTXT_NONZERO_CONFIG:
891 assert(va == 0);
892 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG));
893 break;
894 case ASI_SPARC_ERROR_STATUS_REG:
895 warn("returning 0 for SPARC ERROR regsiter read\n");
896 pkt->set(0);
897 break;
898 case ASI_HYP_SCRATCHPAD:
899 case ASI_SCRATCHPAD:
900 pkt->set(tc->readMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3)));
901 break;
902 case ASI_IMMU:
903 switch (va) {
904 case 0x0:
905 temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
906 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
907 break;
908 case 0x18:
909 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_SFSR));
910 break;
911 case 0x30:
912 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS));
913 break;
914 default:
915 goto doMmuReadError;
916 }
917 break;
918 case ASI_DMMU:
919 switch (va) {
920 case 0x0:
921 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
922 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
923 break;
924 case 0x18:
925 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_SFSR));
926 break;
927 case 0x20:
928 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_SFAR));
929 break;
930 case 0x30:
931 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS));
932 break;
933 case 0x80:
934 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID));
935 break;
936 default:
937 goto doMmuReadError;
938 }
939 break;
940 case ASI_DMMU_TSB_PS0_PTR_REG:
941 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
942 if (bits(temp,12,0) == 0) {
943 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0);
944 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG);
945 } else {
946 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0);
947 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG);
948 }
949 data = mbits(tsbtemp,63,13);
950 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
951 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
952 pkt->set(data);
953 break;
954 case ASI_DMMU_TSB_PS1_PTR_REG:
955 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
956 if (bits(temp,12,0) == 0) {
957 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1);
958 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG);
959 } else {
960 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1);
961 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG);
962 }
963 data = mbits(tsbtemp,63,13);
964 if (bits(tsbtemp,12,12))
965 data |= ULL(1) << (13+bits(tsbtemp,3,0));
966 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
967 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
968 pkt->set(data);
969 break;
970 case ASI_IMMU_TSB_PS0_PTR_REG:
971 temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
972 if (bits(temp,12,0) == 0) {
973 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0);
974 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG);
975 } else {
976 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0);
977 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG);
978 }
979 data = mbits(tsbtemp,63,13);
980 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
981 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
982 pkt->set(data);
983 break;
984 case ASI_IMMU_TSB_PS1_PTR_REG:
985 temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
986 if (bits(temp,12,0) == 0) {
987 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1);
988 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG);
989 } else {
990 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1);
991 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG);
992 }
993 data = mbits(tsbtemp,63,13);
994 if (bits(tsbtemp,12,12))
995 data |= ULL(1) << (13+bits(tsbtemp,3,0));
996 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
997 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
998 pkt->set(data);
999 break;
1000
1001 default:
1002doMmuReadError:
1003 panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n",
1004 (uint32_t)asi, va);
1005 }
1006 pkt->result = Packet::Success;
1007 return tc->getCpuPtr()->cycles(1);
1008}
1009
1010Tick
1011DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
1012{
1013 uint64_t data = gtoh(pkt->get<uint64_t>());
1014 Addr va = pkt->getAddr();
1015 ASI asi = (ASI)pkt->req->getAsi();
1016
1017 Addr ta_insert;
1018 Addr va_insert;
1019 Addr ct_insert;
1020 int part_insert;
1021 int entry_insert = -1;
1022 bool real_insert;
1023 bool ignore;
1024 int part_id;
1025 int ctx_id;
1026 PageTableEntry pte;
1027
1028 DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
1029 (uint32_t)asi, va, data);
1030
1031 switch (asi) {
1032 case ASI_LSU_CONTROL_REG:
1033 assert(va == 0);
1034 tc->setMiscRegWithEffect(MISCREG_MMU_LSU_CTRL, data);
1035 break;
1036 case ASI_MMU:
1037 switch (va) {
1038 case 0x8:
1039 tc->setMiscRegWithEffect(MISCREG_MMU_P_CONTEXT, data);
1040 break;
1041 case 0x10:
1042 tc->setMiscRegWithEffect(MISCREG_MMU_S_CONTEXT, data);
1043 break;
1044 default:
1045 goto doMmuWriteError;
1046 }
1047 break;
1048 case ASI_QUEUE:
1049 assert(mbits(data,13,6) == data);
1050 tc->setMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
1051 (va >> 4) - 0x3c, data);
1052 break;
1053 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
1054 assert(va == 0);
1055 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0, data);
1056 break;
1057 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
1058 assert(va == 0);
1059 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1, data);
1060 break;
1061 case ASI_DMMU_CTXT_ZERO_CONFIG:
1062 assert(va == 0);
1063 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG, data);
1064 break;
1065 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
1066 assert(va == 0);
1067 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0, data);
1068 break;
1069 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
1070 assert(va == 0);
1071 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1, data);
1072 break;
1073 case ASI_IMMU_CTXT_ZERO_CONFIG:
1074 assert(va == 0);
1075 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG, data);
1076 break;
1077 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
1078 assert(va == 0);
1079 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0, data);
1080 break;
1081 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
1082 assert(va == 0);
1083 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1, data);
1084 break;
1085 case ASI_DMMU_CTXT_NONZERO_CONFIG:
1086 assert(va == 0);
1087 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG, data);
1088 break;
1089 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
1090 assert(va == 0);
1091 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0, data);
1092 break;
1093 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
1094 assert(va == 0);
1095 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1, data);
1096 break;
1097 case ASI_IMMU_CTXT_NONZERO_CONFIG:
1098 assert(va == 0);
1099 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG, data);
1100 break;
1101 case ASI_SPARC_ERROR_EN_REG:
1102 case ASI_SPARC_ERROR_STATUS_REG:
1103 warn("Ignoring write to SPARC ERROR regsiter\n");
1104 break;
1105 case ASI_HYP_SCRATCHPAD:
1106 case ASI_SCRATCHPAD:
1107 tc->setMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3), data);
1108 break;
1109 case ASI_IMMU:
1110 switch (va) {
1111 case 0x18:
1112 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_SFSR, data);
1113 break;
1114 case 0x30:
1115 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS, data);
1116 break;
1117 default:
1118 goto doMmuWriteError;
1119 }
1120 break;
1121 case ASI_ITLB_DATA_ACCESS_REG:
1122 entry_insert = bits(va, 8,3);
1123 case ASI_ITLB_DATA_IN_REG:
1124 assert(entry_insert != -1 || mbits(va,10,9) == va);
1125 ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
1126 va_insert = mbits(ta_insert, 63,13);
1127 ct_insert = mbits(ta_insert, 12,0);
1128 part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1129 real_insert = bits(va, 9,9);
1130 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1131 PageTableEntry::sun4u);
1132 tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert,
1133 pte, entry_insert);
1134 break;
1135 case ASI_DTLB_DATA_ACCESS_REG:
1136 entry_insert = bits(va, 8,3);
1137 case ASI_DTLB_DATA_IN_REG:
1138 assert(entry_insert != -1 || mbits(va,10,9) == va);
1139 ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
1140 va_insert = mbits(ta_insert, 63,13);
1141 ct_insert = mbits(ta_insert, 12,0);
1142 part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1143 real_insert = bits(va, 9,9);
1144 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1145 PageTableEntry::sun4u);
1146 insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert);
1147 break;
1148 case ASI_IMMU_DEMAP:
1149 ignore = false;
1150 ctx_id = -1;
1151 part_id = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1152 switch (bits(va,5,4)) {
1153 case 0:
1154 ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT);
1155 break;
1156 case 1:
1157 ignore = true;
1158 break;
1159 case 3:
1160 ctx_id = 0;
1161 break;
1162 default:
1163 ignore = true;
1164 }
1165
1166 switch(bits(va,7,6)) {
1167 case 0: // demap page
1168 if (!ignore)
1169 tc->getITBPtr()->demapPage(mbits(va,63,13), part_id,
1170 bits(va,9,9), ctx_id);
1171 break;
1172 case 1: //demap context
1173 if (!ignore)
1174 tc->getITBPtr()->demapContext(part_id, ctx_id);
1175 break;
1176 case 2:
1177 tc->getITBPtr()->demapAll(part_id);
1178 break;
1179 default:
1180 panic("Invalid type for IMMU demap\n");
1181 }
1182 break;
1183 case ASI_DMMU:
1184 switch (va) {
1185 case 0x18:
1186 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_SFSR, data);
1187 break;
1188 case 0x30:
1189 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS, data);
1190 break;
1191 case 0x80:
1192 tc->setMiscRegWithEffect(MISCREG_MMU_PART_ID, data);
1193 break;
1194 default:
1195 goto doMmuWriteError;
1196 }
1197 break;
1198 case ASI_DMMU_DEMAP:
1199 ignore = false;
1200 ctx_id = -1;
1201 part_id = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
1202 switch (bits(va,5,4)) {
1203 case 0:
1204 ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT);
1205 break;
1206 case 1:
1207 ctx_id = tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT);
1208 break;
1209 case 3:
1210 ctx_id = 0;
1211 break;
1212 default:
1213 ignore = true;
1214 }
1215
1216 switch(bits(va,7,6)) {
1217 case 0: // demap page
1218 if (!ignore)
1219 demapPage(mbits(va,63,13), part_id, bits(va,9,9), ctx_id);
1220 break;
1221 case 1: //demap context
1222 if (!ignore)
1223 demapContext(part_id, ctx_id);
1224 break;
1225 case 2:
1226 demapAll(part_id);
1227 break;
1228 default:
1229 panic("Invalid type for IMMU demap\n");
1230 }
1231 break;
1232 default:
1233doMmuWriteError:
1234 panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
1235 (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
1236 }
1237 pkt->result = Packet::Success;
1238 return tc->getCpuPtr()->cycles(1);
1239}
1240
1241void
1242TLB::serialize(std::ostream &os)
1243{
1244 panic("Need to implement serialize tlb for SPARC\n");
1245}
1246
1247void
1248TLB::unserialize(Checkpoint *cp, const std::string &section)
1249{
1250 panic("Need to implement unserialize tlb for SPARC\n");
1251}
1252
1253
1254DEFINE_SIM_OBJECT_CLASS_NAME("SparcTLB", TLB)
1255
1256BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB)
1257
1258 Param<int> size;
1259
1260END_DECLARE_SIM_OBJECT_PARAMS(ITB)
1261
1262BEGIN_INIT_SIM_OBJECT_PARAMS(ITB)
1263
1264 INIT_PARAM_DFLT(size, "TLB size", 48)
1265
1266END_INIT_SIM_OBJECT_PARAMS(ITB)
1267
1268
1269CREATE_SIM_OBJECT(ITB)
1270{
1271 return new ITB(getInstanceName(), size);
1272}
1273
1274REGISTER_SIM_OBJECT("SparcITB", ITB)
1275
1276BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB)
1277
1278 Param<int> size;
1279
1280END_DECLARE_SIM_OBJECT_PARAMS(DTB)
1281
1282BEGIN_INIT_SIM_OBJECT_PARAMS(DTB)
1283
1284 INIT_PARAM_DFLT(size, "TLB size", 64)
1285
1286END_INIT_SIM_OBJECT_PARAMS(DTB)
1287
1288
1289CREATE_SIM_OBJECT(DTB)
1290{
1291 return new DTB(getInstanceName(), size);
1292}
1293
1294REGISTER_SIM_OBJECT("SparcDTB", DTB)
1295}