Merge branch 'master' of steve-icarus@icarus.com:git/verilog
[iverilog.git] / vpi / sys_readmem.c
blob1d09fd5e9f8a5ebc0258780b250899e911798f9b
1 /*
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)
8 * any later version.
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
19 #ifdef HAVE_CVS_IDENT
20 #ident "$Id: sys_readmem.c,v 1.19 2007/03/14 04:05:51 steve Exp $"
21 #endif
23 # include "vpi_config.h"
25 # include "vpi_user.h"
26 # include <string.h>
27 # include <stdlib.h>
28 # include <stdio.h>
29 # include <assert.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));
37 return 0;
40 switch(vpi_get(vpiConstType, handle)){
41 case vpiDecConst:
42 case vpiBinaryConst:
43 case vpiOctConst:
44 case vpiHexConst:
45 return 1;
46 break;
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. */
50 case vpiRealConst:
51 vpi_printf("Warning: real supplied to %s instead of integer.\n", name);
52 return 1;
53 break;
55 case vpiStringConst:
56 vpi_printf("Warning: string supplied to %s instead of integer.\n", name);
57 return 1;
58 break;
61 /* switch statement covers all possibilities. Code should never come here... */
62 assert(0);
63 return 0;
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)) {
74 case vpiConstant:
75 if (vpi_get(vpiConstType, item) != vpiStringConst) {
76 vpi_printf("ERROR: %s argument 1: file name argument "
77 "must be a string.\n", name);
78 return 0;
80 break;
82 case vpiParameter:
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));
87 return 0;
89 break;
91 case vpiReg:
92 break;
94 default:
95 vpi_printf("ERROR: %s argument 1: must be a string\n", name);
96 return 0;
99 return 1;
103 static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name)
105 int code;
106 int wwid;
107 char*path;
108 char*mem_name;
109 FILE*file;
110 unsigned addr;
111 s_vpi_value value;
112 vpiHandle words;
113 vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
114 vpiHandle argv = vpi_iterate(vpiArgument, sys);
115 vpiHandle item = vpi_scan(argv);
116 vpiHandle mitem;
117 vpiHandle start_item;
118 vpiHandle stop_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. */
138 unsigned word_count;
141 /*======================================== Get parameters */
143 if (item == 0) {
144 vpi_printf("%s: file name parameter missing.\n", name);
145 return 0;
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);
154 return 0;
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);
163 if (mitem == 0) {
164 vpi_printf("%s: Missing memory parameter\n", name);
165 free(path);
166 return 0;
169 if (vpi_get(vpiType, mitem) != vpiMemory) {
170 vpi_printf("%s: Second parameter must be a memory.\n", name);
171 free(path);
172 vpi_free_object(argv);
173 return 0;
176 mem_name = vpi_get_str(vpiFullName, mitem);
178 /* Get optional third parameter. It must be a constant. */
179 start_item = vpi_scan(argv);
180 if (start_item!=0){
181 if (check_integer_constant(name, start_item) == 0){
182 vpi_free_object(argv);
183 return 0;
186 /* Get optional forth parameter. It must be a constant. */
187 stop_item = vpi_scan(argv);
188 if (stop_item!=0){
189 if (check_integer_constant(name, stop_item) == 0){
190 vpi_free_object(argv);
191 return 0;
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);
198 return 0;
203 else{
204 stop_item = 0;
207 /*======================================== Process parameters */
209 /* Open the data file. */
210 file = fopen(path, "r");
211 if (file == 0) {
212 vpi_printf("%s: Unable to open %s for reading.\n", name, path);
213 free(path);
214 return 0;
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 */
230 if (start_item==0){
231 start_addr = left_addr<right_addr ? left_addr : right_addr;
232 stop_addr = left_addr<right_addr ? right_addr : left_addr;
233 addr_incr = 1;
235 else{
236 s_vpi_value value;
237 value.format = vpiIntVal;
238 vpi_get_value(start_item, &value);
239 start_addr = value.value.integer;
241 if (stop_item==0){
242 stop_addr = left_addr<right_addr ? right_addr : left_addr;
243 addr_incr = 1;
245 else{
246 s_vpi_value value;
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
262 range */
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);
266 return 0;
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);
271 return 0;
274 else{
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);
277 return 0;
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);
282 return 0;
287 words = vpi_iterate(vpiMemoryWord, mitem);
288 assert(words);
290 item = vpi_scan(words);
291 wwid = vpi_get(vpiSize, item);
293 /* variable that will be uses by the lexer to pass values
294 back to this code */
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);
301 else
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 */
308 addr = start_addr;
309 while ((code = readmemlex()) != 0) {
310 switch (code) {
311 case MEM_ADDRESS:
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
316 behavior. */
317 word_count = 0;
318 break;
320 case MEM_WORD:
321 if (addr >= min_addr && addr <= max_addr){
322 word_index = vpi_handle_by_index(mitem, addr);
323 assert(word_index);
324 vpi_put_value(word_index, &value, 0, vpiNoDelay);
326 if (word_count > 0)
327 word_count -= 1;
329 else{
330 vpi_printf("%s(%s): address (0x%x) out of range (0x%x:0x%x)\n",
331 name, path, addr, start_addr, stop_addr);
332 goto bailout;
335 addr += addr_incr;
336 break;
338 default:
339 vpi_printf("Huh?! (%d)\n", code);
340 break;
344 if (word_count > 0)
345 vpi_printf("%s(%s): Not enough words in the read file "
346 "for requested range.\n", name, path);
348 bailout:
349 free(value.value.vector);
351 if (item)
352 vpi_free_object(words);
353 free(path);
354 fclose(file);
355 return 0;
358 static PLI_INT32 sys_writemem_calltf(PLI_BYTE8*name)
360 int wwid;
361 char*path;
362 char*mem_name;
363 FILE*file;
364 unsigned addr = 0;
365 unsigned cnt = 0;
366 s_vpi_value value;
367 vpiHandle words;
368 vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
369 vpiHandle argv = vpi_iterate(vpiArgument, sys);
370 vpiHandle item = vpi_scan(argv);
371 vpiHandle mitem;
372 vpiHandle start_item;
373 vpiHandle stop_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 */
384 if (item == 0) {
385 vpi_printf("%s: file name parameter missing.\n", name);
386 return 0;
389 if (vpi_get(vpiType, item) != vpiConstant) {
390 vpi_printf("ERROR: %s parameter must be a constant\n", name);
391 vpi_free_object(argv);
392 return 0;
395 if (vpi_get(vpiConstType, item) != vpiStringConst) {
396 vpi_printf("ERROR: %s parameter must be a string\n", name);
397 vpi_free_object(argv);
398 return 0;
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);
407 if (mitem == 0) {
408 vpi_printf("%s: Missing memory parameter\n", name);
409 free(path);
410 return 0;
413 if (vpi_get(vpiType, mitem) != vpiMemory) {
414 vpi_printf("%s: Second parameter must be a memory.\n", name);
415 free(path);
416 vpi_free_object(argv);
417 return 0;
420 mem_name = vpi_get_str(vpiFullName, mitem);
422 /* Get optional third parameter. It must be a constant. */
423 start_item = vpi_scan(argv);
424 if (start_item!=0){
425 if (check_integer_constant(name, start_item) == 0){
426 vpi_free_object(argv);
427 return 0;
430 /* Get optional forth parameter. It must be a constant. */
431 stop_item = vpi_scan(argv);
432 if (stop_item!=0){
433 if (check_integer_constant(name, stop_item) == 0){
434 vpi_free_object(argv);
435 return 0;
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);
442 return 0;
447 else{
448 stop_item = 0;
451 /*======================================== Process parameters */
453 /* Open the data file. */
454 file = fopen(path, "w");
455 if (file == 0) {
456 vpi_printf("%s: Unable to open %s for writeing.\n", name, path);
457 free(path);
458 return 0;
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 */
474 if (start_item==0){
475 start_addr = left_addr<right_addr ? left_addr : right_addr;
476 stop_addr = left_addr<right_addr ? right_addr : left_addr;
477 addr_incr = 1;
479 else{
480 s_vpi_value value;
481 value.format = vpiIntVal;
482 vpi_get_value(start_item, &value);
483 start_addr = value.value.integer;
485 if (stop_item==0){
486 stop_addr = left_addr<right_addr ? right_addr : left_addr;
487 addr_incr = 1;
489 else{
490 s_vpi_value value;
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
503 range */
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);
507 return 0;
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);
512 return 0;
515 else{
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);
518 return 0;
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);
523 return 0;
528 words = vpi_iterate(vpiMemoryWord, mitem);
529 assert(words);
531 item = vpi_scan(words);
532 wwid = vpi_get(vpiSize, item);
534 if (strcmp(name,"$writememb")==0){
535 value.format = vpiBinStrVal;
537 else{
538 value.format = vpiHexStrVal;
541 /*======================================== Write memory file */
543 cnt=0;
544 for(addr=start_addr; addr!=stop_addr+addr_incr; addr+=addr_incr, ++cnt){
545 if (cnt%16 == 0)
546 fprintf(file, "// 0x%08x\n", cnt);
548 word_index = vpi_handle_by_index(mitem, addr);
549 assert(word_index);
550 vpi_get_value(word_index, &value);
551 fprintf(file, "%s\n", value.value.str);
554 fclose(file);
555 return 0;
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;
566 tf_data.sizetf = 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;
574 tf_data.sizetf = 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;
582 tf_data.sizetf = 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;
590 tf_data.sizetf = 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
634 * Support $writememh
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
647 * Add readmemb.
649 * Revision 1.2 1999/12/15 04:02:38 steve
650 * Excess warning.
652 * Revision 1.1 1999/12/15 04:01:14 steve
653 * Add the VPI implementation of $readmemh.