Reading array of regs using Verilator and VPI - verilog

So I have the following register defined in my verilog
reg [31:0] register_mem [0:15]/* verilator public */;
My goal is from my verilator c++ code to read each of the 16 values stored in it.
I have found that the documentation for this VPI stuff is rather difficult to find. I still cannot figure out what a t_vpi_vecval is and what its parameters are or if it is even the right approach.
Here is my approach at reading the 5th value in the register
unsigned int read_regs() {
const std::string path = "TOP.TOP.cpu.reg_file.register_mem";
vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)path.c_str(), NULL);
if (!vh1) {
printf("Name %s", path.c_str());
vl_fatal(__FILE__, __LINE__, "sim_main", "No handle found: ");
}
const char* name = vpi_get_str(vpiName, vh1);
s_vpi_value v;
v.format = vpiVectorVal;
vpi_get_value(vh1, &v);
return v.value.vector[4].aval;
}
No-matter what I do here the method returns 0 suggesting that I am not looking at the register_mem array.
What am I doing wrong?

In order to get values of the array, you need to get values for every element of an array separately. VPI does not return values for the full array.
Actually the handle which you get for an array is a handle of the vpiRegArray type. It can be iterated to access every separate element.
Here is a simple code which does the iteration and prints values of every element in the array:
#include "vpi_user.h"
PLI_INT32 preg_calltf( char *txt ) {
vpiHandle hreg = vpi_handle_by_name("rarr.register_mem", 0);
vpi_printf("reg type: %s\n", vpi_get_str(vpiType, hreg)); // vpiRegArray
s_vpi_value val = {vpiDecStrVal}; // struct t_vpi_value
vpiHandle arrayIterator = vpi_iterate( vpiReg, hreg);
if( arrayIterator != NULL ) {
vpiHandle item = NULL;
while( NULL != ( item = vpi_scan( arrayIterator ) ) ) {
vpi_get_value(item, &val);
vpi_printf("item type: %s = %s\n", vpi_get_str(vpiType, item), val.value.str); // vpiReg
vpi_free_object( item );
}
}
return 0;
}
In this case I initialized the val with vpiDecStrVal. It instructs the compiler to prepare value results as a decimal string. The value is now accessible as val.value.str. You have multiple choices to get string or binary data in 2-state or 4-state representation.
For 2-state values up to 32 bit you can use an integer formatting. However, for longer values or 4-state, you need vpiVectorVal. It actually requests verilog to create 2 arrays of 32-bit integers, aval and bval. Both have sizes big enough to keep all bits of the value. Combination of bits in aval and bval represent the 4-state value of all bits in the vector.
All vpi information is available in LRM including relation diagrams and data structures. There are also some books, for example "the verilog pli handbook" by Sutherland.

Related

How to add pointer char datas (created using malloc) to a char array in C?

