tags:

views:

147

answers:

1

I have a 256-bit value in Verilog:

reg [255:0] val;

I want to define a system task $foo that calls out to external C using the VPI, so I can call $foo like this:

$foo(val);

Now, in the C definition for the function 'foo', I cannot simply read the argument as an integer (PLI_INT32), because I have too many bits to fit in one of those. But, I can read the argument as a string, which is the same thing as an array of bytes. Here is what I wrote:

static int foo(char *userdata) {
  vpiHandle systfref, args_iter, argh;
  struct t_vpi_value argval;
  PLI_BYTE8 *value;

  systfref = vpi_handle(vpiSysTfCall, NULL);
  args_iter = vpi_iterate(vpiArgument, systfref);

  argval.format = vpiStringVal;
  argh = vpi_scan(args_iter);
  vpi_get_value(argh, &argval);
  value = argval.value.str;

  int i;

  for (i = 0; i < 32; i++) {
    vpi_printf("%.2x ", value[i]);
  }
  vpi_printf("\n");

  vpi_free_object(args_iter);
  return 0;
}

As you can see, this code reads the argument as a string and then prints out each character (aka byte) in the string. This works almost perfectly. However, the byte 00 always gets read as 20. For example, if I assign the Verilog reg as follows:

 val = 256'h000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f;

And call it using $foo(val), then the C function prints this at simulation time:

VPI: 20 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f

I have tested this with many different values and have found that the byte 00 always gets mapped to 20, no matter where or how many times it appears in val.

Also, note that if I read the value in as a vpiHexStrVal, and print the string, it looks fine.

So, two questions:

  1. Is there a better way to read in my 256-bit value from the Verilog?
  2. What's going on with the 20? Is this a bug? Am I missing something?

Note: I am using Aldec for simulation.

+2  A: 

vpiStringVal is used when the value is expected to be ASCII text, in order to get the value as a pointer to a C string. This is useful if you want to use it with C functions that expect a C string, such as printf() with the %s format, fopen(), etc. However, C strings cannot contain the null character (since null is used to terminate C strings), and also cannot represent x or z bits, so this is not a format that should be used if you need to distinguish any possible vector value. It looks like the simulator you are using formats the null character as a space (0x20); other simulators just skip them, but that doesn't help you either. To distinguish any possible vector value use either vpiVectorVal (the most compact representation) or vpiBinStrVal (a binary string with one 0/1/x/z character for each bit).

mark4o
I didn't want to use `vpiBinStrVal` or `vpiVectorVal`, because it was inconvenient to have the input formatted one bit at a time. I actually want the data to formatted as 32 8-bit values; I ended up just splicing the 256-bit wire and sending it in as 8 32-bit inputs, which can be read as `vpiIntVal`, and trivially converting that to an array of 32 bytes.
pheaver
Ok but `vpiVectorVal` allows you to read the bits as 32-bit words; it is not one bit at a time.
mark4o
Yes, you are correct, and I misspoke. What I mean is I want an actual integral value, not something that has 'x' and 'z' in it. Not a big deal though, I can convert it.
pheaver
If you don't care about x and z you can just read only the `aval` fields and ignore `bval`.
mark4o