Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / ss / lib / csr / src / SS_BaseCsr.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: SS_BaseCsr.cc
4// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
6//
7// The above named program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public
9// License version 2 as published by the Free Software Foundation.
10//
11// The above named program is distributed in the hope that it will be
12// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15//
16// You should have received a copy of the GNU General Public
17// License along with this work; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19//
20// ========== Copyright Header End ============================================
21/************************************************************************
22**
23** Copyright (C) 2006, Sun Microsystems, Inc.
24**
25** Sun considers its source code as an unpublished, proprietary
26** trade secret and it is available only under strict license provisions.
27** This copyright notice is placed here only to protect Sun in the event
28** the source is deemed a published work. Disassembly, decompilation,
29** or other means of reducing the object code to human readable form
30** is prohibited by the license agreement under which this code is
31** provided to the user or company in possession of this copy.
32**
33*************************************************************************/
34#include <sstream>
35#include <list>
36#include "SS_BaseCsr.h"
37#include "SS_Memory.h"
38#include "SS_AddressMap.h"
39
40using namespace std;
41
42//======================================================================
43//======================================================================
44void
45SS_BaseCsr::access( void* obj,
46 uint_t sid,
47 SS_Access::Type type,
48 SS_Paddr addr,
49 uint_t size,
50 uint64_t* data)
51{
52 SS_BaseCsr* self = (SS_BaseCsr*)obj;
53 switch (type)
54 {
55 case SS_Access::LOAD:
56 self->read64(addr, data, MemoryTransaction::READ, sid);
57 break;
58 case SS_Access::STORE:
59 self->write64(addr, *data, MemoryTransaction::WRITE, sid);
60 break;
61 }
62}
63
64//======================================================================
65//======================================================================
66int64_t
67SS_BaseCsr::findAttributeEntryNdx(SS_Paddr paddr,
68 const RegisterAttribute* attributeTable,
69 int entries)
70{
71 for (int i = 0; i < entries; i++) {
72 if (attributeTable[i].startAddr <= paddr && paddr <= attributeTable[i].endAddr) {
73 if (((paddr - attributeTable[i].startAddr) & (attributeTable[i].stride - 1)) == 0) {
74 return i;
75 }
76 }
77 }
78 return ENTRY_NOT_FOUND;
79}
80
81//======================================================================
82//======================================================================
83const RegisterAttribute* const
84SS_BaseCsr::findAttributeEntry(SS_Paddr paddr,
85 const RegisterAttribute* attributeTable,
86 int entries)
87{
88 uint64_t ndx = findAttributeEntryNdx(paddr, attributeTable, entries);
89 return ndx == ENTRY_NOT_FOUND ? NULL: &attributeTable[ndx];
90}
91
92//======================================================================
93//======================================================================
94void
95SS_BaseCsr::warmReset(vector<vector<RegisterValue>*>* values,
96 int nrAttributeEntries)
97{
98 //TODO if a register has different por and warm-reset values, and
99 // the register is never referenced up to this point, such that it
100 // is not in the table yet, then we won't create a register with
101 // warm-reset value for it, the next access to the register will
102 // return its por value, which is wrong. 11/29/05
103 for (int i = 0; i < nrAttributeEntries; i++)
104 {
105 // CSR entries, has 1-to-1 mapping with RegisterAttribute table
106 vector<vector<RegisterValue>*> nodes = values[i];
107 for (int j = 0; j < nodes.size(); j++)
108 {
109 // each entry points to a vector of registers belong to a particulat node
110 if (nodes[j] != NULL)
111 {
112 vector<RegisterValue>& regs = *nodes[j];
113 for (int k = 0; k < regs.size(); k++)
114 {
115 // registers, of a particular node and a particular CSR entry
116 if (regs[k].valid())
117 {
118 if (regs[k].attribute->maskWarm == 0x0)
119 {
120 // if no warm-reset mask, just use warm-reset value
121 regs[k].set_data(regs[k].attribute->warmReset);
122 }
123 else
124 {
125 // otherwise, use warm-reset mask on current data to produce
126 // the new data.
127 regs[k].set_data(regs[k].data() & regs[k].attribute->maskWarm);
128 }
129 }
130 }
131 }
132 }
133 }
134}
135
136//=============================================================================
137// this function assumes value is always 8-byte
138//=============================================================================
139uint64_t
140SS_BaseCsr::reverseByteOrder(uint64_t value, bool littleEndian)
141{
142 if (littleEndian)
143 {
144 int size = 8;
145 uint8_t *byteArr = (uint8_t*)&value;
146 uint64_t revValue = 0;
147 uint8_t *revByteArr = (uint8_t*)&revValue;
148
149 int revIdx = sizeof( value ) - size;
150 int topByte = sizeof( value ) - 1;
151 for ( int byte = topByte; byte > topByte - size; --byte )
152 {
153 revByteArr[revIdx] = byteArr[byte];
154 ++revIdx;
155 }
156 return revValue;
157 }
158 else
159 {
160 return value;
161 }
162}
163
164//=============================================================================
165// mainly used by follow-me, allow writing into any bits except reserved ones,
166// ignore RW1C and RW1S masking. If the data is in littleEndian, then the
167// reserved-mask must be reversed before doing the masking.
168//=============================================================================
169uint64_t
170SS_BaseCsr::forceWrite(uint64_t inputData,
171 const RegisterAttribute* attribute,
172 int access)
173{
174 bool littleEndian = (access & MemoryTransaction::LITTLE_ENDIAN) ? true : false;
175 return (inputData & ~(reverseByteOrder(attribute->maskRSVD, littleEndian)));
176}
177
178//=============================================================================
179// normal write operation, take all masking into account.
180//
181// exclude_maskRW = maskRW & ~(maskRW1C | maskRW1S)
182// new_data = (input_data & exclude_maskRW) |
183// (input_data & maskRW1S) |
184// (old_data & ~(exclde_maskRW | (input_data & maskRW1C)))
185// newData = normalWrite(inputData, oldData, attribute, littleEndian);
186//=============================================================================
187uint64_t
188SS_BaseCsr::normalWrite(uint64_t inputData,
189 uint64_t oldData,
190 const RegisterAttribute* attribute,
191 int access)
192{
193 bool littleEndian = (access & MemoryTransaction::LITTLE_ENDIAN) ? true : false;
194 uint64_t maskRW_exc = attribute->maskRW & ~(attribute->maskRW1C | attribute->maskRW1S);
195 uint64_t newData = (inputData & reverseByteOrder(maskRW_exc, littleEndian)) |
196 (inputData & reverseByteOrder(attribute->maskRW1S, littleEndian)) |
197 (oldData & ~(reverseByteOrder(maskRW_exc, littleEndian) | (inputData & reverseByteOrder(attribute->maskRW1C, littleEndian))));
198
199 return newData;
200}
201
202//=============================================================================
203//=============================================================================
204void
205SS_BaseCsr::registerAddressSpace(RegisterAttribute *attributeTable,
206 uint_t tableSize,
207 const string &description)
208{
209 //TODO this routine does not take localvs global I/O address into account
210
211 uint64_t start = ULLONG_MAX;
212 uint64_t end = 0;
213
214 for (uint_t tableNdx = 0; tableNdx < tableSize; ++tableNdx) {
215 if (attributeTable[tableNdx].startAddr < start) {
216 start = attributeTable[tableNdx].startAddr;
217 }
218 if (attributeTable[tableNdx].endAddr > end) {
219 // Be sure to cover the entire address range
220 end = attributeTable[tableNdx].endAddr +
221 attributeTable[tableNdx].stride - 1;
222
223 // Die if the stride and the count don't match the
224 // endAddr
225 if (end + 1 < attributeTable[tableNdx].startAddr +
226 attributeTable[tableNdx].stride *
227 attributeTable[tableNdx].count) {
228 ostringstream os;
229 os << "SS_BaseCsr::registerAddressSpace: " <<
230 "bad RegisterAttribute ranges: endAddr 0x" <<
231 hex << end <<
232 " startAddr 0x" << attributeTable[tableNdx].startAddr <<
233 " stride " << dec << attributeTable[tableNdx].stride <<
234 " count\n" << dec << attributeTable[tableNdx].count <<
235 "\n";
236
237 fprintf(stderr, "ERROR: %s\n", os.str().c_str());
238 }
239 }
240 }
241#ifndef COMPILE_FOR_COSIM
242 //TODO we don't have strand pointer here, cannot access sim_state.cosim()
243 //if (!s->sim_state.cosim())
244 SS_Io::io.add(start, end, this, SS_AddressMap::ABS, SS_BaseCsr::access);
245#endif
246}
247
248//=============================================================================
249// when mem==NULL, a paddr that does not match any supported CSR will
250// return INVALID value, this is mainly used by callback corresponding
251// to asi_read. when access.getInternal()==true, it means the
252// read64() is invoked by callback// corresponding to asi_read, the
253// read64() will return INVALID for non-matched paddr, and it will
254// remove a matched entry after the value is returned.
255//=============================================================================
256//======================================================================
257// THIS IS READ64
258//======================================================================
259int
260SS_BaseCsr::read64( SS_Paddr paddr, uint64_t* data, int access, int sid )
261{
262 // for N2, there is only one cpu (i.e., node), so local I/O address is
263 // equal to global I/O address.
264
265 // In general strands in the same cpu use the same global I/O address, but
266 // for CSR follow-me, each strand can have its own follow-me value, so we
267 // need strand-id in follow-me matching up.
268
269 SS_Paddr laddr;
270 SS_Paddr gaddr;
271 if (is_global_addr(paddr))
272 {
273 laddr = global2local(paddr);
274 gaddr = paddr;
275 }
276 else if (sid < 0)
277 {
278 // if it is not a global address, then we need a real strand-id to
279 // convert the address to global address, otherwise it is an error.
280 fprintf(stderr, "ERROR: SS_BaseCsr::read64( paddr=%#llx, sid=%d ): paddr not a global addr\n", paddr, sid);
281 *data = 0;
282 return SS_Io::NOP;
283 }
284 else
285 {
286 laddr = paddr;
287 gaddr = local2global(paddr, sid);
288 }
289 SS_Paddr baddr = addr_node0(paddr);
290 int nid = get_node_id(gaddr);
291
292 // for any read, look at follow-me list first, if a match can be found,
293 // use it (and then discard the entry), otherwise go to real register area.
294 if ((access & SS_BaseCsr::NO_FOLLOW_ME) == 0)
295 {
296 list<FollowMeData>::iterator iter = followme_.begin();
297 for (; iter != followme_.end(); iter++)
298 {
299 // if either side of sid is -1, then pick the first entry that has a
300 // matching addr
301 if (((*iter).addr == gaddr) &&
302 (((*iter).sid == sid) || ((*iter).sid < 0) || (sid < 0)))
303 {
304 *data = (*iter).data;
305 followme_.erase(iter);
306 return SS_Io::FOLLOWME;
307 }
308 }
309 }
310
311 // no matching follow-me, search real CSR
312 uint64_t attributeNdx =
313 findAttributeEntryNdx(baddr, attributeTable_, nrAttributeEntries_);
314 if (attributeNdx != ENTRY_NOT_FOUND)
315 {
316 // attribute table uses node0 addr as keyword, 'value' vector has an
317 // 1-on-1 mapping with attribute table, so node0 addr has to be used.
318 const RegisterAttribute* attribute = &attributeTable_[attributeNdx];
319 RegisterValue *value = attribute->find(baddr, values_[attributeNdx], nid);
320 if (value == NULL)
321 {
322 // this is an error
323 fprintf(stderr, "ERROR: SS_BaseCsr::read64( paddr=%#llx, sid=%d ): null RegisterValue pointer\n", paddr, sid);
324 *data = 0;
325 return SS_Io::NOP;
326 }
327 else
328 {
329 if (!value->valid())
330 {
331 // no valid data for this entry yet, generate it
332 uint64_t init_data;
333 // first, see if the addr has a valid data in mem.image (sometimes
334 // uses this approach to provide a csr's init value other then its
335 // pre-defined por value).
336 int state = read_memimage(gaddr, laddr, &init_data);
337 init_data &= attribute->maskRSVD;
338 if (init_data == 0x0)
339 {
340 // when read_memimage() returns 0, we consider that means no data
341 // for this addr is available in mem.image, so we use the por value
342 // in CSR attribute table.
343 //TODO this can be troublesome, if a real 0x0 value is set for the
344 // addr in mem.image, then we will mistake it as not available,
345 // and use por value instead (wrongly), do we have a way of
346 // knowing whether a valid data is available in mem.image?
347 init_data = attribute->por;
348 }
349 RegisterValue newValue(baddr, init_data, attribute, sid);
350 *value = newValue;
351 }
352 *data = value->data();
353 }
354 }
355 else
356 {
357 // not in csr attribute list, use global addr for non-csr
358 return read64_notCsr( gaddr, laddr, data );
359 }
360 return SS_Io::OK;
361}
362
363//=============================================================================
364// read64_notCsr() reads any non-CSR address
365//=============================================================================
366int
367SS_BaseCsr::read64_notCsr( SS_Paddr gaddr, SS_Paddr laddr, uint64_t* data )
368{
369 // for addr not in csr list, just read it from memory
370 return read_memimage(gaddr, laddr, data);
371}
372
373//=============================================================================
374// when mem==NULL, a paddr that does not match any supported CSR will
375// be silently dropped, this is mainly used by asi_read function.
376// when access.getInternal()==true, it means allwoing write to RO
377// non-reserved field(s) of a register, this is to mimic hardware
378// writing to RO non-reserved field(s).
379//=============================================================================
380int
381SS_BaseCsr::write64( SS_Paddr paddr, uint64_t data, int access, int sid )
382{
383 SS_Paddr laddr;
384 SS_Paddr gaddr;
385 if (is_global_addr(paddr))
386 {
387 laddr = global2local(paddr);
388 gaddr = paddr;
389 }
390 else if (sid < 0)
391 {
392 // if it is not a global address, then we need a real strand-id to
393 // convert the address to global address, otherwise it is an error.
394 fprintf(stderr, "ERROR: SS_BaseCsr::write64( paddr=%#llx, sid=%d ): paddr not a global addr\n", paddr, sid);
395 return SS_Io::NOP;
396 }
397 else
398 {
399 laddr = paddr;
400 gaddr = local2global(paddr, sid);
401 }
402 SS_Paddr baddr = addr_node0(paddr);
403 int nid = get_node_id(gaddr);
404
405 if (access & MemoryTransaction::FOLLOW_ME)
406 {
407 // this is a follow-me write, keep the value in followme_ list
408 FollowMeData fm(gaddr, data, sid);
409 followme_.push_back(fm);
410 return SS_Io::OK;
411 }
412 else
413 {
414 uint64_t attributeNdx =
415 findAttributeEntryNdx(baddr, attributeTable_, nrAttributeEntries_);
416 if (attributeNdx != ENTRY_NOT_FOUND)
417 {
418 const RegisterAttribute* attribute = &attributeTable_[attributeNdx];
419 RegisterValue *value = attribute->find(baddr, values_[attributeNdx], nid);
420 if (value == NULL)
421 {
422 // this is an error
423 fprintf(stderr, "ERROR: SS_BaseCsr::write64( paddr=%#llx, sid=%d ): null RegisterValue pointer\n", paddr, sid);
424 return SS_Io::NOP;
425 }
426 else
427 {
428 uint64_t new_data;
429 uint64_t old_data = attribute->por;
430 if (value->valid())
431 {
432 old_data = value->data();
433 }
434 if ((access & MemoryTransaction::INTERNAL) ||
435 (access & MemoryTransaction::MEM_SLAM))
436 {
437 // allow writing into any non-reserved bits
438 new_data = forceWrite(data, attribute, access);
439 }
440 else
441 {
442 if (attribute->protect != RegisterAttribute::RO)
443 {
444 // can only write into W bits (e.g., WO, RW, RW1C, RW1S, etc)
445 new_data = normalWrite(data, old_data, attribute, access);
446 }
447 else
448 {
449 fprintf(stderr, "WARNING: %s::write64(): paddr=%#llx (gaddr=%#llx) is read-only, data=%#llx is NOT committed\n", className_.c_str(), paddr, gaddr, data);
450 return SS_Io::NOP;
451 }
452 }
453 if (!value->valid())
454 {
455 // the entry is not available yet, create it
456 RegisterValue newValue(baddr, new_data, attribute, sid);
457 *value = newValue;
458 }
459 else
460 {
461 value->set_data(new_data);
462 }
463 }
464 }
465 else
466 {
467 // paddr not in csr list
468 return write64_notCsr( gaddr, data );
469 }
470 }
471 return SS_Io::OK;
472}
473
474//=============================================================================
475// write64_notCsr() reads any non-CSR address
476//=============================================================================
477int
478SS_BaseCsr::write64_notCsr( SS_Paddr gaddr, uint64_t data )
479{
480 // for addr not in csr list, just write it to memory using global-addr
481#ifndef COMPILE_FOR_SAM
482 SS_Memory::memory.poke64(gaddr, data);
483 return SS_Io::OK;
484#else
485 extern SS_Memory *mm1;
486 mm1->st64(gaddr, data);
487 return SS_Io::OK;
488#endif
489}
490
491//=============================================================================
492// even if an addr in question is in CSR list, a diag may have the addr's
493// initial value in mem.image, it can use either local or global addr, so
494// look for those first. Always start with global addr, as that is specific
495// to each node, local addr is shared among nodes. If none is found, then use
496// the pre-defined por value (if one is available). (yes, it is messy, but
497// verification diag wants the flexibility).
498//=============================================================================
499int
500SS_BaseCsr::read_memimage( SS_Paddr gaddr, SS_Paddr laddr, uint64_t* data )
501{
502#ifndef COMPILE_FOR_SAM
503 *data = SS_Memory::memory.peek64(gaddr);
504#else
505 extern SS_Memory *mm1;
506 *data = mm1->ld64(gaddr);
507#endif
508 if ((*data == 0x0) && (gaddr != laddr))
509 {
510 // if not match with global addr, try local addr
511 //TODO this is not perfect, returned value of 0x0 can be
512 // (1) the addr is not in mem.image, (2) the addr is in
513 // mem.image with value 0x0. In here we assume 0x0 means
514 // not in mem.image.
515#ifndef COMPILE_FOR_SAM
516 *data = SS_Memory::memory.peek64(laddr);
517#else
518 extern SS_Memory *mm1;
519 *data = mm1->ld64(laddr);
520#endif
521 }
522 return SS_Io::OK;
523}