static PLI_INT32 sys_readmem_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { int code, wwid, addr; FILE*file; char *fname = 0; s_vpi_value value; vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle mitem = 0; vpiHandle start_item = 0; vpiHandle stop_item = 0; /* start_addr and stop_addr are the parameters given to $readmem in the Verilog code. When not specified, start_addr is equal to the lower of the [left,right]_addr and stop_addr is equal to the higher of the [left,right]_addr. */ int start_addr, stop_addr, addr_incr; /* min_addr and max_addr are equal to start_addr and stop_addr if start_addr<stop_addr or vice versa if not... */ int min_addr, max_addr; /* This is the number of words that we need from the memory. */ unsigned word_count; /*======================================== Get parameters */ get_mem_params(argv, callh, name, &fname, &mitem, &start_item, &stop_item); if (fname == 0) return 0; /*======================================== Process parameters */ if (process_params(mitem, start_item, stop_item, callh, name, &start_addr, &stop_addr, &addr_incr, &min_addr, &max_addr)) { free(fname); return 0; } /* Open the data file. */ file = fopen(fname, "r"); /* Check to see if we have other directories to look for this file. */ if (file == 0 && sl_count > 0 && fname[0] != '/') { unsigned idx; char path[4096]; for (idx = 0; idx < sl_count; idx += 1) { snprintf(path, sizeof(path), "%s/%s", search_list[idx], fname); path[sizeof(path)-1] = 0; if ((file = fopen(path, "r"))) break; } } if (file == 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s: Unable to open %s for reading.\n", name, fname); free(fname); return 0; } /* We need this many words from the file. */ word_count = max_addr-min_addr+1; wwid = vpi_get(vpiSize, vpi_handle_by_index(mitem, min_addr)); /* variable that will be used by the lexer to pass values back to this code */ value.format = vpiVectorVal; value.value.vector = calloc((wwid+31)/32, sizeof(s_vpi_vecval)); /* Configure the readmem lexer */ if (strcmp(name,"$readmemb") == 0) sys_readmem_start_file(file, 1, wwid, value.value.vector); else sys_readmem_start_file(file, 0, wwid, value.value.vector); /*======================================== Read memory file */ /* Run through the input file and store the new contents in the memory */ addr = start_addr; while ((code = readmemlex()) != 0) { switch (code) { case MEM_ADDRESS: addr = value.value.vector->aval; if (addr < min_addr || addr > max_addr) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s(%s): address (0x%x) is out of range " "[0x%x:0x%x]\n", name, fname, addr, start_addr, stop_addr); goto bailout; } /* if there is an address in the memory file, then turn off any possible warnings about not having enough words to load the memory. This is standard behavior from 1364-2005. */ word_count = 0; break; case MEM_WORD: if (addr >= min_addr && addr <= max_addr) { vpiHandle word_index; word_index = vpi_handle_by_index(mitem, addr); assert(word_index); vpi_put_value(word_index, &value, 0, vpiNoDelay); if (word_count > 0) word_count -= 1; } else { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s(%s): Too many words in the file for the " "requested range [%d:%d].\n", name, fname, start_addr, stop_addr); goto bailout; } addr += addr_incr; break; case MEM_ERROR: vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s(%s): Invalid input character: %s\n", name, fname, readmem_error_token); goto bailout; break; default: assert(0); break; } } /* Print a warning if there are not enough words in the data file. */ if (word_count > 0) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s(%s): Not enough words in the file for the " "requested range [%d:%d].\n", name, fname, start_addr, stop_addr); } bailout: free(value.value.vector); free(fname); fclose(file); destroy_readmem_lexor(); return 0; }
static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name) { int code; int wwid; char*path; char*mem_name; FILE*file; unsigned addr; s_vpi_value value; vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, sys); vpiHandle item = vpi_scan(argv); vpiHandle mitem; vpiHandle start_item; vpiHandle stop_item; vpiHandle left_range; vpiHandle right_range; vpiHandle word_index; /* These are left and right hand side parameters in the declaration of the memory. */ int left_addr, right_addr; /* start_addr and stop_addr are the parameters given to $readmem in the Verilog code. When not specified, start_addr is equal to the lower of the [left,right]_addr and stop_addr is equal to the higher of the [left,right]_addr. */ int start_addr, stop_addr, addr_incr; /* min_addr and max_addr are equal to start_addr and stop_addr if start_addr<stop_addr or vice versa if not... */ unsigned min_addr, max_addr; /* This is the number of words that we need from the memory. */ unsigned word_count; /*======================================== Get parameters */ if (item == 0) { vpi_printf("%s: file name parameter missing.\n", name); return 0; } /* Check then get the first argument, the file name. It is possible that Verilog would right-justify a name to fit a reg value to fit the reg width, so chop off leading white space in the process. */ if (check_file_name(name, item) == 0) { vpi_free_object(argv); return 0; } value.format = vpiStringVal; vpi_get_value(item, &value); path = strdup(value.value.str + strspn(value.value.str, " ")); /* Get and check the second parameter. It must be a memory. */ mitem = vpi_scan(argv); if (mitem == 0) { vpi_printf("%s: Missing memory parameter\n", name); free(path); return 0; } if (vpi_get(vpiType, mitem) != vpiMemory) { vpi_printf("%s: Second parameter must be a memory.\n", name); free(path); vpi_free_object(argv); return 0; } mem_name = vpi_get_str(vpiFullName, mitem); /* Get optional third parameter. It must be a constant. */ start_item = vpi_scan(argv); if (start_item!=0) { if (check_integer_constant(name, start_item) == 0) { vpi_free_object(argv); return 0; } /* Get optional forth parameter. It must be a constant. */ stop_item = vpi_scan(argv); if (stop_item!=0) { if (check_integer_constant(name, stop_item) == 0) { vpi_free_object(argv); return 0; } /* Check that there is no 5th parameter */ if (vpi_scan(argv) != 0) { vpi_printf("ERROR: %s accepts maximum 4 parameters!\n", name ); vpi_free_object(argv); return 0; } } } else { stop_item = 0; } /*======================================== Process parameters */ /* Open the data file. */ file = fopen(path, "r"); if (file == 0) { vpi_printf("%s: Unable to open %s for reading.\n", name, path); free(path); return 0; } /* Get left addr of memory */ left_range = vpi_handle(vpiLeftRange, mitem); value.format = vpiIntVal; vpi_get_value(left_range, &value); left_addr = value.value.integer; /* Get right addr of memory */ right_range = vpi_handle(vpiRightRange, mitem); value.format = vpiIntVal; vpi_get_value(right_range, &value); right_addr = value.value.integer; /* Get start_addr, stop_addr and addr_incr */ if (start_item==0) { start_addr = left_addr<right_addr ? left_addr : right_addr; stop_addr = left_addr<right_addr ? right_addr : left_addr; addr_incr = 1; } else { s_vpi_value value2; value2.format = vpiIntVal; vpi_get_value(start_item, &value2); start_addr = value2.value.integer; if (stop_item==0) { stop_addr = left_addr<right_addr ? right_addr : left_addr; addr_incr = 1; } else { s_vpi_value value3; value3.format = vpiIntVal; vpi_get_value(stop_item, &value3); stop_addr = value3.value.integer; addr_incr = start_addr<stop_addr ? 1 : -1; } } min_addr = start_addr<stop_addr ? start_addr : stop_addr ; max_addr = start_addr<stop_addr ? stop_addr : start_addr; /* We need this many words from the file. */ word_count = max_addr-min_addr+1; /* Check that start_addr and stop_addr are within the memory range */ if (left_addr<right_addr) { if (start_addr<left_addr || start_addr > right_addr) { vpi_printf("%s: Start address is out of bounds for memory \'%s\'!\n", name, mem_name); return 0; } if (stop_addr<left_addr || stop_addr > right_addr) { vpi_printf("%s: Stop address is out of bounds for memory \'%s\'!\n", name, mem_name); return 0; } } else { if (start_addr<right_addr || start_addr > left_addr) { vpi_printf("%s: Start address is out of bounds for memory \'%s\'!\n", name, mem_name); return 0; } if (stop_addr<right_addr || stop_addr > left_addr) { vpi_printf("%s: Stop address is out of bounds for memory \'%s\'!\n", name, mem_name); return 0; } } item = vpi_handle_by_index(mitem,min_addr); wwid = vpi_get(vpiSize, item); /* variable that will be uses by the lexer to pass values back to this code */ value.format = vpiVectorVal; value.value.vector = calloc((wwid+31)/32, sizeof(s_vpi_vecval)); /* Configure the readmem lexer */ if (strcmp(name,"$readmemb") == 0) sys_readmem_start_file(file, 1, wwid, value.value.vector); else sys_readmem_start_file(file, 0, wwid, value.value.vector); /*======================================== Read memory file */ /* Run through the input file and store the new contents in the memory */ addr = start_addr; while ((code = readmemlex()) != 0) { switch (code) { case MEM_ADDRESS: addr = value.value.vector->aval; /* if there is an address in the memory file, then turn off any possible warnings about not having enough words to load the memory. This is standard behavior. */ word_count = 0; break; case MEM_WORD: if (addr >= min_addr && addr <= max_addr) { word_index = vpi_handle_by_index(mitem, addr); assert(word_index); vpi_put_value(word_index, &value, 0, vpiNoDelay); if (word_count > 0) word_count -= 1; } else { vpi_printf("%s(%s): address (0x%x) out of range (0x%x:0x%x)\n", name, path, addr, start_addr, stop_addr); goto bailout; } addr += addr_incr; break; default: vpi_printf("Huh?! (%d)\n", code); break; } } if (word_count > 0) vpi_printf("%s(%s): Not enough words in the read file " "for requested range.\n", name, path); bailout: free(value.value.vector); free(path); fclose(file); return 0; }