void return_command_block_data(){ vpiHandle systfref, args_iter, argh; struct t_vpi_value argval; int value,i; int n; uint32_t data; uint32_t length; char *block_data_buf; uint32_t *block_word_data_buf_ptr; int num_words; int sent_words = 0; vpiHandle array_word; // Now setup the handles to verilog objects and check things // Obtain a handle to the argument list systfref = vpi_handle(vpiSysTfCall, NULL); // Now call iterate with the vpiArgument parameter args_iter = vpi_iterate(vpiArgument, systfref); // get a handle on the length variable argh = vpi_scan(args_iter); argval.format = vpiIntVal; // get the value for the length object vpi_get_value(argh, &argval); // now set length length = argval.value.integer; // now get a handle on the next object (memory array) argh = vpi_scan(args_iter); // check we got passed a memory (array of regs) (modelsim passes back a vpiRegArray, so check for that too) if (!((vpi_get(vpiType, argh) == vpiMemory) #ifdef MODELSIM_VPI || (vpi_get(vpiType, argh) == vpiRegArray) #endif )) { vpi_printf("jp_vpi: ERROR: did not pass a memory to return_command_block_data\n"); vpi_printf("jp_vpi: ERROR: was passed type %d\n", (int)vpi_get(vpiType, argh)); return; } // We have to alloc memory here for lengths > 4 if (length > 4); { block_data_buf = (char*) malloc(length * sizeof(char)); if (block_data_buf == NULL) { vpi_printf("jp_vpi: return_command_block_data: Error. Could not allocate memory\n"); // Cleanup and return vpi_free_object(args_iter); return; } // Now cast it as a uint32_t array block_word_data_buf_ptr = (uint32_t *) block_data_buf; } num_words = length / 4; // We're always going to be dealing with whole words here if (DBG_JP_VPI) printf("jp_vpi: return_command_block_data: num_words %d\n", num_words); // Loop to load the words while (sent_words < num_words) { // Get a handle on the current word we want in the array that was passed to us array_word = vpi_handle_by_index(argh, sent_words); if (array_word != NULL) { vpi_get_value(array_word, &argval); data = (uint32_t) argval.value.integer; block_word_data_buf_ptr[sent_words] = data; } else return; if (DBG_JP_VPI) printf ( "jp_vpi: return_command_block_data: word %d 0x%.8x\n", sent_words, data); sent_words++; } if (!(length > 4)) { block_data_buf = (char *) &data; } n = write(vpi_to_rsp_pipe[1],block_data_buf,length); if (length > 4) { // Free the array free(block_data_buf); } // Cleanup and return vpi_free_object(args_iter); return; }
static void scan_item(unsigned depth, vpiHandle item, int skip) { struct t_cb_data cb; struct vcd_info* info; const char* name; const char* ident; int nexus_id; /* list of types to iterate upon */ int i; static int types[] = { /* Value */ vpiNet, vpiReg, vpiVariables, /* Scope */ vpiFunction, vpiModule, vpiNamedBegin, vpiNamedFork, vpiTask, -1 }; switch (vpi_get(vpiType, item)) { case vpiMemoryWord: if (vpi_get(vpiConstantSelect, item) == 0) { /* Turn a non-constant array word select into a * constant word select. */ vpiHandle array = vpi_handle(vpiParent, item); PLI_INT32 idx = vpi_get(vpiIndex, item); item = vpi_handle_by_index(array, idx); } case vpiIntegerVar: case vpiBitVar: case vpiByteVar: case vpiShortIntVar: case vpiIntVar: case vpiLongIntVar: case vpiTimeVar: case vpiReg: case vpiNet: /* An array word is implicitly escaped so look for an * escaped identifier that this could conflict with. */ if (vpi_get(vpiType, item) == vpiMemoryWord && vpi_handle_by_name(vpi_get_str(vpiFullName, item), 0)) { vpi_printf("LXT warning: dumping array word %s will " "conflict with an escaped identifier.\n", vpi_get_str(vpiFullName, item)); } if (skip || vpi_get(vpiAutomatic, item)) break; name = vpi_get_str(vpiName, item); nexus_id = vpi_get(_vpiNexusId, item); if (nexus_id) { ident = find_nexus_ident(nexus_id); } else { ident = 0; } if (!ident) { char*tmp = create_full_name(name); ident = strdup_sh(&name_heap, tmp); free(tmp); if (nexus_id) set_nexus_ident(nexus_id, ident); info = malloc(sizeof(*info)); info->time.type = vpiSimTime; info->item = item; info->sym = lt_symbol_add(dump_file, ident, 0 /* array rows */, vpi_get(vpiLeftRange, item), vpi_get(vpiRightRange, item), LT_SYM_F_BITS); info->scheduled = 0; cb.time = &info->time; cb.user_data = (char*)info; cb.value = NULL; cb.obj = item; cb.reason = cbValueChange; cb.cb_rtn = variable_cb_1; info->next = vcd_list; vcd_list = info; info->cb = vpi_register_cb(&cb); } else { char *n = create_full_name(name); lt_symbol_alias(dump_file, ident, n, vpi_get(vpiSize, item)-1, 0); free(n); } break; case vpiRealVar: if (skip || vpi_get(vpiAutomatic, item)) break; name = vpi_get_str(vpiName, item); { char*tmp = create_full_name(name); ident = strdup_sh(&name_heap, tmp); free(tmp); } info = malloc(sizeof(*info)); info->time.type = vpiSimTime; info->item = item; info->sym = lt_symbol_add(dump_file, ident, 0 /* array rows */, vpi_get(vpiSize, item)-1, 0, LT_SYM_F_DOUBLE); info->scheduled = 0; cb.time = &info->time; cb.user_data = (char*)info; cb.value = NULL; cb.obj = item; cb.reason = cbValueChange; cb.cb_rtn = variable_cb_1; info->next = vcd_list; vcd_list = info; info->cb = vpi_register_cb(&cb); break; case vpiModule: case vpiNamedBegin: case vpiTask: case vpiFunction: case vpiNamedFork: if (depth > 0) { int nskip; vpiHandle argv; const char* fullname = vpi_get_str(vpiFullName, item); #if 0 vpi_printf("LXT info: scanning scope %s, %u levels\n", fullname, depth); #endif nskip = 0 != vcd_names_search(&lxt_tab, fullname); if (!nskip) vcd_names_add(&lxt_tab, fullname); else vpi_printf("LXT warning: ignoring signals in " "previously scanned scope %s\n", fullname); name = vpi_get_str(vpiName, item); push_scope(name); for (i=0; types[i]>0; i++) { vpiHandle hand; argv = vpi_iterate(types[i], item); while (argv && (hand = vpi_scan(argv))) { scan_item(depth-1, hand, nskip); } } pop_scope(); } break; default: vpi_printf("LXT warning: $dumpvars: Unsupported parameter " "type (%s)\n", vpi_get_str(vpiType, item)); } }
void get_command_block_data(){ // $get_command_block_data(length, mem_array) vpiHandle systfref, args_iter, argh; struct t_vpi_value argval; int value,i; int n; uint32_t data; uint32_t length; char* recv_buf; // Now setup the handles to verilog objects and check things // Obtain a handle to the argument list systfref = vpi_handle(vpiSysTfCall, NULL); // Now call iterate with the vpiArgument parameter args_iter = vpi_iterate(vpiArgument, systfref); // get a handle on the length variable argh = vpi_scan(args_iter); argval.format = vpiIntVal; // get the value for the length object vpi_get_value(argh, &argval); // now set length length = argval.value.integer; int num_words = length/4; //if((length % 4) != 0) vpi_printf("length of %d bytes is not exactly word-aligned\n",length); // If non-word aligned we throw away remainder int throw_away_bytes = length %4; int loaded_words = 0; if(DBG_JP_VPI)printf("jp_vpi: get_command_block_data: length=%d, num_words=%d\n",length,num_words); // now get a handle on the next object (memory array) argh = vpi_scan(args_iter); // check we got passed a memory (array of regs) if (!((vpi_get(vpiType, argh) == vpiMemory) #ifdef MODELSIM_VPI || (vpi_get(vpiType, argh) == vpiRegArray) #endif )) { vpi_printf("jp_vpi: ERROR: did not pass a memory to get_command_block_data\n"); vpi_printf("jp_vpi: ERROR: was passed type %d\n", (int)vpi_get(vpiType, argh)); return; } // check the memory we're writing into is big enough if (vpi_get(vpiSize, argh) < num_words ) { vpi_printf("jp_vpi: ERROR: buffer passed to get_command_block_data too small. size is %d words, needs to be %d\n", vpi_get(vpiSize, argh), num_words); return; } vpiHandle array_word; // Loop to load the words while (loaded_words < num_words) { recv_buf = (char *) &data; // blocking receive for data block n = read(rsp_to_vpi_pipe[0],recv_buf,4); // now get a handle on the current word we want in the array that was passed to us array_word = vpi_handle_by_index(argh, loaded_words); if (array_word != NULL) { argval.value.integer = (uint32_t) data; // And vpi_put_value() it back into the sim vpi_put_value(array_word, &argval, NULL, vpiNoDelay); } else return; loaded_words++; } // TODO: This is a quick fix, should be delt with properly!! if (throw_away_bytes) { //printf("reading off %d extra data bytes\n",throw_away_bytes); n = read(rsp_to_vpi_pipe[0],&data,throw_away_bytes); //printf("read off %d bytes \n",n); } // Cleanup and return vpi_free_object(args_iter); return; }
static PLI_INT32 sys_writemem_calltf(PLI_BYTE8*name) { int wwid; char*path; char*mem_name; FILE*file; unsigned addr = 0; unsigned cnt = 0; s_vpi_value value; vpiHandle words; 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 word_index; vpiHandle left_range; vpiHandle right_range; int left_addr, right_addr; int start_addr, stop_addr, addr_incr; int min_addr, max_addr; /*======================================== Get parameters */ if (item == 0) { vpi_printf("%s: file name parameter missing.\n", name); return 0; } if (vpi_get(vpiType, item) != vpiConstant) { vpi_printf("ERROR: %s parameter must be a constant\n", name); vpi_free_object(argv); return 0; } if (vpi_get(vpiConstType, item) != vpiStringConst) { vpi_printf("ERROR: %s parameter must be a string\n", name); vpi_free_object(argv); return 0; } value.format = vpiStringVal; vpi_get_value(item, &value); path = strdup(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, "w"); if (file == 0) { vpi_printf("%s: Unable to open %s for writing.\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; /* 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; } } words = vpi_iterate(vpiMemoryWord, mitem); assert(words); item = vpi_scan(words); wwid = vpi_get(vpiSize, item); if (strcmp(name,"$writememb")==0) { value.format = vpiBinStrVal; } else { value.format = vpiHexStrVal; } /*======================================== Write memory file */ cnt=0; for(addr=start_addr; addr!=stop_addr+addr_incr; addr+=addr_incr, ++cnt) { if (cnt%16 == 0) fprintf(file, "// 0x%08x\n", cnt); word_index = vpi_handle_by_index(mitem, addr); assert(word_index); vpi_get_value(word_index, &value); fprintf(file, "%s\n", value.value.str); } fclose(file); 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; }
void send_result_to_server(char *userdata){ vpiHandle systfref, args_iter, argh; struct t_vpi_value argval; int n; struct vpi_cmd vpi; uint32_t length; int sent_words; vpiHandle array_word; // Now setup the handles to verilog objects and check things // Obtain a handle to the argument list systfref = vpi_handle(vpiSysTfCall, NULL); // Now call iterate with the vpiArgument parameter args_iter = vpi_iterate(vpiArgument, systfref); // get a handle on the length variable argh = vpi_scan(args_iter); argval.format = vpiIntVal; // get the value for the length object vpi_get_value(argh, &argval); // now set length length = argval.value.integer; // now get a handle on the next object (memory array) argh = vpi_scan(args_iter); // check we got passed a memory (array of regs) if (!((vpi_get(vpiType, argh) == vpiMemory) #ifdef MODELSIM_VPI || (vpi_get(vpiType, argh) == vpiRegArray) #endif )) { vpi_printf("jp_vpi: ERROR: did not pass a memory to get_command_block_data\n"); vpi_printf("jp_vpi: ERROR: was passed type %d\n", (int)vpi_get(vpiType, argh)); return; } // check the memory we're writing into is big enough if (vpi_get(vpiSize, argh) < length ) { vpi_printf("jp_vpi: ERROR: buffer passed to get_command_block_data too small. size is %d words, needs to be %d\n", vpi_get(vpiSize, argh), length); return; } // Loop to load the words sent_words = 0; while (sent_words < length) { // Get a handle on the current word we want in the array that was passed to us array_word = vpi_handle_by_index(argh, sent_words); if (array_word != NULL) { vpi_get_value(array_word, &argval); vpi.buffer_in[sent_words] = (uint32_t) argval.value.integer; } else return; sent_words++; } n = write(connfd, &vpi, sizeof(struct vpi_cmd)); // Cleanup and return vpi_free_object(args_iter); }
void check_for_command(char *userdata) { vpiHandle systfref, args_iter, argh; struct t_vpi_value argval; struct vpi_cmd vpi; int nb; int loaded_words = 0; // Get the command from TCP server nb = read(connfd, &vpi, sizeof(struct vpi_cmd)); if (((nb < 0) && (errno == EAGAIN)) || (nb == 0)) { // Nothing in the fifo this time, let's return return; } else { if (nb < 0) { // some sort of error perror("check_for_command"); exit(1); } } /* printf("\nReceived command:\n"); printf("cmd = %s\n", cmd_to_string[vpi.cmd]); printf("length = %d\n", vpi.length); if (vpi.length) { printf("nb_bits = %d\n", vpi.nb_bits); printf("buffer = "); for (i = 0; i < vpi.length; i++) printf("%02X ", vpi.buffer_out[i]); printf("\n"); } */ /************* vpi.cmd to VPI ******************************/ // Obtain a handle to the argument list systfref = vpi_handle(vpiSysTfCall, NULL); // Now call iterate with the vpiArgument parameter args_iter = vpi_iterate(vpiArgument, systfref); // get a handle on the variable passed to the function argh = vpi_scan(args_iter); // now store the command value back in the sim argval.format = vpiIntVal; // Now set the command value vpi_get_value(argh, &argval); argval.value.integer = (uint32_t)vpi.cmd; // And vpi_put_value() it back into the sim vpi_put_value(argh, &argval, NULL, vpiNoDelay); /************* vpi.length to VPI ******************************/ // now get a handle on the next object (memory array) argh = vpi_scan(args_iter); // now store the command value back in the sim argval.format = vpiIntVal; // Now set the command value vpi_get_value(argh, &argval); argval.value.integer = (uint32_t)vpi.length; // And vpi_put_value() it back into the sim vpi_put_value(argh, &argval, NULL, vpiNoDelay); /************* vpi.nb_bits to VPI ******************************/ // now get a handle on the next object (memory array) argh = vpi_scan(args_iter); // now store the command value back in the sim argval.format = vpiIntVal; // Now set the command value vpi_get_value(argh, &argval); argval.value.integer = (uint32_t)vpi.nb_bits; // And vpi_put_value() it back into the sim vpi_put_value(argh, &argval, NULL, vpiNoDelay); /*****************vpi.buffer_out to VPI ********/ // now get a handle on the next object (memory array) argh = vpi_scan(args_iter); vpiHandle array_word; // Loop to load the words while (loaded_words < vpi.length) { // now get a handle on the current word we want in the array that was passed to us array_word = vpi_handle_by_index(argh, loaded_words); if (array_word != NULL) { argval.value.integer = (uint32_t)vpi.buffer_out[loaded_words]; // And vpi_put_value() it back into the sim vpi_put_value(array_word, &argval, NULL, vpiNoDelay); } else return; loaded_words++; } /*******************************************/ // Cleanup and return vpi_free_object(args_iter); }
static void scan_item(unsigned depth, vpiHandle item, int skip) { struct t_cb_data cb; struct vcd_info* info; enum fstVarType type = FST_VT_MAX; enum fstScopeType stype = FST_ST_MAX; enum fstVarDir dir; const char *name; const char *fullname; char *escname; const char *ident; fstHandle new_ident; int nexus_id; unsigned size; PLI_INT32 item_type; /* Get the displayed type for the various $var and $scope types. */ /* Not all of these are supported now, but they should be in a * future development version. */ item_type = vpi_get(vpiType, item); switch (item_type) { case vpiNamedEvent: type = FST_VT_VCD_EVENT; break; case vpiIntVar: case vpiIntegerVar: type = FST_VT_VCD_INTEGER; break; case vpiParameter: type = FST_VT_VCD_PARAMETER; break; /* Icarus converts realtime to real. */ case vpiRealVar: type = FST_VT_VCD_REAL; break; case vpiMemoryWord: case vpiBitVar: case vpiByteVar: case vpiShortIntVar: case vpiLongIntVar: case vpiReg: type = FST_VT_VCD_REG; break; /* Icarus converts a time to a plain register. */ case vpiTimeVar: type = FST_VT_VCD_TIME; break; case vpiNet: switch (vpi_get(vpiNetType, item)) { case vpiWand: type = FST_VT_VCD_WAND; break; case vpiWor: type = FST_VT_VCD_WOR; break; case vpiTri: type = FST_VT_VCD_TRI; break; case vpiTri0: type = FST_VT_VCD_TRI0; break; case vpiTri1: type = FST_VT_VCD_TRI1; break; case vpiTriReg: type = FST_VT_VCD_TRIREG; break; case vpiTriAnd: type = FST_VT_VCD_TRIAND; break; case vpiTriOr: type = FST_VT_VCD_TRIOR; break; case vpiSupply1: type = FST_VT_VCD_SUPPLY1; break; case vpiSupply0: type = FST_VT_VCD_SUPPLY0; break; default: type = FST_VT_VCD_WIRE; break; } break; case vpiNamedBegin: stype = FST_ST_VCD_BEGIN; break; case vpiNamedFork: stype = FST_ST_VCD_FORK; break; case vpiFunction: stype = FST_ST_VCD_FUNCTION; break; case vpiGenScope: stype = FST_ST_VCD_GENERATE; break; case vpiModule: stype = FST_ST_VCD_MODULE; break; case vpiTask: stype = FST_ST_VCD_TASK; break; default: vpi_printf("FST warning: $dumpvars: Unsupported argument " "type (%s)\n", vpi_get_str(vpiType, item)); return; } /* Do some special processing/checking on array words. Dumping * array words is an Icarus extension. */ if (item_type == vpiMemoryWord) { /* Turn a non-constant array word select into a constant * word select. */ if (vpi_get(vpiConstantSelect, item) == 0) { vpiHandle array = vpi_handle(vpiParent, item); PLI_INT32 idx = vpi_get(vpiIndex, item); item = vpi_handle_by_index(array, idx); } /* An array word is implicitly escaped so look for an * escaped identifier that this could conflict with. */ /* This does not work as expected since we always find at * least the array word. We likely need a custom routine. */ if (vpi_get(vpiType, item) == vpiMemoryWord && vpi_handle_by_name(vpi_get_str(vpiFullName, item), 0)) { vpi_printf("FST warning: array word %s will conflict " "with an escaped identifier.\n", vpi_get_str(vpiFullName, item)); } } fullname = vpi_get_str(vpiFullName, item); /* Generate the $var or $scope commands. */ switch (item_type) { case vpiParameter: vpi_printf("FST sorry: $dumpvars: can not dump parameters.\n"); break; case vpiNamedEvent: case vpiIntegerVar: case vpiBitVar: case vpiByteVar: case vpiShortIntVar: case vpiIntVar: case vpiLongIntVar: case vpiRealVar: case vpiMemoryWord: case vpiReg: case vpiTimeVar: case vpiNet: /* If we are skipping all signal or this is in an automatic * scope then just return. */ if (skip || vpi_get(vpiAutomatic, item)) return; /* Skip this signal if it has already been included. * This can only happen for implicitly given signals. */ if (vcd_names_search(&fst_var, fullname)) return; /* Declare the variable in the FST file. */ name = vpi_get_str(vpiName, item); if (is_escaped_id(name)) { escname = malloc(strlen(name) + 2); sprintf(escname, "\\%s", name); } else escname = strdup(name); /* Some signals can have an alias so handle that. */ nexus_id = vpi_get(_vpiNexusId, item); ident = 0; if (nexus_id) ident = find_nexus_ident(nexus_id); /* Named events do not have a size, but other tools use * a size of 1 and some viewers do not accept a width of * zero so we will also use a width of one for events. */ if (item_type == vpiNamedEvent) size = 1; else size = vpi_get(vpiSize, item); /* The FST format supports a port direction so if the net * is a port set the direction to one of the following: * FST_VD_INPUT, FST_VD_OUTPUT or FST_VD_INOUT */ dir = FST_VD_IMPLICIT; if (size > 1 || vpi_get(vpiLeftRange, item) != 0) { char *buf = malloc(strlen(escname) + 65); sprintf(buf, "%s [%i:%i]", escname, (int)vpi_get(vpiLeftRange, item), (int)vpi_get(vpiRightRange, item)); new_ident = fstWriterCreateVar(dump_file, type, dir, size, buf, (fstHandle)(intptr_t)ident); free(buf); } else { new_ident = fstWriterCreateVar(dump_file, type, dir, size, escname, (fstHandle)(intptr_t)ident); } free(escname); if (!ident) { if (nexus_id) set_nexus_ident(nexus_id, (const char *)(intptr_t)new_ident); /* Add a callback for the signal. */ info = malloc(sizeof(*info)); info->time.type = vpiSimTime; info->item = item; info->handle = new_ident; info->scheduled = 0; cb.time = &info->time; cb.user_data = (char*)info; cb.value = NULL; cb.obj = item; cb.reason = cbValueChange; cb.cb_rtn = variable_cb_1; info->dmp_next = 0; info->next = vcd_list; vcd_list = info; info->cb = vpi_register_cb(&cb); } break; case vpiModule: case vpiGenScope: case vpiFunction: case vpiTask: case vpiNamedBegin: case vpiNamedFork: if (depth > 0) { char *instname; char *defname = NULL; /* list of types to iterate upon */ static int types[] = { /* Value */ vpiNamedEvent, vpiNet, /* vpiParameter, */ vpiReg, vpiVariables, /* Scope */ vpiFunction, vpiGenScope, vpiModule, vpiNamedBegin, vpiNamedFork, vpiTask, -1 }; int i; int nskip = (vcd_names_search(&fst_tab, fullname) != 0); /* We have to always scan the scope because the * depth could be different for this call. */ if (nskip) { vpi_printf("FST warning: ignoring signals in " "previously scanned scope %s.\n", fullname); } else { vcd_names_add(&fst_tab, fullname); } /* Set the file and line information for this scope. * Everything has instance information. Only a module * has separate definition information. */ instname = vpi_get_str(vpiFile, item); fstWriterSetSourceInstantiationStem(dump_file, instname, (int)vpi_get(vpiLineNo, item), 0); if (item_type == vpiModule) { fstWriterSetSourceStem(dump_file, vpi_get_str(vpiDefFile, item), (int)vpi_get(vpiDefLineNo, item), 0); } else { fstWriterSetSourceStem(dump_file, instname, (int)vpi_get(vpiLineNo, item), 0); } /* This must be done before the other name is fetched * and the string must always be freed */ if (item_type == vpiModule) { defname = strdup(vpi_get_str(vpiDefName, item)); } name = vpi_get_str(vpiName, item); /* If the two names match only use the vpiName. */ if (defname && (strcmp(defname, name) == 0)) { free(defname); defname = NULL; } fstWriterSetScope(dump_file, stype, name, defname); free(defname); for (i=0; types[i]>0; i++) { vpiHandle hand; vpiHandle argv = vpi_iterate(types[i], item); while (argv && (hand = vpi_scan(argv))) { scan_item(depth-1, hand, nskip); } } /* Sort any signals that we added above. */ fstWriterSetUpscope(dump_file); } break; } }
static PLI_INT32 sys_fread_calltf(PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle arg, mem_reg; s_vpi_value val; PLI_UINT32 fd_mcd; PLI_INT32 start, count, width, rtn; unsigned is_mem, bpe, words; FILE *fp; s_vpi_vecval *vector; errno = 0; /* Get the register/memory. */ mem_reg = vpi_scan(argv); /* Get the file descriptor. */ arg = vpi_scan(argv); val.format = vpiIntVal; vpi_get_value(arg, &val); fd_mcd = val.value.integer; /* Return 0 if this is not a valid fd. */ fp = vpi_get_file(fd_mcd); if (!fp) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("invalid file descriptor (0x%x) given to %s.\n", (unsigned int)fd_mcd, name); errno = EBADF; val.format = vpiIntVal; val.value.integer = 0; vpi_put_value(callh, &val, 0, vpiNoDelay); vpi_free_object(argv); return 0; } /* Are we reading into a memory? */ if (vpi_get(vpiType, mem_reg) == vpiReg) is_mem = 0; else is_mem = 1; /* We only need to get these for memories. */ if (is_mem) { PLI_INT32 left, right, max, min; /* Get the left and right memory address. */ val.format = vpiIntVal; vpi_get_value(vpi_handle(vpiLeftRange, mem_reg), &val); left = val.value.integer; val.format = vpiIntVal; vpi_get_value(vpi_handle(vpiRightRange, mem_reg), &val); right = val.value.integer; max = (left > right) ? left : right; min = (left < right) ? left : right; /* Get the starting address (optional). */ arg = vpi_scan(argv); if (arg) { val.format = vpiIntVal; vpi_get_value(arg, &val); start = val.value.integer; if (start < min || start > max) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's start argument (%d) is outside " "memory range [%d:%d].\n", name, (int)start, (int)left, (int)right); val.format = vpiIntVal; val.value.integer = 0; vpi_put_value(callh, &val, 0, vpiNoDelay); vpi_free_object(argv); return 0; } /* Get the count (optional). */ arg = vpi_scan(argv); if (arg) { val.format = vpiIntVal; vpi_get_value(arg, &val); count = val.value.integer; if (count > max-start) { vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s's count argument (%d) is too " "large for start (%d) and memory " "range [%d:%d].\n", name, (int)count, (int)start, (int)left, (int)right); count = max - start + 1; } vpi_free_object(argv); } else { count = max - start + 1; } } else { start = min; count = max - min + 1; } width = vpi_get(vpiSize, vpi_handle_by_index(mem_reg, start)); } else { start = 0; count = 1; width = vpi_get(vpiSize, mem_reg); vpi_free_object(argv); } words = (width+31)/32; vector = calloc(words, sizeof(s_vpi_vecval)); bpe = (width+7)/8; if (is_mem) { unsigned idx; rtn = 0; for (idx = 0; idx < count; idx += 1) { vpiHandle word; word = vpi_handle_by_index(mem_reg, start+(signed)idx); rtn += fread_word(fp, word, words, bpe, vector); if (feof(fp)) break; } } else { rtn = fread_word(fp, mem_reg, words, bpe, vector); } free(vector); /* Return the number of bytes read. */ val.format = vpiIntVal; val.value.integer = rtn; vpi_put_value(callh, &val, 0, vpiNoDelay); return 0; }
static void scan_item(unsigned depth, vpiHandle item, int skip) { struct t_cb_data cb; struct vcd_info* info; const char *type; const char *name; const char *fullname; const char *prefix; const char *ident; int nexus_id; unsigned size; PLI_INT32 item_type; /* Get the displayed type for the various $var and $scope types. */ /* Not all of these are supported now, but they should be in a * future development version. */ item_type = vpi_get(vpiType, item); switch (item_type) { case vpiNamedEvent: type = "event"; break; case vpiIntVar: case vpiIntegerVar: type = "integer"; break; case vpiParameter: type = "parameter"; break; /* Icarus converts realtime to real. */ case vpiRealVar: type = "real"; break; case vpiMemoryWord: case vpiBitVar: case vpiByteVar: case vpiShortIntVar: case vpiLongIntVar: case vpiReg: type = "reg"; break; /* Icarus converts a time to a plain register. */ case vpiTimeVar: type = "time"; break; case vpiNet: switch (vpi_get(vpiNetType, item)) { case vpiWand: type = "wand"; break; case vpiWor: type = "wor"; break; case vpiTri: type = "tri"; break; case vpiTri0: type = "tri0"; break; case vpiTri1: type = "tri1"; break; case vpiTriReg: type = "trireg"; break; case vpiTriAnd: type = "triand"; break; case vpiTriOr: type = "trior"; break; case vpiSupply1: type = "supply1"; break; case vpiSupply0: type = "supply0"; break; default: type = "wire"; break; } break; case vpiNamedBegin: type = "begin"; break; case vpiGenScope: type = "begin"; break; case vpiNamedFork: type = "fork"; break; case vpiFunction: type = "function"; break; case vpiModule: type = "module"; break; case vpiTask: type = "task"; break; default: vpi_printf("VCD warning: $dumpvars: Unsupported argument " "type (%s)\n", vpi_get_str(vpiType, item)); return; } /* Do some special processing/checking on array words. Dumping * array words is an Icarus extension. */ if (item_type == vpiMemoryWord) { /* Turn a non-constant array word select into a constant * word select. */ if (vpi_get(vpiConstantSelect, item) == 0) { vpiHandle array = vpi_handle(vpiParent, item); PLI_INT32 idx = vpi_get(vpiIndex, item); item = vpi_handle_by_index(array, idx); } /* An array word is implicitly escaped so look for an * escaped identifier that this could conflict with. */ /* This does not work as expected since we always find at * least the array word. We likely need a custom routine. */ if (vpi_get(vpiType, item) == vpiMemoryWord && vpi_handle_by_name(vpi_get_str(vpiFullName, item), 0)) { vpi_printf("VCD warning: array word %s will conflict " "with an escaped identifier.\n", vpi_get_str(vpiFullName, item)); } } fullname = vpi_get_str(vpiFullName, item); /* Generate the $var or $scope commands. */ switch (item_type) { case vpiParameter: vpi_printf("VCD sorry: $dumpvars: can not dump parameters.\n"); break; case vpiNamedEvent: case vpiIntegerVar: case vpiBitVar: case vpiByteVar: case vpiShortIntVar: case vpiIntVar: case vpiLongIntVar: case vpiRealVar: case vpiMemoryWord: case vpiReg: case vpiTimeVar: case vpiNet: /* If we are skipping all signal or this is in an automatic * scope then just return. */ if (skip || vpi_get(vpiAutomatic, item)) return; /* Skip this signal if it has already been included. * This can only happen for implicitly given signals. */ if (vcd_names_search(&vcd_var, fullname)) return; /* Declare the variable in the VCD file. */ name = vpi_get_str(vpiName, item); prefix = is_escaped_id(name) ? "\\" : ""; /* Some signals can have an alias so handle that. */ nexus_id = vpi_get(_vpiNexusId, item); ident = 0; if (nexus_id) ident = find_nexus_ident(nexus_id); if (!ident) { ident = strdup(vcdid); gen_new_vcd_id(); if (nexus_id) set_nexus_ident(nexus_id, ident); /* Add a callback for the signal. */ info = malloc(sizeof(*info)); info->time.type = vpiSimTime; info->item = item; info->ident = ident; info->scheduled = 0; cb.time = &info->time; cb.user_data = (char*)info; cb.value = NULL; cb.obj = item; cb.reason = cbValueChange; cb.cb_rtn = variable_cb_1; info->dmp_next = 0; info->next = vcd_list; vcd_list = info; info->cb = vpi_register_cb(&cb); } /* Named events do not have a size, but other tools use * a size of 1 and some viewers do not accept a width of * zero so we will also use a width of one for events. */ if (item_type == vpiNamedEvent) size = 1; else size = vpi_get(vpiSize, item); fprintf(dump_file, "$var %s %u %s %s%s", type, size, ident, prefix, name); /* Add a range for vectored values. */ if (size > 1 || vpi_get(vpiLeftRange, item) != 0) { fprintf(dump_file, " [%i:%i]", (int)vpi_get(vpiLeftRange, item), (int)vpi_get(vpiRightRange, item)); } fprintf(dump_file, " $end\n"); break; case vpiModule: case vpiGenScope: case vpiFunction: case vpiTask: case vpiNamedBegin: case vpiNamedFork: if (depth > 0) { /* list of types to iterate upon */ static int types[] = { /* Value */ vpiNamedEvent, vpiNet, /* vpiParameter, */ vpiReg, vpiVariables, /* Scope */ vpiFunction, vpiGenScope, vpiModule, vpiNamedBegin, vpiNamedFork, vpiTask, -1 }; int i; int nskip = (vcd_names_search(&vcd_tab, fullname) != 0); /* We have to always scan the scope because the * depth could be different for this call. */ if (nskip) { vpi_printf("VCD warning: ignoring signals in " "previously scanned scope %s.\n", fullname); } else { vcd_names_add(&vcd_tab, fullname); } name = vpi_get_str(vpiName, item); fprintf(dump_file, "$scope %s %s $end\n", type, name); for (i=0; types[i]>0; i++) { vpiHandle hand; vpiHandle argv = vpi_iterate(types[i], item); while (argv && (hand = vpi_scan(argv))) { scan_item(depth-1, hand, nskip); } } /* Sort any signals that we added above. */ fprintf(dump_file, "$upscope $end\n"); } break; } }