2 * Copyright (c) 1999 Stephen Williams (steve@icarus.com)
4 * This source code is free software; you can redistribute it
5 * and/or modify it in source code form under the terms of the GNU
6 * General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20 #ident "$Id: sys_readmem.c,v 1.19 2007/03/14 04:05:51 steve Exp $"
23 # include "vpi_config.h"
25 # include "vpi_user.h"
30 # include "sys_readmem_lex.h"
32 static int check_integer_constant(char*name
, vpiHandle handle
)
34 if (vpi_get(vpiType
, handle
) != vpiConstant
){
35 vpi_printf("ERROR: %s parameter must be a constant (vpiType=%d)\n",
36 name
, vpi_get(vpiType
, handle
));
40 switch(vpi_get(vpiConstType
, handle
)){
48 /* We rely on vpi_get_value for reals and strings to return a correct */
49 /* integer value when this is requested. So only a warning is generated. */
51 vpi_printf("Warning: real supplied to %s instead of integer.\n", name
);
56 vpi_printf("Warning: string supplied to %s instead of integer.\n", name
);
61 /* switch statement covers all possibilities. Code should never come here... */
67 * This function makes sure the handle is of an object that can get a
68 * string value for a file name.
70 static int check_file_name(const char*name
, vpiHandle item
)
72 switch (vpi_get(vpiType
, item
)) {
75 if (vpi_get(vpiConstType
, item
) != vpiStringConst
) {
76 vpi_printf("ERROR: %s argument 1: file name argument "
77 "must be a string.\n", name
);
83 if (vpi_get(vpiConstType
,item
) != vpiStringConst
) {
84 vpi_printf("ERROR: %s argument 1: Parameter %s is "
85 "not a string in this context.\n",
86 name
, vpi_get_str(vpiName
,item
));
95 vpi_printf("ERROR: %s argument 1: must be a string\n", name
);
103 static PLI_INT32
sys_readmem_calltf(PLI_BYTE8
*name
)
113 vpiHandle sys
= vpi_handle(vpiSysTfCall
, 0);
114 vpiHandle argv
= vpi_iterate(vpiArgument
, sys
);
115 vpiHandle item
= vpi_scan(argv
);
117 vpiHandle start_item
;
119 vpiHandle left_range
;
120 vpiHandle right_range
;
121 vpiHandle word_index
;
123 /* These are left and right hand side parameters in the
124 declaration of the memory. */
125 int left_addr
, right_addr
;
127 /* start_addr and stop_addr are the parameters given to $readmem in the
128 verilog code. When not specified, start_addr is equal to the lower of
129 the [left,right]_addr and stop_addr is equal to the higher of the
130 [left,right]_addr. */
131 int start_addr
, stop_addr
, addr_incr
;
133 /* min_addr and max_addr are equal to start_addr and stop_addr if
134 start_addr<stop_addr or vice versa if not... */
135 unsigned min_addr
, max_addr
;
137 /* This is the number of words that we need from the memory. */
141 /*======================================== Get parameters */
144 vpi_printf("%s: file name parameter missing.\n", name
);
148 /* Check then get the first argument, the file name. It is
149 possible that Verilog would right-justify a name to fit a
150 reg value to fit the reg width, so chop off leading white
151 space in the process. */
152 if (check_file_name(name
, item
) == 0) {
153 vpi_free_object(argv
);
157 value
.format
= vpiStringVal
;
158 vpi_get_value(item
, &value
);
159 path
= strdup(value
.value
.str
+ strspn(value
.value
.str
, " "));
161 /* Get and check the second parameter. It must be a memory. */
162 mitem
= vpi_scan(argv
);
164 vpi_printf("%s: Missing memory parameter\n", name
);
169 if (vpi_get(vpiType
, mitem
) != vpiMemory
) {
170 vpi_printf("%s: Second parameter must be a memory.\n", name
);
172 vpi_free_object(argv
);
176 mem_name
= vpi_get_str(vpiFullName
, mitem
);
178 /* Get optional third parameter. It must be a constant. */
179 start_item
= vpi_scan(argv
);
181 if (check_integer_constant(name
, start_item
) == 0){
182 vpi_free_object(argv
);
186 /* Get optional forth parameter. It must be a constant. */
187 stop_item
= vpi_scan(argv
);
189 if (check_integer_constant(name
, stop_item
) == 0){
190 vpi_free_object(argv
);
194 /* Check that ther is no 5th parameter */
195 if (vpi_scan(argv
) != 0){
196 vpi_printf("ERROR: %s accepts maximum 4 parameters!\n", name
);
197 vpi_free_object(argv
);
207 /*======================================== Process parameters */
209 /* Open the data file. */
210 file
= fopen(path
, "r");
212 vpi_printf("%s: Unable to open %s for reading.\n", name
, path
);
217 /* Get left addr of memory */
218 left_range
= vpi_handle(vpiLeftRange
, mitem
);
219 value
.format
= vpiIntVal
;
220 vpi_get_value(left_range
, &value
);
221 left_addr
= value
.value
.integer
;
223 /* Get right addr of memory */
224 right_range
= vpi_handle(vpiRightRange
, mitem
);
225 value
.format
= vpiIntVal
;
226 vpi_get_value(right_range
, &value
);
227 right_addr
= value
.value
.integer
;
229 /* Get start_addr, stop_addr and addr_incr */
231 start_addr
= left_addr
<right_addr
? left_addr
: right_addr
;
232 stop_addr
= left_addr
<right_addr
? right_addr
: left_addr
;
237 value
.format
= vpiIntVal
;
238 vpi_get_value(start_item
, &value
);
239 start_addr
= value
.value
.integer
;
242 stop_addr
= left_addr
<right_addr
? right_addr
: left_addr
;
247 value
.format
= vpiIntVal
;
248 vpi_get_value(stop_item
, &value
);
249 stop_addr
= value
.value
.integer
;
251 addr_incr
= start_addr
<stop_addr
? 1 : -1;
255 min_addr
= start_addr
<stop_addr
? start_addr
: stop_addr
;
256 max_addr
= start_addr
<stop_addr
? stop_addr
: start_addr
;
258 /* We need this many words from the file. */
259 word_count
= max_addr
-min_addr
+1;
261 /* Check that start_addr and stop_addr are within the memory
263 if (left_addr
<right_addr
){
264 if (start_addr
<left_addr
|| start_addr
> right_addr
) {
265 vpi_printf("%s: Start address is out of bounds for memory \'%s\'!\n", name
, mem_name
);
269 if (stop_addr
<left_addr
|| stop_addr
> right_addr
) {
270 vpi_printf("%s: Stop address is out of bounds for memory \'%s\'!\n", name
, mem_name
);
275 if (start_addr
<right_addr
|| start_addr
> left_addr
) {
276 vpi_printf("%s: Start address is out of bounds for memory \'%s\'!\n", name
, mem_name
);
280 if (stop_addr
<right_addr
|| stop_addr
> left_addr
) {
281 vpi_printf("%s: Stop address is out of bounds for memory \'%s\'!\n", name
, mem_name
);
287 words
= vpi_iterate(vpiMemoryWord
, mitem
);
290 item
= vpi_scan(words
);
291 wwid
= vpi_get(vpiSize
, item
);
293 /* variable that will be uses by the lexer to pass values
295 value
.format
= vpiVectorVal
;
296 value
.value
.vector
= calloc((wwid
+31)/32, sizeof(s_vpi_vecval
));
298 /* Configure the readmem lexer */
299 if (strcmp(name
,"$readmemb") == 0)
300 sys_readmem_start_file(file
, 1, wwid
, value
.value
.vector
);
302 sys_readmem_start_file(file
, 0, wwid
, value
.value
.vector
);
305 /*======================================== Read memory file */
307 /* Run through the input file and store the new contents in the memory */
309 while ((code
= readmemlex()) != 0) {
312 addr
= value
.value
.vector
->aval
;
313 /* if there is an address in the memory file, then
314 turn off any possible warnings about not having
315 enough words to load the memory. This is standard
321 if (addr
>= min_addr
&& addr
<= max_addr
){
322 word_index
= vpi_handle_by_index(mitem
, addr
);
324 vpi_put_value(word_index
, &value
, 0, vpiNoDelay
);
330 vpi_printf("%s(%s): address (0x%x) out of range (0x%x:0x%x)\n",
331 name
, path
, addr
, start_addr
, stop_addr
);
339 vpi_printf("Huh?! (%d)\n", code
);
345 vpi_printf("%s(%s): Not enough words in the read file "
346 "for requested range.\n", name
, path
);
349 free(value
.value
.vector
);
352 vpi_free_object(words
);
358 static PLI_INT32
sys_writemem_calltf(PLI_BYTE8
*name
)
368 vpiHandle sys
= vpi_handle(vpiSysTfCall
, 0);
369 vpiHandle argv
= vpi_iterate(vpiArgument
, sys
);
370 vpiHandle item
= vpi_scan(argv
);
372 vpiHandle start_item
;
374 vpiHandle word_index
;
375 vpiHandle left_range
;
376 vpiHandle right_range
;
378 int left_addr
, right_addr
;
379 int start_addr
, stop_addr
, addr_incr
;
380 int min_addr
, max_addr
;
382 /*======================================== Get parameters */
385 vpi_printf("%s: file name parameter missing.\n", name
);
389 if (vpi_get(vpiType
, item
) != vpiConstant
) {
390 vpi_printf("ERROR: %s parameter must be a constant\n", name
);
391 vpi_free_object(argv
);
395 if (vpi_get(vpiConstType
, item
) != vpiStringConst
) {
396 vpi_printf("ERROR: %s parameter must be a string\n", name
);
397 vpi_free_object(argv
);
401 value
.format
= vpiStringVal
;
402 vpi_get_value(item
, &value
);
403 path
= strdup(value
.value
.str
);
405 /* Get and check the second parameter. It must be a memory. */
406 mitem
= vpi_scan(argv
);
408 vpi_printf("%s: Missing memory parameter\n", name
);
413 if (vpi_get(vpiType
, mitem
) != vpiMemory
) {
414 vpi_printf("%s: Second parameter must be a memory.\n", name
);
416 vpi_free_object(argv
);
420 mem_name
= vpi_get_str(vpiFullName
, mitem
);
422 /* Get optional third parameter. It must be a constant. */
423 start_item
= vpi_scan(argv
);
425 if (check_integer_constant(name
, start_item
) == 0){
426 vpi_free_object(argv
);
430 /* Get optional forth parameter. It must be a constant. */
431 stop_item
= vpi_scan(argv
);
433 if (check_integer_constant(name
, stop_item
) == 0){
434 vpi_free_object(argv
);
438 /* Check that ther is no 5th parameter */
439 if (vpi_scan(argv
) != 0){
440 vpi_printf("ERROR: %s accepts maximum 4 parameters!\n", name
);
441 vpi_free_object(argv
);
451 /*======================================== Process parameters */
453 /* Open the data file. */
454 file
= fopen(path
, "w");
456 vpi_printf("%s: Unable to open %s for writeing.\n", name
, path
);
461 /* Get left addr of memory */
462 left_range
= vpi_handle(vpiLeftRange
, mitem
);
463 value
.format
= vpiIntVal
;
464 vpi_get_value(left_range
, &value
);
465 left_addr
= value
.value
.integer
;
467 /* Get right addr of memory */
468 right_range
= vpi_handle(vpiRightRange
, mitem
);
469 value
.format
= vpiIntVal
;
470 vpi_get_value(right_range
, &value
);
471 right_addr
= value
.value
.integer
;
473 /* Get start_addr, stop_addr and addr_incr */
475 start_addr
= left_addr
<right_addr
? left_addr
: right_addr
;
476 stop_addr
= left_addr
<right_addr
? right_addr
: left_addr
;
481 value
.format
= vpiIntVal
;
482 vpi_get_value(start_item
, &value
);
483 start_addr
= value
.value
.integer
;
486 stop_addr
= left_addr
<right_addr
? right_addr
: left_addr
;
491 value
.format
= vpiIntVal
;
492 vpi_get_value(stop_item
, &value
);
493 stop_addr
= value
.value
.integer
;
495 addr_incr
= start_addr
<stop_addr
? 1 : -1;
499 min_addr
= start_addr
<stop_addr
? start_addr
: stop_addr
;
500 max_addr
= start_addr
<stop_addr
? stop_addr
: start_addr
;
502 /* Check that start_addr and stop_addr are within the memory
504 if (left_addr
<right_addr
){
505 if (start_addr
<left_addr
|| start_addr
> right_addr
) {
506 vpi_printf("%s: Start address is out of bounds for memory \'%s\'!\n", name
, mem_name
);
510 if (stop_addr
<left_addr
|| stop_addr
> right_addr
) {
511 vpi_printf("%s: Stop address is out of bounds for memory \'%s\'!\n", name
, mem_name
);
516 if (start_addr
<right_addr
|| start_addr
> left_addr
) {
517 vpi_printf("%s: Start address is out of bounds for memory \'%s\'!\n", name
, mem_name
);
521 if (stop_addr
<right_addr
|| stop_addr
> left_addr
) {
522 vpi_printf("%s: Stop address is out of bounds for memory \'%s\'!\n", name
, mem_name
);
528 words
= vpi_iterate(vpiMemoryWord
, mitem
);
531 item
= vpi_scan(words
);
532 wwid
= vpi_get(vpiSize
, item
);
534 if (strcmp(name
,"$writememb")==0){
535 value
.format
= vpiBinStrVal
;
538 value
.format
= vpiHexStrVal
;
541 /*======================================== Write memory file */
544 for(addr
=start_addr
; addr
!=stop_addr
+addr_incr
; addr
+=addr_incr
, ++cnt
){
546 fprintf(file
, "// 0x%08x\n", cnt
);
548 word_index
= vpi_handle_by_index(mitem
, addr
);
550 vpi_get_value(word_index
, &value
);
551 fprintf(file
, "%s\n", value
.value
.str
);
558 void sys_readmem_register()
560 s_vpi_systf_data tf_data
;
562 tf_data
.type
= vpiSysTask
;
563 tf_data
.tfname
= "$readmemh";
564 tf_data
.calltf
= sys_readmem_calltf
;
565 tf_data
.compiletf
= 0;
567 tf_data
.user_data
= "$readmemh";
568 vpi_register_systf(&tf_data
);
570 tf_data
.type
= vpiSysTask
;
571 tf_data
.tfname
= "$readmemb";
572 tf_data
.calltf
= sys_readmem_calltf
;
573 tf_data
.compiletf
= 0;
575 tf_data
.user_data
= "$readmemb";
576 vpi_register_systf(&tf_data
);
578 tf_data
.type
= vpiSysTask
;
579 tf_data
.tfname
= "$writememh";
580 tf_data
.calltf
= sys_writemem_calltf
;
581 tf_data
.compiletf
= 0;
583 tf_data
.user_data
= "$writememh";
584 vpi_register_systf(&tf_data
);
586 tf_data
.type
= vpiSysTask
;
587 tf_data
.tfname
= "$writememb";
588 tf_data
.calltf
= sys_writemem_calltf
;
589 tf_data
.compiletf
= 0;
591 tf_data
.user_data
= "$writememb";
592 vpi_register_systf(&tf_data
);
596 * $Log: sys_readmem.c,v $
597 * Revision 1.19 2007/03/14 04:05:51 steve
598 * VPI tasks take PLI_BYTE* by the standard.
600 * Revision 1.18 2006/10/30 22:45:37 steve
601 * Updates for Cygwin portability (pr1585922)
603 * Revision 1.17 2006/04/25 05:00:12 steve
604 * Warning when file is inadequate for requested range.
606 * Revision 1.16 2004/10/04 01:10:58 steve
607 * Clean up spurious trailing white space.
609 * Revision 1.15 2004/01/21 01:22:53 steve
610 * Give the vip directory its own configure and vpi_config.h
612 * Revision 1.14 2003/12/19 01:27:10 steve
613 * Fix various unsigned compare warnings.
615 * Revision 1.13 2003/05/10 16:06:50 steve
616 * $readmem more flexible with file name argument.
618 * Revision 1.12 2003/04/23 04:57:41 steve
619 * Accept string parameters for file name argument.
621 * Revision 1.11 2002/08/12 01:35:05 steve
622 * conditional ident string using autoconfig.
624 * Revision 1.10 2002/02/06 04:50:22 steve
625 * Add writememb (Tom Verbeure)
627 * Revision 1.9 2002/01/31 04:28:17 steve
628 * Full support for $readmem ranges (Tom Verbeure)
630 * Revision 1.8 2001/12/01 02:40:10 steve
631 * Support addresses in readmemh.
633 * Revision 1.7 2001/11/09 03:39:21 steve
636 * Revision 1.6 2001/07/25 03:10:50 steve
637 * Create a config.h.in file to hold all the config
638 * junk, and support gcc 3.0. (Stephan Boettcher)
640 * Revision 1.5 2000/02/23 02:56:56 steve
641 * Macintosh compilers do not support ident.
643 * Revision 1.4 2000/01/23 23:54:36 steve
644 * Compile time problems with vpi_user.h
646 * Revision 1.3 1999/12/15 04:35:34 steve
649 * Revision 1.2 1999/12/15 04:02:38 steve
652 * Revision 1.1 1999/12/15 04:01:14 steve
653 * Add the VPI implementation of $readmemh.