Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: ext_sys_mem.cc | |
4 | // Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved | |
5 | // 4150 Network Circle, Santa Clara, California 95054, U.S.A. | |
6 | // | |
7 | // * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
8 | // | |
9 | // This program is free software; you can redistribute it and/or modify | |
10 | // it under the terms of the GNU General Public License as published by | |
11 | // the Free Software Foundation; version 2 of the License. | |
12 | // | |
13 | // This program is distributed in the hope that it will be useful, | |
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | // GNU General Public License for more details. | |
17 | // | |
18 | // You should have received a copy of the GNU General Public License | |
19 | // along with this program; if not, write to the Free Software | |
20 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | // | |
22 | // For the avoidance of doubt, and except that if any non-GPL license | |
23 | // choice is available it will apply instead, Sun elects to use only | |
24 | // the General Public License version 2 (GPLv2) at this time for any | |
25 | // software where a choice of GPL license versions is made | |
26 | // available with the language indicating that GPLv2 or any later version | |
27 | // may be used, or where a choice of which version of the GPL is applied is | |
28 | // otherwise unspecified. | |
29 | // | |
30 | // Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
31 | // CA 95054 USA or visit www.sun.com if you need additional information or | |
32 | // have any questions. | |
33 | // | |
34 | // ========== Copyright Header End ============================================ | |
35 | // Copyright 2001 ADVANCED MICRO DEVICES, INC. All Rights Reserved. | |
36 | // | |
37 | // This software and any related documentation (the "Materials") are the | |
38 | // confidential proprietary information of AMD. Unless otherwise provided | |
39 | // in an agreement specifically licensing the Materials, the Materials are | |
40 | // provided in confidence and may not to be used, distributed, modified, or | |
41 | // reproduced in whole or in part by any means. | |
42 | // | |
43 | // LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED "AS IS" WITHOUT ANY | |
44 | // EXPRESS OR IMPLIED WARRANTY OF ANY KIND, INCLUDING BUT NOT LIMITED TO | |
45 | // WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT, TITLE, FITNESS FOR ANY | |
46 | // PARTICULAR PURPOSE, OR WARRANTIES ARISING FORM CONDUCT, COURSE OF | |
47 | // DEALING, OR USAGE OF TRADE. IN NO EVENT SHALL AMD OR ITS LICENSORS BE | |
48 | // LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, | |
49 | // DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION, OR LOSS OF | |
50 | // INFORMATION) ARISING OUT OF THE USE OF OR INABILITY TO USE THE | |
51 | // MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |
52 | // DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION OR | |
53 | // LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE | |
54 | // ABOVE LIMITATION MAY NOT APPLY TO YOU. | |
55 | // | |
56 | // AMD does not assume any responsibility for any errors which may appear | |
57 | // in the Materials nor any responsibility to support or update the | |
58 | // Materials. AMD retains the right to modify the Materials at any time, | |
59 | // without notice, and is not obligated to provide such modified Materials | |
60 | // to you. | |
61 | // | |
62 | // NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make | |
63 | // any further information, software, technical information, know-how, or | |
64 | // show-how available to you. | |
65 | // | |
66 | // U.S. GOVERNMENT RESTRICTED RIGHTS: The Materials are provided with | |
67 | // "RESTRICTED RIGHTS." Use, duplication, or disclosure by the Government | |
68 | // is subject to the restrictions as set forth in FAR 52.227-14 and DFAR | |
69 | // 252.227-7013, et seq., or its successor. Use of the Materials by the | |
70 | // Government constitutes acknowledgement of AMD's proprietary rights in | |
71 | // them. | |
72 | // | |
73 | //////////////////////////////////////////////////////////////////////////////// | |
74 | ||
75 | /***************************************************************************** | |
76 | * | |
77 | * $RCSfile: ext_sys_mem.cc,v $ | |
78 | * | |
79 | * $Revision: 1.3 $ | |
80 | * $Date: 2008/02/21 09:51:16 $ | |
81 | * $Author: nhussain $ | |
82 | * $State: Exp $ | |
83 | * $Locker: $ | |
84 | * | |
85 | * Copyright (c) 1997 by Advanced Micro Devices, Inc. | |
86 | * | |
87 | * This file is protected by Federal Copyright Law, with all rights | |
88 | * reserved. No part of this file may be reproduced, stored in a | |
89 | * retrieval system, translated, transcribed, or transmitted, in any | |
90 | * form, or by any means manual, electric, electronic, mechanical, | |
91 | * electro-magnetic, chemical, optical, or otherwise, without prior | |
92 | * explicit written permission from Advanced Micro Devices, Inc. | |
93 | * | |
94 | ****************************************************************************/ | |
95 | #include <iostream> | |
96 | #include <stdlib.h> | |
97 | #include <stdio.h> | |
98 | #include "ext_sys_mem.h" | |
99 | #include "vcsuser.h" | |
100 | ||
101 | //////////////////////////////////////////////////////////////////////////////// | |
102 | // | |
103 | // System Memory Model | |
104 | // | |
105 | // Author: Ron Herzer x52085 | |
106 | // | |
107 | // Function: | |
108 | // Implements a 64-Gig memory with 64-bit reads, and 64-bit writes that are | |
109 | // byte-wise granular. Dynamically allocates memory in 512 byte chunks | |
110 | // as needed. | |
111 | // | |
112 | // Data structures: | |
113 | // Uses a 1024 entry hash table for first lookup step for quick access. | |
114 | // Uses binary tree for storing multiple hits to the same hash table index. | |
115 | // Keeps track of last tree node hit for each hash table index for | |
116 | // quick subsequent accesses to the same chunk. | |
117 | // | |
118 | //////////////////////////////////////////////////////////////////////////////// | |
119 | ||
120 | // Constructor clears all valid bits in hash table. | |
121 | SYS_MEM::SYS_MEM () { | |
122 | int i; | |
123 | _ClrMemVal = 0xffffffff; | |
124 | iUseRandom = 0; | |
125 | for (i=0; i<SYS_HTBL_SIZE; i++) htable[i].valid=0; | |
126 | debug = 0; | |
127 | } | |
128 | ||
129 | void SYS_MEM::SetDefaultMemRandom() { | |
130 | iUseRandom = 1; | |
131 | } | |
132 | ||
133 | void SYS_MEM::SetDefaultMemVal(uint val) { | |
134 | iUseRandom = 0; | |
135 | val &= 0xff; | |
136 | io_printf("SYS_MEM::Setting default memory to 0x%02x\n", val); | |
137 | val = val << 8 | val; | |
138 | val = val << 16 | val; | |
139 | _ClrMemVal = val; | |
140 | } | |
141 | ||
142 | ||
143 | void SYS_MEM::dump (char *FileName) { | |
144 | MEMCHUNK *CurK7Block; | |
145 | HTABLE_ENTRY *K7MemTable; | |
146 | HTABLE_ENTRY *NextTableEntry; | |
147 | FILE *memfile; | |
148 | ||
149 | if (0==strcmp(FileName, "-")) { | |
150 | memfile = stdout; | |
151 | } else { | |
152 | memfile = fopen(FileName, "w"); | |
153 | } | |
154 | ||
155 | if (!memfile) { | |
156 | io_printf("SYS_MEM::error - unable to open output file: %s", FileName); | |
157 | } else { | |
158 | io_printf("SYS_MEM::dump dumping memory to %s\n", FileName); | |
159 | } | |
160 | ||
161 | assert(memfile); | |
162 | K7MemTable = (HTABLE_ENTRY *) ReturnHTable(); | |
163 | for (int idx = 0; idx < SYS_HTBL_SIZE; idx++) { | |
164 | NextTableEntry = (HTABLE_ENTRY*) ((int)(K7MemTable) + (idx*(sizeof(HTABLE_ENTRY)))); | |
165 | if (NextTableEntry->valid) { | |
166 | CurK7Block = NextTableEntry->headPtr; | |
167 | dumpMemTree(memfile, CurK7Block, idx); | |
168 | } | |
169 | } | |
170 | fclose(memfile); | |
171 | } | |
172 | ||
173 | ||
174 | void SYS_MEM::dumpMemTree(FILE *memfile, MEMCHUNK *K7Block, int Index) { | |
175 | uint PrintNice; | |
176 | unsigned char K7Data; | |
177 | uint AddrHi, AddrLo; | |
178 | ||
179 | if (K7Block->right) | |
180 | dumpMemTree(memfile, K7Block->right, Index); | |
181 | if (K7Block->left) | |
182 | dumpMemTree(memfile, K7Block->left, Index); | |
183 | ||
184 | AddrLo = uint(K7Block->tag & 0xffffffffllu) | ((Index & 0x3ff) << 9); | |
185 | AddrHi = uint(K7Block->tag >> 32); | |
186 | ||
187 | if (AddrHi) | |
188 | fprintf(memfile, "@%02x_%08x\n", AddrHi, AddrLo); | |
189 | else | |
190 | fprintf(memfile, "@%08x\n", AddrLo); | |
191 | ||
192 | for(int idx = 0; idx < SYS_CHUNK_SIZE; idx++) { | |
193 | PrintNice = (idx + 1) % 16; | |
194 | K7Data = read(AddrHi, AddrLo+idx); | |
195 | if (PrintNice && (idx < (SYS_CHUNK_SIZE - 1))) | |
196 | fprintf(memfile, "%02x ", (K7Data & 0xff)); | |
197 | else | |
198 | fprintf(memfile, "%02x\n", (K7Data & 0xff)); | |
199 | } | |
200 | } | |
201 | ||
202 | ||
203 | // *************************************************************************** | |
204 | // Get upto a 64 bit address from the given string (Note: '_' are | |
205 | // allowed as delimiters within the address field). | |
206 | // *************************************************************************** | |
207 | int SYS_MEM::GetAddressFromString(char *InputBuffer, unsigned int *Addr) { | |
208 | static char AddrBufferHi[128]; // May hold 64bit address + delimiters | |
209 | static char AddrBufferLo[8+1]; // Only ever hold 4GB of address | |
210 | bool retVal = true; | |
211 | bool FoundNonZero = false; | |
212 | ||
213 | char *destptr = AddrBufferHi; // strip out '_'s, strip off leading '0's | |
214 | for (char *srcptr = InputBuffer; srcptr && *srcptr; srcptr++) { | |
215 | switch (*srcptr) { | |
216 | case '_': continue; | |
217 | case '0': if (!FoundNonZero) continue; break; | |
218 | default: FoundNonZero = true; break; | |
219 | } | |
220 | if (!isxdigit(*srcptr)) retVal = false; | |
221 | *destptr = *srcptr; | |
222 | destptr++; | |
223 | } | |
224 | *destptr = '\0'; | |
225 | assert(strlen(AddrBufferHi) <= 16); | |
226 | if (strlen(AddrBufferHi) <= 8) { // defined AddrHi, AddrLo | |
227 | strcpy(AddrBufferLo, strlen(AddrBufferHi) ? AddrBufferHi : "0"); // Were only zeroes there? | |
228 | strcpy(AddrBufferHi, "0"); | |
229 | } else { | |
230 | strcpy(AddrBufferLo, AddrBufferHi + (strlen(AddrBufferHi) - 8)); | |
231 | *(AddrBufferHi + (strlen(AddrBufferHi) - 8)) = '\0'; | |
232 | } | |
233 | // scan them in | |
234 | retVal &= (sscanf(AddrBufferHi, "%x", Addr + 1)) ? true : false; | |
235 | retVal &= (sscanf(AddrBufferLo, "%x", Addr )) ? true : false; | |
236 | return retVal; | |
237 | } | |
238 | ||
239 | ||
240 | // Load memory from .vram or .sim file. | |
241 | // Should only be called once at the beginning of simulation. | |
242 | // There is no function to deallocate any existing chunks. | |
243 | ||
244 | // *************************************************************************** | |
245 | void SYS_MEM::load (FILE *memfile, char *Filename, | |
246 | long long unsigned int addrLimitLow, long long unsigned int addrLimitHigh) { | |
247 | const uint bufferSize = 0x100; | |
248 | char line[bufferSize << 1]; // buffer is 2x since worst case bufferSize chars could be sneaked | |
249 | char word[bufferSize]; | |
250 | char *lptr, *wptr; | |
251 | char *chkptr; | |
252 | char *filename = const_cast<char *>(Filename ? Filename : "<RAM FILE>"); | |
253 | char overFlow = '\n'; | |
254 | uint SkipOverFlow = 0; | |
255 | uint overFlowCount; | |
256 | uint CommentActive = 0x0; // Needed for comments that exceed the bufferSize | |
257 | // 0x0 - Not active | |
258 | // 0x1 - Starting this line | |
259 | // 0x2 - Continuing | |
260 | // 0x4 - Ending this line | |
261 | dword address[2] = {0,0}; // assumes address starts at 0 if first @address not specified. | |
262 | dword data1,data0, dat; | |
263 | static uint ErrorCnt = 0; // Retain the knowledge that were already dead if multiple images are loaded | |
264 | uint ErrorCntLimit = 0xffffffff; | |
265 | uint Done = ErrorCnt; | |
266 | uint LineNum = 0; | |
267 | byte be; | |
268 | uint linechkDone = 0, linechkErr; | |
269 | uint FoundAddr = ErrorCnt; // Only flag first instance (if there's another error)... | |
270 | uint FoundData = ErrorCnt; // Only flag first instance (if there's another error)... | |
271 | ||
272 | rewind (memfile); // Rewind the file in case this was previously loaded | |
273 | ||
274 | // load data in vram or sim file. - memfile should always be valid | |
275 | if (!memfile) { | |
276 | io_printf("SYS_MEM load error! Could not open memory file, %s, for reading.\n", filename); | |
277 | } | |
278 | ||
279 | // specifically check for NULL characters since some sim files | |
280 | // (randomly generated) have been noted to have NULL in file | |
281 | for (char prechk = fgetc(memfile); (prechk != EOF) && !Done; prechk = fgetc(memfile)) { | |
282 | if (prechk == 0) { | |
283 | io_printf("SYS_MEM::error - .sim load error: Found Null character in memory file, %s, at position: %u\n", | |
284 | filename, ftell(memfile)); | |
285 | //Rc->Finish(); | |
286 | ErrorCnt++; | |
287 | if (ErrorCnt >= ErrorCntLimit) | |
288 | Done++; | |
289 | } | |
290 | } | |
291 | rewind(memfile); // Reset the file pointer | |
292 | ||
293 | while ((fgets(line, bufferSize, memfile)) && !Done) { | |
294 | if (SkipOverFlow && (CommentActive & 0x1)) | |
295 | CommentActive = 0; // This was a comment that started and ended on the same line... | |
296 | ||
297 | SkipOverFlow = 0; | |
298 | linechkDone = 0; | |
299 | ||
300 | lptr = line; // pointer to line | |
301 | ||
302 | // Initialize here so overFlow is done once per buffer read... | |
303 | overFlowCount = 0; | |
304 | for (chkptr = line; chkptr && *chkptr; chkptr++) { | |
305 | overFlowCount++; | |
306 | overFlow = *chkptr; | |
307 | } | |
308 | overFlowCount--; | |
309 | if (chkptr && (overFlow == '\n')) | |
310 | SkipOverFlow = 1; | |
311 | ||
312 | if (CommentActive & 0x4) | |
313 | CommentActive = 0; // Continued comment ended last line | |
314 | ||
315 | if (overFlow == '\n') { | |
316 | if (CommentActive & 0x3) | |
317 | CommentActive = 0x4; // Continuing comment ending this line | |
318 | else | |
319 | CommentActive = 0; | |
320 | LineNum++; | |
321 | } | |
322 | else if (CommentActive & 0x3) | |
323 | CommentActive = 0x2; // Comment continuing | |
324 | ||
325 | if (!(CommentActive & 0x6)) { | |
326 | for (chkptr = line; chkptr && *chkptr && !linechkDone; chkptr++) { | |
327 | linechkErr = 0; | |
328 | if (*chkptr == '/') { | |
329 | if (!(*(chkptr + 1))) linechkErr = 1; // not quite a Comment | |
330 | else if (*(chkptr + 1) == '/') { | |
331 | linechkDone = 1; // Comment for rest of line... | |
332 | CommentActive = 0x1; | |
333 | } | |
334 | } else { | |
335 | // In general, overFlowCount should never get larger than one since a byte will typically be | |
336 | // split -- don't forget about the possibility of a split address. | |
337 | if (!SkipOverFlow) { | |
338 | while (*line && (overFlowCount < ((bufferSize << 1)-1)) && (!isspace(line[overFlowCount]))) { | |
339 | overFlow = fgetc(memfile); | |
340 | //io_printf("Found line[%u] '%c', Line %4u sneaking char '%c' from stream", | |
341 | // overFlowCount, line[overFlowCount], LineNum, overFlow); | |
342 | if (overFlow == EOF) | |
343 | overFlow = '\n'; | |
344 | else if (overFlow == '\n') { | |
345 | ungetc(overFlow, memfile); | |
346 | LineNum++; | |
347 | } | |
348 | ++overFlowCount; | |
349 | line[overFlowCount] = overFlow; | |
350 | if (!overFlow) // Null terminates string and overflow search... | |
351 | overFlowCount = (bufferSize << 1); | |
352 | } | |
353 | assert(overFlowCount < (bufferSize << 1)); | |
354 | line[overFlowCount+1] = '\0'; | |
355 | } | |
356 | ||
357 | if (!( isxdigit(*chkptr) | |
358 | || isspace(*chkptr) | |
359 | || (*chkptr == '_') // Allow '_' delimiters in addresses... | |
360 | || (*chkptr == '@') | |
361 | )) linechkErr = 1; | |
362 | ||
363 | } | |
364 | ||
365 | if (linechkErr) { | |
366 | io_printf("SYS_MEM::error - .sim load error: found illegal character '%c' in non-commented fields on line %u.\n",*chkptr, LineNum); | |
367 | //Rc->Finish(); | |
368 | ErrorCnt++; | |
369 | if (ErrorCnt >= ErrorCntLimit) | |
370 | linechkDone = 1; // already exceeded error limit | |
371 | } | |
372 | } | |
373 | } | |
374 | ||
375 | #ifdef DEBUG_COMMENTS | |
376 | if (CommentActive & 0x4) | |
377 | io_printf("Line %4u is a ending comment -%s-\n", LineNum-1, line); | |
378 | else if (CommentActive & 0x2) | |
379 | io_printf("Line %4u is a continuing comment -%s-\n", LineNum, line); | |
380 | else if (CommentActive & 0x1) | |
381 | io_printf("Line %4u is a new comment -%s-\n", LineNum, line); | |
382 | else | |
383 | io_printf("Line %4u is not a comment -%s-\n", LineNum, line); | |
384 | #endif | |
385 | ||
386 | while ((lptr && *lptr && (*lptr != '\n') && (sscanf(lptr,"%s",word)==1)) && !Done) | |
387 | { // get the next word on the line | |
388 | if (ErrorCnt >= ErrorCntLimit) { | |
389 | io_printf("SYS_MEM::Error Limit exceeded: run with --assertions_warnings_only if a complete list is needed\n"); | |
390 | Done++; | |
391 | } | |
392 | ||
393 | wptr = word; | |
394 | // skip comment lines (or comments at end of line) -- Note: already checked that '/' equates to '//' | |
395 | if (!(CommentActive & 0x6) && (*wptr != '/')) { | |
396 | if (*wptr=='@') { // found new address | |
397 | FoundAddr++; | |
398 | ++wptr; | |
399 | if (!GetAddressFromString(wptr, address)) { | |
400 | io_printf("SYS_MEM::Error while reading .sim file, %s:%u, unable to determine address from %s\n", | |
401 | filename, LineNum, wptr); | |
402 | //Rc->Finish(); | |
403 | ErrorCnt++; | |
404 | } | |
405 | } else { // write byte | |
406 | if (!sscanf(wptr,"%x",&dat)) { | |
407 | io_printf("SYS_MEM:: .sim load error: At %x%08x, Data '%s' is not a hex number at %s:%u\n", | |
408 | address[1], address[0], wptr, filename, LineNum); | |
409 | //Rc->Finish(); | |
410 | ErrorCnt++; | |
411 | } else if (dat > 0xff) { | |
412 | io_printf("SYS_MEM:: .sim load error: Detected byte data '0x%02x' at %s:%u\n", | |
413 | dat, filename, LineNum); | |
414 | //Rc->Finish(); | |
415 | ErrorCnt++; | |
416 | } | |
417 | FoundData++; | |
418 | data1 = dat<<8*3&0xff000000 | dat<<8*2&0xff0000 | dat<<8*1&0xff00 | dat&0xff; | |
419 | data0 = data1; | |
420 | // decode byte enables & write byte to memory | |
421 | be=0x1<<((address[0])&0x7); | |
422 | ||
423 | long long unsigned int addressLong = ((long long unsigned int)(address[1]) << 32) | (long long unsigned int)address[0]; | |
424 | if (!(addrLimitLow || addrLimitHigh) || // Limits not enabled | |
425 | ((addrLimitLow <= addressLong) && (addressLong <= addrLimitHigh))) { | |
426 | // DEBUG PRINT | |
427 | // printf("load %s: Addr: %02x_%08x (%02x) %02x\n", filename, address[1], address[0], (be & 0x000000ff), data0); | |
428 | write(address[1],address[0],be,data1,data0); | |
429 | } | |
430 | ||
431 | address[0]++; | |
432 | if (!address[0]) address[1]++; // increment addr[63:32] on wrap around of addr[31:0]. | |
433 | } | |
434 | } | |
435 | else lptr=NULL; // forget everything after comment | |
436 | // look for next space | |
437 | while(lptr && (*lptr != '\0') && isspace(*lptr)) lptr++; // skip whitespace within string | |
438 | // lptr=strstr(lptr," "); // note: returns null if not found | |
439 | while(lptr && (*lptr != '\0') && !isspace(*lptr)) lptr++; // skip whitespace | |
440 | } | |
441 | } | |
442 | if (!FoundAddr) | |
443 | io_printf("SYS_MEM::No address specifier in .sim file, %s. The assembler/user must know exactly what's going on...\n", filename); | |
444 | if (!FoundData) { | |
445 | io_printf("SYS_MEM:: No data bytes found in .sim file, %s\n", filename); | |
446 | //Rc->Finish(); // Stop (this will be at the beginning of time... | |
447 | } | |
448 | } | |
449 | ||
450 | ||
451 | // *************************************************************************** | |
452 | // Specific check for NULL characters since some sim files (randomly generated | |
453 | // ones) have been noted to have NULL characters in the file. | |
454 | // *************************************************************************** | |
455 | int SYS_MEM::PreCheckError(FILE *memfile, char *filename) { | |
456 | bool Done = false; | |
457 | rewind (memfile); // Rewind the file in case this was previously loaded | |
458 | for (char prechk = fgetc(memfile); (prechk != EOF) && !Done; prechk = fgetc(memfile)) { | |
459 | if (prechk == '\0') { | |
460 | io_printf("SYS_MEM:: .sim load error: Found Null character in memory file, %s, at position: %u\n", | |
461 | filename, ftell(memfile)); | |
462 | //Rc->Finish(); | |
463 | Done |= true; | |
464 | } | |
465 | } | |
466 | rewind(memfile); // Reset the file pointer | |
467 | return (Done); | |
468 | } | |
469 | ||
470 | ||
471 | // *************************************************************************** | |
472 | // Memory Read QW | |
473 | // Maximum address size = 64 bits. Aligned to QW boundary. (A[2:0] not used) | |
474 | // Always returns a QW in {data1,data0}. | |
475 | ||
476 | void SYS_MEM::read (dword addrh, dword addrl, dword *data1, dword *data0) | |
477 | { | |
478 | long long unsigned int addr; | |
479 | long long unsigned int tag; | |
480 | uint idx; | |
481 | uint offset; | |
482 | MEMCHUNK* current; | |
483 | uint randh; | |
484 | uint randl; | |
485 | uint _RandomClrMemVal1; | |
486 | uint _RandomClrMemVal0; | |
487 | ||
488 | addr = (((long long unsigned int)addrh)<<32) | addrl; | |
489 | tag = addr & ~0x7ffffllu; // tag = addr[63:SYS_CHUNK_BITS] | |
490 | ||
491 | // extract hash table index addr[18:9], and chunk offset addr[8:3]: | |
492 | idx = addrl>>9 & 0x3ff; | |
493 | offset = addrl>>2 & 0x7e; // note: zero out bit 2 | |
494 | ||
495 | // see if valid entry exists in hash table: | |
496 | if (htable[idx].valid) { | |
497 | ||
498 | // look for tag match (first check most recent access): | |
499 | if (htable[idx].mraPtr->tag==tag) { // most common case! | |
500 | *data1=htable[idx].mraPtr->data[offset+1]; | |
501 | *data0=htable[idx].mraPtr->data[offset]; | |
502 | ||
503 | } else { // find chunk in tree | |
504 | current = htable[idx].headPtr; | |
505 | while (current && current->tag!=tag) { | |
506 | if (tag > current->tag) { | |
507 | current = current->right; | |
508 | } else { | |
509 | current = current->left; | |
510 | } | |
511 | } | |
512 | if (current) { | |
513 | *data1=current->data[offset+1]; | |
514 | *data0=current->data[offset]; | |
515 | htable[idx].mraPtr=current; | |
516 | } else { // not in chunk tree | |
517 | if (iUseRandom) { | |
518 | randh = rand(); | |
519 | randl = rand(); | |
520 | randh = randh << 16; | |
521 | _RandomClrMemVal1 = randh | randl; | |
522 | *data1 = _RandomClrMemVal1; | |
523 | randh = rand(); | |
524 | randl = rand(); | |
525 | randh = randh << 16; | |
526 | _RandomClrMemVal0 = randh | randl; | |
527 | *data0 = _RandomClrMemVal0; | |
528 | // create memory location with this random data | |
529 | write(addrh,addrl,0xff,_RandomClrMemVal1,_RandomClrMemVal0); | |
530 | } else { | |
531 | *data1=_ClrMemVal; | |
532 | *data0=_ClrMemVal; | |
533 | } | |
534 | } | |
535 | } | |
536 | ||
537 | } else { // hash table entry not valid | |
538 | if (iUseRandom) { | |
539 | randh = rand(); | |
540 | randl = rand(); | |
541 | randh = randh << 16; | |
542 | _RandomClrMemVal1 = randh | randl; | |
543 | *data1 = _RandomClrMemVal1; | |
544 | randh = rand(); | |
545 | randl = rand(); | |
546 | randh = randh << 16; | |
547 | _RandomClrMemVal0 = randh | randl; | |
548 | *data0 = _RandomClrMemVal0; | |
549 | // create memory location with this random data | |
550 | write(addrh,addrl,0xff,_RandomClrMemVal1,_RandomClrMemVal0); | |
551 | } else { | |
552 | *data1=_ClrMemVal; | |
553 | *data0=_ClrMemVal; | |
554 | } | |
555 | } | |
556 | } | |
557 | ||
558 | ||
559 | // *************************************************************************** | |
560 | // Memory Read QW - long long version | |
561 | // Maximum address size = 64 bits. Aligned to DW boundary. (A[1:0] not used) | |
562 | // Always returns a QW in {data}. | |
563 | long long unsigned int SYS_MEM::read (long long unsigned int addr, long long unsigned int *data) { | |
564 | uint data1, data0; | |
565 | uint addr1 = uint(addr >> 32); | |
566 | uint addr0 = uint(addr & 0xffffffff); | |
567 | ||
568 | read (addr1, addr0, &data1, &data0); | |
569 | *data = ((long long unsigned int)(data1) << 32) | (long long unsigned int)data0; | |
570 | return *data; | |
571 | } | |
572 | ||
573 | ||
574 | // *************************************************************************** | |
575 | // Memory Read DW | |
576 | // Maximum address size = 64 bits. Aligned to DW boundary. (A[1:0] not used) | |
577 | // Always returns a DW in {data}. | |
578 | uint SYS_MEM::read (dword addrh, dword addr, dword *data) { | |
579 | uint data1, data0; | |
580 | ||
581 | read (addrh, addr, &data1, &data0); | |
582 | if (addr & 0x4) *data = data1; | |
583 | else *data = data0; | |
584 | return *data; | |
585 | } | |
586 | ||
587 | ||
588 | // *************************************************************************** | |
589 | // Memory Read Byte | |
590 | // Maximum address size = 64 bits. | |
591 | unsigned char SYS_MEM::read (dword addrh, dword addr) | |
592 | { | |
593 | uint data; | |
594 | ||
595 | read (addrh, addr, &data); | |
596 | data = (data >> ((addr & 0x3)*8)) & 0xff; | |
597 | return ((unsigned char) (data)); | |
598 | } | |
599 | ||
600 | ||
601 | // *************************************************************************** | |
602 | // Memory Read - arbitrary Size | |
603 | unsigned char * SYS_MEM::read (dword addrh, dword addr, uint Size) { | |
604 | unsigned char * retVal = NULL; | |
605 | if (!Size) | |
606 | io_printf("Error: Zero size passed to SYS_MEM::read(...)\n"); | |
607 | else { | |
608 | retVal = new unsigned char [Size]; | |
609 | for (unsigned int idx = 0; idx < Size; idx++) | |
610 | retVal[idx] = '\0'; | |
611 | for (uint idx = 0; idx < Size; idx++) { | |
612 | retVal[idx] = read(addrh, addr); | |
613 | if (addr == ~uint(0x0)) // Generate carry for upper address | |
614 | addrh++; | |
615 | addr++; | |
616 | } | |
617 | } | |
618 | return (retVal); | |
619 | } | |
620 | ||
621 | ||
622 | // *************************************************************************** | |
623 | // Memory Read (one Bit) | |
624 | // Maximum address size = 64 bits. Aligned to DW boundary. (A[1:0] not used) | |
625 | // returns a bit | |
626 | uint SYS_MEM::readBit (dword addrh, dword addr, dword bitField) { | |
627 | uint retVal; | |
628 | ||
629 | //if (!bitField) Rc->Assertion(bitField, "bitField must be defined in readBit()\n"); | |
630 | read (addrh, addr, &retVal); | |
631 | return (retVal & bitField); | |
632 | } | |
633 | ||
634 | ||
635 | // *************************************************************************** | |
636 | // Memory Write Byte | |
637 | void SYS_MEM::write (dword addrh, dword addr, byte data) { | |
638 | byte be = 0x1 << (addr & 0x3); | |
639 | write(addrh, (addr & ~0x3), be, dword(data)); | |
640 | } | |
641 | ||
642 | ||
643 | // *************************************************************************** | |
644 | // Memory Write QW - long long version | |
645 | // Aligned to QW boundary. (A[2:0] not used). Always uses a QW in {data}. | |
646 | void SYS_MEM::write (long long unsigned int addr, byte be, long long unsigned int data) { | |
647 | uint addr1 = uint(addr >> 32); | |
648 | uint addr0 = uint(addr & 0xffffffff); | |
649 | uint data1 = uint(data >> 32); | |
650 | uint data0 = uint(data & 0xffffffff); | |
651 | write (addr1, addr0, be, data1, data0); | |
652 | } | |
653 | ||
654 | ||
655 | // *************************************************************************** | |
656 | // Memory Write DW | |
657 | // Aligned to DW boundary. (A[1:0] not used). Always uses a DW in {data}. | |
658 | void SYS_MEM::write (dword addrh, dword addr, byte be, dword data) { | |
659 | if (be > 0xf) | |
660 | printf("SYS_MEM::write(dWord), inappropriate byte enables (%u) sent\n", be); | |
661 | be &= 0xf; | |
662 | if (addr & 0x4) | |
663 | be = be << 4; | |
664 | write (addrh, addr, be, data, data); | |
665 | } | |
666 | ||
667 | ||
668 | // *************************************************************************** | |
669 | // Memory Write | |
670 | // Maximum address size = 64 bits. Aligned to QW boundary. (A[2:0] not used) | |
671 | // Uses the QW in {data1,data0} and updates bytes whose byte enable (be[7:0]) is set. | |
672 | ||
673 | void SYS_MEM::write (dword addrh, dword addrl, byte be, dword data1, dword data0) | |
674 | { | |
675 | long long unsigned int addr; | |
676 | long long unsigned int tag; | |
677 | uint idx; | |
678 | uint offset; | |
679 | MEMCHUNK* current; | |
680 | dword temp1, temp0; | |
681 | byte byte7,byte6,byte5,byte4,byte3,byte2,byte1,byte0; | |
682 | int cont; | |
683 | int i; | |
684 | int added_chunk; | |
685 | uint randh; | |
686 | uint randl; | |
687 | uint _RandomClrMemVal; | |
688 | ||
689 | addr = (((long long unsigned int)addrh)<<32) | addrl; | |
690 | tag = addr & ~0x7ffffllu; // tag = addr[63:SYS_CHUNK_BITS] | |
691 | cont = 1; | |
692 | added_chunk = 0; | |
693 | ||
694 | // extract hash table index addr[18:9], and chunk offset addr[8:3]: | |
695 | idx = addrl>>9 & 0x3ff; | |
696 | offset = addrl>>2 & 0x7e; // note: zero out bit 2 | |
697 | ||
698 | // see if valid entry exists in hash table: | |
699 | if (htable[idx].valid) { | |
700 | // look for tag match (first check most recent access): | |
701 | if (htable[idx].mraPtr->tag==tag) { // most common case! | |
702 | current=htable[idx].mraPtr; | |
703 | } | |
704 | else { // find chunk in tree | |
705 | current = htable[idx].headPtr; | |
706 | while(current && current->tag!=tag && cont) { | |
707 | if (tag>current->tag && current->right) { current = current->right; } | |
708 | else if (tag<=current->tag && current->left) { current = current->left; } | |
709 | else { cont=0; } | |
710 | } | |
711 | if (current && current->tag!=tag) { // not in chunk tree | |
712 | // add entry to chunk tree | |
713 | if (tag>current->tag) { | |
714 | current->right= (MEMCHUNK *) malloc(sizeof(MEMCHUNK)); | |
715 | if (current) { current=current->right; added_chunk=1;} | |
716 | } | |
717 | else { | |
718 | current->left= (MEMCHUNK *) malloc(sizeof(MEMCHUNK)); | |
719 | if (current) { current=current->left; added_chunk=1;} | |
720 | } | |
721 | } | |
722 | } | |
723 | } | |
724 | else { // hash table entry not valid | |
725 | // add entry into hash table | |
726 | htable[idx].headPtr= (MEMCHUNK *) malloc(sizeof(MEMCHUNK)); | |
727 | htable[idx].valid=1; | |
728 | current=htable[idx].headPtr; | |
729 | added_chunk=1; | |
730 | } | |
731 | ||
732 | if (current) { // write data | |
733 | if (added_chunk) { | |
734 | current->right=NULL; | |
735 | current->left=NULL; | |
736 | current->tag=tag; | |
737 | for (i=0; i<SYS_CHUNK_SIZE/4; i++) { | |
738 | if (iUseRandom) { | |
739 | randh = rand(); | |
740 | randl = rand(); | |
741 | randh = randh << 16; | |
742 | _RandomClrMemVal = randh | randl; | |
743 | current->data[i] = _RandomClrMemVal; | |
744 | } else { | |
745 | current->data[i] = _ClrMemVal; | |
746 | } | |
747 | } | |
748 | } | |
749 | temp1=current->data[offset+1]; | |
750 | temp0=current->data[offset]; | |
751 | byte7= (be&0x80) ? (data1>>3*8) : (temp1>>3*8); | |
752 | byte6= (be&0x40) ? (data1>>2*8) : (temp1>>2*8); | |
753 | byte5= (be&0x20) ? (data1>>1*8) : (temp1>>1*8); | |
754 | byte4= (be&0x10) ? (data1) : (temp1); | |
755 | byte3= (be&0x08) ? (data0>>3*8) : (temp0>>3*8); | |
756 | byte2= (be&0x04) ? (data0>>2*8) : (temp0>>2*8); | |
757 | byte1= (be&0x02) ? (data0>>1*8) : (temp0>>1*8); | |
758 | byte0= (be&0x01) ? (data0) : (temp0); | |
759 | current->data[offset+1]= byte7<<3*8&0xff000000 | byte6<<2*8&0xff0000 | byte5<<1*8&0xff00 | byte4&0xff; | |
760 | current->data[offset] = byte3<<3*8&0xff000000 | byte2<<2*8&0xff0000 | byte1<<1*8&0xff00 | byte0&0xff; | |
761 | htable[idx].mraPtr=current; | |
762 | } | |
763 | else io_printf("SYS_MEM write error! Could not allocate memory...\n"); | |
764 | } |