In my MPI code in C, i'm receiving a word from each of my slave processes. I want to add all these words to an char array in master side (part of code below). I can print these words but not collect them into a single char array.
(I consider max word length as 10, and number of slave's as slavenumber)
char* word = (char*)malloc(sizeof(char)*10);
char words[slavenumber*10];
for (int p = 0; p<slavenumber; p++){
MPI_Recv(word, 10, MPI_CHAR, p, 0,MPI_COMM_WORLD, MPI_STATUS_IGNORE);
printf("Word: %s\n", word); //it works fine
words[p*10] = *word; //This does not work, i think there is a problem here.
}
printf(words); //This does not work correctly, it gives something like: ��>;&�>W�
Can anybody help me on this?
Let's break it down line by line
// allocate a buffer large enough to hold 10 elements of type `char`
char* word = (char*)malloc(sizeof(char)*10);
// define a variable-length-array large enough to
// hold 10*slavenumber elements of `char`
char words[slavenumber*10];
for (int p = 0; p<slavenumber; p++){
// dereference `word` which is exactly the same as writing
// `word[0]` assigning it to `words[p*10]`
words[p*10] = *word;
// words[p*10+1] to words[p*10+9] are unchanged,
// i.e. uninitialized
}
// printing from an array. For this to work properly all
// accessed elements must be initialized and the buffer
// terminated by a null byte. You have neither
printf(words);
Because you left elements uninitialized and didn't null terminate, you're invoking undefined behavior. Be happy that you didn't get demons crawl out of your nose.
In seriousness though, in C you can copy strings by mere assignment. Your usage case calls for strncpy.
for (int p = 0; p<slavenumber; p++){
strncpy(&words[p*10], word, 10);
}

SHA1 ERROR WHILE USING TinyECC in tinyos-2.x

I am using TinyOS-2.1.2 and to achieve security techniques I am using TinyECC-2.0. I want to use the SHA1 available in tinyecc. But, when I take the hash of a value say,
uint8_t data=123;
I use the three functions of sha given in SHA1.nc namely, SHA1.reset, SHA1.update and SHA1.digest to obtain the result. But each time I run the code ie. do "make micaz sim" I get different hash results for the same data.
How to get a unique hash value for each data taken?
The code is:
#include "sha1.h"
module DisseminationC {
uses {
interface SHA1;
}
implementation{
void hash(){
uint8_t x=123;
call SHA1.context(context);
call SHA1.update(context, x, sizeof(x));
call SHA1.digest(context, Message_Digest[SHA1HashSize]);
dbg("All", "%s Hash is : %d \n", sim_time_string(), Message_Digest);
}
I made modifications in the code as shown below. Now, I am getting a hash output. But the problem is that for every different number given as input I am getting the same answer. How do I solve this issue?
Please help me..
#include "sha1.h"
module SecurityC{
uses interface Boot;
uses interface SHA1;
}
implementation{
uint8_t Message_Digest[SHA1HashSize];
SHA1Context context;
uint8_t num=123;
uint32_t length=3;
uint8_t i;
event void Boot.booted()
{
dbg("Boot", "Application booted.\n");
call SHA1.reset(&context);
while(length>0)
{
length=length/10;
call SHA1.update(&context, &num, length);
}
call SHA1.digest(&context, Message_Digest);
for(i = 0; i < SHA1HashSize; i++) {
dbg("Boot", "%s KEY IS: %x \n", sim_time_string(), Message_Digest[i]);
}
}
}
First of all, your code is bad. It lacks two braces and the function SHA1.context doesn't exist in this library (it should be SHA1.reset, I think). Moreover, Message_Digest and context aren't declared. Please provide the full code you actually use.
However, I see you have at least two serious bugs.
Firstly, you pass the value of x to SHA1.update, but you should pass a pointer to the message. Therefore, the function processes a message that lies at the address 123 in the memory (you should get a compiler warning about this). If you want to calculate a hash from the value of x, try this:
call SHA1.update(context, &x, sizeof(x));
Secondly, Message_Digest seems to be a uint8_t array of size SHA1HashSize. In the last statement you print a pointer to this array instead of its content (and again, the compiler should warn you), so you get an adress of this array in the memory. You may want to process the array in a loop:
uint8_t i;
for(i = 0; i < SHA1HashSize; ++i) {
// process Message_Digest[i], for instance print it
}

How to send an int over uint8_t data?

I'm using the RadioHead Packet Radio library from airspayce.com. In the example (nrf24_reliable_datagram_client & server) they let two nodes communicate with each other by sending strings back and forth. Now I want to send an int instead of a string there, and do something with this data. This is what they do in the example:
Define the buf byte.
uint8_t buf[RH_NRF24_MAX_MESSAGE_LEN];
This function receives the data:
manager.recvfromAckTimeout(buf, &len, 500, &from)
Print the buf variable.
Serial.print((char*)buf);
So far so good.Now I want to do something like:
int value = (char*)buf;
Or:
char value[10] = { (char*)buf };
But then I get:
invalid conversion from 'char*' to 'int' (or to 'char'...)
Next to that, on the other side where I'm sending the data, I have:
uint8_t data[] = { analogRead(A0) };
When I'm printing this data on the receiver side, using the code from the first question, I get weird characters. So I thought, let's try:
Serial.print((char*)buf, DEC); // or BYTE
But then I get:
call of overloaded 'print(char*, int)' is ambiguous
What am I doing wrong? Thanks in advance!
You can't just assign an array to an integer and hope that it merges the elements together for you - for example, how does it know how to merge them?
For converting a uint16_t to a uint8_t[2] array you would want to do something like this:
uint16_t analog = analogRead(A0); //read in as int.
uint8_t data[2] = {analog, (analog >> 8)}; // extract as {lower byte, upper byte)
Serial.write(data,2); //write the two bytes to the serial port, lower byte first.
You could do it in other ways like using a union of a uint16_t with an array of two uint8_t's, but the above way is more portable. You could also do it by type casting the pointer to an int, however if one end uses big endian and the other uses little endian, that won't work unless you flip the data around in the array as you are receiving it.
For the receiver end, you would have:
uint8_t data[2];
...
... //whatever you do to receive the bytes that were sent over serial.
...
//Now assuming that data[] contains the received bytes where:
//data[0] was the first in (lower byte) and data[1] was the second in (upper byte)
uint16_t merged = (data[1] << 8) | data[0]; //merge them back together
Hopefully that helps.
Also, the 'overloaded prototype' is saying that no function exists which takes that particular set of input variables. From the print class header you will find there is however this prototype:
write(const uint8_t *buffer, size_t size);
which does what you want - print a specified number of uint8_t's from an array.

allocating enough memory using typedef struct object whose size varies in another typedef struct

I have defined two typedef structs, and the second has the first as an object:
typedef struct
{
int numFeatures;
float* levelNums;
} Symbol;
typedef struct
{
int numSymbols;
Symbol* symbols;
} Data_Set;
I then defined numFeatures and numSymbols and allocate memory for both symbols and levelNums, then fill levelNums inside a for loop with value of the inner loop index just to verify it is working as expected.
Data_Set lung_cancer;
lung_cancer.numSymbols = 5;
lung_cancer.symbols = (Symbol*)malloc( lung_cancer.numSymbols * sizeof( Symbol ) );
lung_cancer.symbols->numFeatures = 3;
lung_cancer.symbols->levelNums = (float*)malloc( lung_cancer.symbols->numFeatures * sizeof( float ) );
for(int symbol = 0; symbol < lung_cancer.numSymbols; symbol++ )
for( int feature = 0; feature < lung_cancer.symbols->numFeatures; feature++ )
*(lung_cancer.symbols->levelNums + symbol * lung_cancer.symbols->numFeatures + feature ) = feature;
for(int symbol = 0; symbol < lung_cancer.numSymbols; symbol++ )
for( int feature = 0; feature < lung_cancer.symbols->numFeatures; feature++ )
cout << *(lung_cancer.symbols->levelNums + symbol * lung_cancer.symbols->numFeatures + feature ) << endl;
return 0;
When levelNums are int I get what I expect( i.e. 0,1,2,0,1,2,...) but when they are float, only the first 3 are correct and the remaining are very small or very large values, not 0,1,2 like expected. I then have two questions:
When allocating memory for symbols, how does it know how big a Symbol is since I have not yet defined how large levelNums will be yet.
How do I get float values into levelNums correctly.
The reason I am doing it like this is this is a data structure that will be sent to a GPU for GPGPU programming in CUDA and arrays are not recognized. I can only send in a continuous block of memory explicitly and the typedef structs are only there for conveying/defining the memory struture of the data.
A couple thing jump out at meet. For one thing, you only allocated a buffer for levelNums of the first symbol. Similarly, your inner loops always loop over the numFeatures of the first symbol.
You're doing a whole lot of dereferencing of arrays, which is fine in general, but the assignment in particular (inside the first set of loops) looks very strange. It's entirely possible I just don't understand what you're trying to do there, but I think it'd be a lot less confusing if you used some square bracket array accessors.

Having trouble passing array to function

I am getting all kinds of errors when passing my array to this function. The function is suppose to have the user enter a name and a score and store them in 2 seperate arrays, one for the names, one for the scores. I believe I have to use pointers but have no idea on how to use them. I don't want the answer, just a push in the right direction. Here is the code:
#include <iostream>
int InputData(int &, char, int);
using namespace std;
int main()
{
char playerName[100][20];
int score[100];
int numPlayers = 0;
InputData(numPlayers, playerName, score);
return 0;
}
int InputData(int &numPlayers, char playerName[][20], int score[])
{
while (numPlayers <= 100)
{
cout << "Enter Player Name (Q to quit): ";
cin.getline(playerName, 100, ‘\n’);
if ((playerName[numPlayers] = 'Q') || (playerName[numPlayers] = 'q'))
return 0;
cout << "Enter score for " << playerName[numPlayers] <<": ";
cin >> score[numPlayers];
numPlayers++;
}
}
Ok, I made some more changes and the errors are less, must be getting close, Lol!
This looks like a school assignment and I applaud you for not asking for the answer. There are several ways to do it, but you are already fairly close in the approach that you are using. When you pass an array reference, you do not want to include the length of the array. For example, the parameter int score[100] should be int score[]. The exception, especially in your scenario, is with multidimensional arrays. In this case, you want to use char playerName[][20]. Your function declaration also needs to change to match. Don't forget InputData returns an int. Your declarations and function call are correct; you just need to adjust your function signature.
Keeping the errors aside -
InputData(numPlayers, playerName, score, size);
// ^^^^ size is no where declared
// resulting Undeclared indentifier error
Prototype mentions of taking 3 arguments but calling the function passing 4 parameters.
Hint regarding errors:
An 1D array decays to a pointer pointing to first element in the array while passing to a function.
A 2D array decays to a pointer pointing to the 1D array ( i.e., T[][size] ) while passing to a function.
Return type of main() should be int.
It seems with the given hints you corrected most of the errors. But you forgot to change the prototype. So, change -
int InputData(int &, char, int);
to
int InputData(int &, char[][20], int[]);
Why aren't you using std::string array for player names ? Use it and remove rest of the errors. Good luck.

Resources