-
Notifications
You must be signed in to change notification settings - Fork 1
/
generic_memory.vr
689 lines (622 loc) · 25.9 KB
/
generic_memory.vr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
// See LICENSE for license details.
/*************************************************************************
** From Perforce:
**
** $Id: //Smart_design/Smash_rel/TestCommonLib/Memory/generic_memory.vr#1 $
** $DateTime: 2008/01/04 23:17:34 $
** $Change: 6220 $
** $Author: zasgar $
*************************************************************************/
// Revision History
//
// Date Author Description
// 5-Sep-06 Ofer Initial version
// 4-Jan-07 Alex Implementeded sim_io
// is_random_value should be 0 by default
// 31-Jan-07 shacham shifted sim_io implementation to MemCtrl_dummy.vr
//
#ifndef INC_GENERIC_MEMORY
#define INC_GENERIC_MEMORY
//////////////////////////////////////////////////////////////////////////////
// File name: generic_mem.vr
// This file contains a (zero latency) model of the main memory
//////////////////////////////////////////////////////////////////////////////
/*******************************************************************************
* Memory Help and FAQ:
* =====================
* This is an implementation of a fully associative memory. This means that the
* user does not need to allocate any memory, and yet can write/read to/from any
* memory location. The memory is composed of two arrays: data array (32 bits)
* and meta_data array (6 bits).
* Any write/read is activated on both arrays simultaniously. For writes, the
* user must specify the data byte mask whether the meta data is valid or not.
* For reads, it is up to the user to choose which information he wants to use
* and which to discard.
*
* How to instantiate the memory module?
* ----------------------------------------
* In order to instantiate the generic memory module do the following:
* 1. At the top part of the file, add this statement:
* #include "generic_memory.vrh"
* 2. Instatiate the memory module by this statement:
* generic_memory <instance_name>;
* 3. Allocate the memory by using the "<instance_name> = new(...)" statment.
* (see task "new()" below)
*
* How to initialize the memory for my own use?
* ----------------------------------------------
* 1. The generic memory is initialized by default to produce random data for
* every address that was not previously written. However, you can change
* these definition by using the SetRandomParams task (see below).
* 2. To start the operation of the memory use the run() task.
* 3. To stop the operation of the memory use the stop_me() task. (This is
* important to do since this task is in-charge of finalizing the log file.)
*
* How to use the memory module?
* -------------------------------
* The generic memory class provides the user with specific and well defined
* interface tasks and functions. Please use those functions and do not use any
* direct reference to the class members.
* Among these tasks/functions are (see elaboration below):
* WriteData, ReadData, Empty, Size, GetClosestIndx
*
* WHAT PITFALLS SHOULD I BE AWARE OF?
* ----------------------------------------
* The only pitfall I can think of at this moment is the following: When the
* test is suppose to read a value from main memory and from local memory. If
* that specific address was not previously written, each memory will return
* its own random data. Those may or may not be identical.
* To prevent this situation, for this kind of tests it is better to set both
* memories as NOT random (this can be done by calling the task
* "SetRandomParams(0, <default_data_val>, <default_meta_data_val>)" of all
* relevant memories.
*
*
* generic_memory interface tasks/functions:
* ============================================
* task generic_memory::WriteData(bit [31:0] addr, bit[31:0] data,
* bit [3:0] byte_mask, bit [5:0] meta,
* bit meta_byte_mask
* [, string comment = "",
* integer written_by=TESTER_ID]);
* task generic_memory::ReadData(bit [31:0] addr, var bit[31:0] data,
* var bit [5:0] meta[, string comment]);
* function bit generic_memory::Empty() - returns 1 if memory is empty
* function integer generic_memory::Size() - returns current size of memory
* function integer generic_memory::GetClosestIndx(var bit [31:0] indx,
* bit [31:0] range_high = 32'hffff_ffff,
* bit [31:0] range_low = 32'h0000_0000,
* bit [31:0] pattern = 32'h0000_0000,
* bit [31:0] pattern_mask = 32'h0000_0000) -
* Sets <indx> to the closest allocated index to the input <indx> with
* the condition that:
* 1. The new index found is with in the given range and
* 2. The new index found match the given <pattern> according to the
* <pattern_mask>
* This means (<indx> & <pattern_mask>) == (<pattern> & <pattern_mask>)
* If the index can not be found the function returns 0, else it returns 1.
*
* Example: Assume the user writes only to addresses 32'h5, 32'h46 ,32'h5e
* and 32'hee. Also assume indx=7. A call to GetClosestIndx(<indx>) will set
* <indx> to the closest index to 7 (which is greater than 7). In this
* example this is index 32'h46.
* For the same example, a call to GetClosestIndx(<indx>,32'h10, 32'h30) will
* return 0 as there is no index in the range, and <indx> will not be changed
* Also For the same example, a call to GetClosestIndx(<indx>,*,*,
* 32'he,32'hf) will return 1 and <indx> will be set to 32'h5e because this is
* the first index to match the given pattern and mask.
*
* task UploadFile(string file_name, bit [31:0] base_addr = 0,
* string new_indx_sign = "@", integer word_size);
* UploadFile is a task that receive for a given file name, openes the
* file, read its content and write it to the memory.
* <file_name> is the file name to open
* <base_addr> is an offset that all indices are calculated accordingly. For
* example, the base address for instruction is usually 0x4000_0000.
* <new_indx_sign> is a string, representing a new index for the following data
* words.
* <word_size> is the size of every word in the file (given in bytes).
* Example:
* "01234567 // word1
* 89abcdef // word2
* @12 // new index
* babebabe // word3
* cafecafe" // word4
* In the above code: word1 will be written to address=<base_addr>, while word2
* will be written to address=<base_addr>+<word_size> and word3 will be written
* to address=<base_addr>+12*<word_size>.
* In other notation, this is:
* Mem[<base_addr>+<word_size>-1:<base_addr>]<=01234567
* Mem[<base_addr>+2*<word_size>-1:<base_addr>+<word_size>]<=89abcdef
* Mem[<base_addr>+13*<word_size>-1:<base_addr>+12*<word_size>]<=babebabe
* Mem[<base_addr>+14*<word_size>-1:<base_addr>+13*<word_size>]<=cafecafe
*
* Initialization Tasks:
* ======================
* generic_memory::new
* * _DEBUG: sets the debug level for verbosity of messages.
* * my_agent_name_: Name of agent that to which this instance belongs
* * my_agent_ID_: This parameter will be used in the future for multiple
* main memories (in system environment etc).
* * my_prefix_: Used to determine the prefix of the log file. Log file
* is then written to "<my_prefix_>Mem.log"
* task generic_memory::new(integer _DEBUG, string my_agent_name_,
* integer my_agent_ID_, string my_prefix_,
* integer entity_ID)
*
* generic_memory::SetRandomParams:
* This task initializes the random params of the memory:
* is_random_value: '1' means use random values for reads of addresses
* that where not written. '0' means use the default_data_value and
* the default_meta_data_value.
* task generic_memory::SetRandomParams(bit is_random_value_,
* bit [31:0] default_data_value_=0,
* bit [5:0] default_meta_data_value_=0)
*
******************************************************************************/
//------------------------------------------------------------------------------
//----- Include Related Files Here
//------------------------------------------------------------------------------
// Main source file for quad testbench
#include <vera_defines.vrh>
#include <VeraErrorHandler.vrh>
// define interfaces, and verilog_node here if necessary
#include "Quad_def.vrh"
#include "generic_master.vrh"
//------------------------------------------------------------------------------
//----- Place Special Definitions and Extern Declarations Here
//------------------------------------------------------------------------------
extern bit RunWithTrace;
//------------------------------------------------------------------------------
//----- Place Main Class Declaration Here
//------------------------------------------------------------------------------
class generic_memory extends GENERIC_master
{
// control variables
//-------------------
protected integer active;
protected string my_agent_name;
protected integer my_agent_ID;
protected string my_prefix;
protected integer my_ID;
protected integer _DEBUG_;
protected integer semID; // use semaphore to arbitrate reads and writes
static protected bit is_random_value; // all memories should have the same random status
static protected bit [31:0] default_data_value;
static protected bit [5:0] default_meta_data_value;
// Associative arrays
//---------------------
protected bit [31:0] assoc_data[];
protected bit [5:0] assoc_meta_data[];
// Handles to log files:
//----------------------
integer log_file_handle;
// Constructor
//------------
task new(integer _DEBUG, string my_agent_name_,
integer my_agent_ID_, string my_prefix_, integer entity_ID_);
// Utility tasks
//--------------
task SetRandomParams(bit is_random_value_, bit [31:0] default_data_value_=0,
bit [5:0] default_meta_data_value_=0);
// generic_memory tasks
//------------------
task WriteData(bit [31:0] addr, bit[31:0] data, bit [3:0] byte_mask,
bit [5:0] meta, bit meta_byte_mask, string comment="",
integer written_by=TESTER_ID);
task ReadData(bit [31:0] addr, var bit[31:0] data,
var bit [5:0] meta, string comment="", bit local_access=0);
// Other Memory Useful Tasks/Functions
//----------------------------------------
function bit Empty(){Empty=(assoc_index(CHECK, assoc_data)==0) ? 1'b0:1'b1;}
function integer Size(){Size = assoc_index(CHECK, assoc_data);}
function integer GetClosestIndx(var bit [31:0] indx,
bit [31:0] range_high = 32'hffff_ffff,
bit [31:0] range_low = 32'h0000_0000,
bit [31:0] pattern = 32'h0000_0000,
bit [31:0] pattern_mask = 32'h0000_0000);
task UploadFile(string file_name, bit [31:0] base_addr = 0,
string new_indx_sign = "@", integer word_size);
// Global activation/termination functions
//----------------------------------------
task run();
task stop_me();
// Task for comunicating with future scoreboards
//----------------------------------------------
task SendWriteToSB(bit [31:0] addr, bit[31:0] data, bit [3:0] byte_mask,
bit [5:0] meta, bit meta_byte_mask)
{/*to be implemented by a scoreboard linking extention*/}
}
//------------------------------------------------------------------------------
//----- Place Implementation of Methods Here
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// generic_memory::new()
task generic_memory::new(integer _DEBUG, string my_agent_name_,
integer my_agent_ID_, string my_prefix_, integer entity_ID_)
{
//////////////////////////////////////////////////////////
// In the common case this method should not be changed //
//////////////////////////////////////////////////////////
_DEBUG_ = _DEBUG;
if ( _DEBUG_ ) printf ("%s: New Mem was created\n",my_agent_name_);
active = 0; // initial memory as not active.
my_agent_name = my_agent_name_;
my_agent_ID = my_agent_ID_;
my_prefix = my_prefix_;
my_ID = entity_ID_;
// by default, use randomness.
is_random_value = 0;
default_data_value = 0;
default_meta_data_value = 0;
// Open log file
log_file_handle = fopen({my_prefix, "Mem.log"}, "w");
if (log_file_handle == 0)
{
printf("ERROR: VERA Can't open %sMem.log for writing\n", my_prefix);
active = 0;
repeat (2) @(posedge CLOCK);
exit(1);
}
else
{
fprintf (log_file_handle,"File: %sMem.log\n", my_prefix);
fprintf (log_file_handle,"*********************************\n" );
}
// initialize the accesses semaphore
// random semaphore ID, #semaphores, keys per semaphore
semID=alloc(SEMAPHORE, 0 , 1 , 1 );
if (! semID)
{
printf("ERROR: VERA Can't Allocate Semaphores\n");
exit (1);
}
// finally enroll to the masters list
EnrollToMastersList(); //defined in GENERIC_master
}
//------------------------------------------------------------------------------
// generic_memory::run()
task generic_memory::run()
{
//////////////////////////////////////////////////////////
// In the common case this method should not be changed //
//////////////////////////////////////////////////////////
if ( _DEBUG_ ) printf ("%s: Mem was activated\n",my_agent_name);
active = 1;
//fork
//{/* Currently no inner threads exists*/ }
//join any
}
//------------------------------------------------------------------------------
// generic_memory::stop_me()
task generic_memory::stop_me()
{
//////////////////////////////////////////////////////////
// In the common case this method should not be changed //
//////////////////////////////////////////////////////////
if ( _DEBUG_ ) printf ("%s: Mem was terminated\n",my_agent_name);
active = 0;
repeat (2) @(posedge CLOCK); //wait for queues to drain
if (log_file_handle)
fclose (log_file_handle);
}
//------------------------------------------------------------------------------
// generic_memory::WriteData(...)
task generic_memory::WriteData(bit [31:0] addr, bit[31:0] data,
bit [3:0] byte_mask, bit [5:0] meta,
bit meta_byte_mask, string comment="",
integer written_by=TESTER_ID)
{
//////////////////////////////////////////////////////////
// In the common case this method should not be changed //
//////////////////////////////////////////////////////////
bit [31:0] readData;
bit [5:0] readMetaData;
addr = addr & 32'hffff_fffc;
if ( _DEBUG_ ) printf ("%d:%s:Mem.WriteData() was activated\n",
get_cycle(),my_agent_name);
// lock semaphore:
semaphore_get(WAIT, semID, 1);
//write to log
if (log_file_handle && (RunWithTrace))
{
fprintf (log_file_handle,
"%d:%s:Mem.WriteData(): addr=%8x data=%8x be=%4b meta=%6b"
" meta_be=%1b |%s\n",
get_cycle(), my_agent_name, addr, data, byte_mask, meta,
meta_byte_mask, comment);
}
// read previous value from memory
ReadData(addr,readData, readMetaData, comment, 1);
//calculate new value according to mask
if ( byte_mask & 4'h1 )
{
readData &= ~32'h000000ff;
readData |= data & 32'h000000ff;
}
if ( byte_mask & 4'h2 )
{
readData &= ~32'h0000ff00;
readData |= data & 32'h0000ff00;
}
if ( byte_mask & 4'h4 )
{
readData &= ~32'h00ff0000;
readData |= data & 32'h00ff0000;
}
if ( byte_mask & 4'h8 )
{
readData &= ~32'hff000000;
readData |= data & 32'hff000000;
}
if ( meta_byte_mask )
readMetaData = meta;
//write new value to memory
assoc_data[addr] = readData;
assoc_meta_data[addr] = readMetaData;
// release semapohre
semaphore_put(semID, 1);
// If this is a Tester write to main memory => send transaction to Scoreboard
if ((written_by == TESTER_ID) && (my_ID == MAINMEM_ID))
SendWriteToSB(addr, data, byte_mask, meta, meta_byte_mask);
}
//------------------------------------------------------------------------------
// generic_memory::ReadData(...)
task generic_memory::ReadData(bit [31:0] addr, var bit[31:0] data,
var bit [5:0] meta, string comment="",
bit local_access=0)
{
// Note: The local_access bit is used to diffrentiate between real accesses
// by memory clients (MemCtrl for instance) and local reads by auxiliary
// functions and by WriteData.
//////////////////////////////////////////////////////////
// In the common case this method should not be changed //
//////////////////////////////////////////////////////////
addr = addr & 32'hffff_fffc;
if ( _DEBUG_ && (! local_access) )
{
printf ("%d:%s:Mem.ReadData() was activated\n",
get_cycle(),my_agent_name);
}
// lock semaphore: (unless this is local access)
if (! local_access)
semaphore_get(WAIT, semID, 1);
if (assoc_index(CHECK, assoc_data, addr))
{
data = assoc_data[addr];
meta = assoc_meta_data[addr];
}
else
{
if( is_random_value == 0 )
{
data = default_data_value;
meta = default_meta_data_value;
}
else
{
data = urandom();
meta = urandom();
}
}
// if this was not a local access, write to log file.
if ((! local_access) && (log_file_handle) && (RunWithTrace))
{
fprintf (log_file_handle,
"%d:%s:Mem.ReadData() : addr=%8x data=%8x meta=%6b"
" |%s\n",
get_cycle(), my_agent_name, addr, data, meta, comment);
}
// release semapohre: (unless this is local access)
if (! local_access)
semaphore_put(semID, 1);
}
//------------------------------------------------------------------------------
// generic_memory::SetRandomParams(...)
// SetRandomParams: tasks initialize the random params of the memory:
// is_random_value: '1' means use random values for reads of addresses that
// where not written. '0' means use the default_data_value and
// the default_meta_data_value.
task generic_memory::SetRandomParams(bit is_random_value_,
bit [31:0] default_data_value_=0,
bit [5:0] default_meta_data_value_=0)
{
//////////////////////////////////////////////////////////
// In the common case this method should not be changed //
//////////////////////////////////////////////////////////
is_random_value = is_random_value_;
default_data_value = default_data_value_;
default_meta_data_value = default_meta_data_value_;
if (is_random_value)
{
if (log_file_handle)
{
fprintf (log_file_handle,
"%d:%s:Mem.SetRandomParams (for all memories): data_value=Random "
"meta_data_value=Random\n",
get_cycle(), my_agent_name );
}
printf ( "%d:%s:Mem.SetRandomParams (for all memories): data_value=Random "
"meta_data_value=Random\n",
get_cycle(), my_agent_name );
}
else
{
if (log_file_handle)
{
fprintf (log_file_handle,
"%d:%s:Mem.SetRandomParams (for all memories): data_value=%8x "
"meta_data_value=%6b\n",
get_cycle(), my_agent_name,
default_data_value, default_meta_data_value);
}
printf ("%d:%s:Mem.SetRandomParams (for all memories): data_value=%8x "
"meta_data_value=%6b\n",
get_cycle(), my_agent_name,
default_data_value, default_meta_data_value);
}
}
//------------------------------------------------------------------------------
/*
GetClosestIndx returns the closest occupied index to <indx> that is in the
range of: range_low <= indx <= range_high
*/
function integer generic_memory::GetClosestIndx(var bit [31:0] indx,
bit [31:0] range_high = 32'hffff_ffff,
bit [31:0] range_low = 32'h0000_0000,
bit [31:0] pattern = 32'h0000_0000,
bit [31:0] pattern_mask = 32'h0000_0000)
{
bit [31:0] local_indx = indx;
// First check if this index exists:
integer local_result = assoc_index(CHECK, assoc_data, local_indx);
// If the indx does not exists, look for the closest one:
if (local_result == 0)
{
local_result = assoc_index(NEXT, assoc_data, local_indx);
}
/* Continue searching till the right index is found...
* This means: as long as there are more addresses AND they are below
* <range_high> AND (they have still not matched the pattern or they are
* below <range_low>)
* Reminder to me: assoc_index(NEXT,...) is monotonically increasing
*/
while ((local_result == 1) && (local_indx <= range_high) &&
(((local_indx & pattern_mask) != (pattern & pattern_mask)) ||
(local_indx < range_low)))
{
local_result = assoc_index(NEXT, assoc_data, local_indx);
// check for upper range
if (local_indx > range_high)
break;
}
/*
Finally, after trying realy hard, if you FOUND an index IN RANGE, set the
<indx> variable to that value, and return 1.
Else, don't modify the index and return 0.
*/
if ((local_result) &&
(local_indx <= range_high) && (local_indx >= range_low) &&
((local_indx & pattern_mask) == (pattern & pattern_mask)))
{
indx = local_indx;
GetClosestIndx = local_result;
}
else
{
GetClosestIndx = 0;
}
}
//------------------------------------------------------------------------------
/*
---UploadFile(...)---
UploadFile is a task that receive for a given file name, openes the file, read
its content and write it to the memory.
<file_name> is the file name to open
<base_addr> is an offset that all indices are calculated accordingly. For
example, the base address for instruction is usually 0x4000_0000.
<new_indx_sign> is a string, representing a new index for the following data
words.
<word_size> is the size of every word in the file (given in bytes).
For example:
"01234567 // word1
89abcdef // word2
@12 // new index
babebabe // word3
cafecafe" // word4
In the above code: word1 will be written to address=<base_addr>, while word2
will be written to address=<base_addr>+<word_size> and word3 will be written
to address=<base_addr>+12*<word_size>.
In other notation, this is:
Mem[<base_addr>+<word_size>-1:<base_addr>]<=01234567
Mem[<base_addr>+2*<word_size>-1:<base_addr>+<word_size>]<=89abcdef
Mem[<base_addr>+13*<word_size>-1:<base_addr>+12*<word_size>]<=babebabe
Mem[<base_addr>+14*<word_size>-1:<base_addr>+13*<word_size>]<=cafecafe
*/
task generic_memory::UploadFile(string file_name, bit [31:0] base_addr = 0,
string new_indx_sign = "@", integer word_size)
{
integer file_handle;
bit [31:0] addr=0;
bit [64:0] data=0;
// load input file in read format.
file_handle = fopen(file_name, "r");
if (file_handle==0)
{
printf("\n\n%d:%s: ERROR: Mem.UploadFile() can not open file %s for reading\n",
get_cycle(), my_agent_name, file_name);
fprintf(stderr, "\n\n%d:%s: ERROR: Mem.UploadFile() can not open file %s"
"for reading\n",
get_cycle(), my_agent_name, file_name);
exit(1);
}
// Start extracting data from the file:
while (!feof(file_handle))
{
string line;
line = freadstr(file_handle, SILENT);
// Two kinds of lines supported: address, or data.
// Address lines start with <new_indx_sign>.
if (line.match({"^",new_indx_sign,"[0-9a-fA-F]+$"}))
{
string indx_str;
indx_str = line.substr(new_indx_sign.len());
addr = base_addr + indx_str.atohex()*word_size;
if (log_file_handle && (RunWithTrace))
{
fprintf (log_file_handle,
"%d:%s:Mem.UploadFile() Found new index %8x => address %8x\n",
get_cycle(), my_agent_name , indx_str.atohex(), addr);
}
}
else if (line.match("^[0-9a-fA-F]{1,16}$"))
{
data = line.atohex();
case (word_size)
{
4:
{
WriteData(addr, data[31:0], /*byte_mask*/ 4'b1111,
/*meta*/ 0, /*meta_byte_mask*/ 0,
"(Written by UploadFile)", my_ID);
}
8:
{
WriteData(addr+4, data[63:32], /*byte_mask*/ 4'b1111,
/*meta*/ 0, /*meta_byte_mask*/ 0,
"(Written by UploadFile)", my_ID);
WriteData(addr, data[31:0], /*byte_mask*/ 4'b1111,
/*meta*/ 0, /*meta_byte_mask*/ 0,
"(Written by UploadFile)", my_ID);
}
default:
{
printf("\n\n%d:%s: ERROR: Mem.UploadFile() Word size of %0d bytes"
"is not supported\n",
get_cycle(), my_agent_name, word_size);
fprintf(stderr, "\n\n%d:%s: ERROR: Mem.UploadFile() Word size of %0d"
"bytes is not supported\n",
get_cycle(), my_agent_name, word_size);
exit(1);
}
}
addr = addr + word_size;
}
/*
Comments are ignored by vera, so if it is not data/address/
empty line/spaces only, print error message
*/
else if (line.len() && !line.match("^\s*//"))
{
printf("\n\n%d:%s: ERROR: Mem.UploadFile() found an illegal line:\n\t\"%s\"\n",
get_cycle(), my_agent_name, line);
fprintf(stderr, "\n\n%d:%s: ERROR: Mem.UploadFile() found an illegal"
"line:\n\t\"%s\"\n",
get_cycle(), my_agent_name, line);
exit(1);
}
}//end of "while (!feof(fh))..."
//close input file:
fclose(file_handle);
}
#endif