Exemplo n.º 1
0
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;
}
Exemplo n.º 2
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;
}