my input in systemverilog is in bits; but I need it to be in uint8_t. is API or library can do it? FYI, Im trying to verify verilog results with .C using "dpi".
system verilog:
//import "DPI-C" function int test_encrypt_ecb();
import "DPI-C" function void compute_bit(input bit i_value, output bit result);
import "DPI-C" function bit get_bit(input bit i_value);
import "DPI-C" function void compute_logic_vector(reg[127:0] i_value, reg[127:0] result, int asize);
c:
void compute_reg_vector(const svLogicVecVal* i_value, svLogicVecVal* result,
int asize) {
log_info("dpi_c.compute_reg_vector(): input %s",
svLogicVecVal2String(i_value, asize));
uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
int j =0;
struct AES_ctx ctx;
j++;
AES_init_ctx(&ctx, key);
f2(&ctx, i_value);
int i;
for(i=0;i<15;i++){
printf("ECB encrypt: ");
memcpy(&result, i_value, 16);
log_info("dpi_c.compute_reg_vector(): result %s",
svLogicVecVal2String(result, asize));
}
void f2(const struct AES_ctx* ctx, uint8_t* buf)
{
Cipher((state_t*)buf, ctx->Ry);
}
error of c compilation
warning: passing argument 2 of \f2\u2019 from incompatible pointer type [enabled by default]
note: expected \u2018uint8_t *\u2019 but argument is of type \u2018const struct svLogicVecVal *\u2019
void f2(const struct AES_ctx* ctx, uint8_t* buf);
warning: \u2018main\u2019 is normally a non-static function [-Wmain]
int main(void)
There are no API functions to convert from svLogicVecVal to other C types. You have to understand the C data structure representation of a 4-state (0,1,X,Z) data type which is
typedef struct t_vpi_vecval {
uint32_t aval; // 2-state component
uint32_t bval; // 4-state component
} s_vpi_vecval, *p_vpi_vecval;
typedef s_vpi_vecval svLogicVecVal;
A 128-bit packed 4-state value would be stored in an array of 8 32-bit words. The aval/bval words would be interwoven. Assuming you are only dealing with 2-state values, then picking up every other 32-bit word will work for you.
However, if you know your DPI routines only need to deal with 2-state values, then your routines should use bit instead of reg/logic. Then your C routines only need to deal with svBitVecVal, which is defined as
typedef uint32_t svBitVecVal;
Which you can cast to uint8_t* as long as your arguments are multiples of 8 bits.
Note for single bit arguments or return values, it is much more efficient to use C compatible types like byte/int that can be passed by value and require no pointers.
Here is a small example
SystemVerilog code:
module top;
import "DPI-C" function void compute_logic_vector(bit[127:0] i_value);
logic [127:0] x = 128'h69c4_e0d8__6a7b_0430__d8cd_b780__70b4_c550;
initial compute_logic_vector(x); // SV handles the 4- to 2-state conversion for you
endmodule
C code:
#include "svBitVecVal.h" // compiler generated header guarantees prototypes match
#include <stdint.h>
#include <stdio.h>
void compute_logic_vector(const svBitVecVal* i_value) {
uint8_t* buf = (uint8_t*) i_value;
for(int i=0;i<16;i++)
printf("0x%x ",*buf++);
printf("\n");
}
Command line to run Questa:
qrun svBitVecVal.sv -dpiheader svBitVecVal.h svBitVecVal.c
Output:
# 0x50 0xc5 0xb4 0x70 0x80 0xb7 0xcd 0xd8 0x30 0x4 0x7b 0x6a 0xd8 0xe0 0xc4 0x69
Related
I have inherited a very ancient (start of 2000s) Code base that consists of a driver and a kernel module and it crashes for some combinations of compiler flags/architectures. At some point an offset is incorrect for an unknown reason and when I skimmed the code base I found a lot of unaligned access and wanted to clean up this part to remove these potential issues. Example:
uint32_t* p = ....; // <-- odd address on right side.
uint32_t b = *p + 1;
I know that current processors handle such cases without noticeable delays, and I had problems finding hardware that would trigger a BUS error (I once had a RPi 1 that would produce bus errors when setting /proc/cpu/alignment to 4). I wanted to make sure the compiler generates code that correctly access the memory. My first draft for reading a 32 bit integer and converting it from network to host byte order (there was already a macro for that) for an unaligned address was thus (dest and src are pointers to some memory):
#define SWAP32(dest, src) \
do { \
uint32_t tmp_ = 0; \
memcpy(&tmp_, (const char*)(src), sizeof(tmp_)); \
tmp_ = bswap_32(tmp_); \
memcpy((char*)(dest), &tmp_, sizeof(tmp_)); \
} while(0)
I then wanted to create a macro to wrap pointer accesses for other cases that were not yet wrapped in a macro and came up with the following solution (sample contains code to make it compile):
#include <stdint.h>
#include <stdio.h>
struct __attribute__((packed)) unaligned_fix_32 { uint32_t n; };
#define GET32(x) ((struct unaligned_fix_32*)(x))->n
int main(int argc, char* argv[])
{
char mem[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint32_t n = GET32(&mem[1]);
printf("0x%8.8x\n", n);
}
My goal is to wrap pointer accesses inside this macro everywhere. The idea is that, knowing the struct is packed, the compiler will generate code that accesses memory in a way that avoids a potential bus error on architectures that cannot access unaligned memory.
EDIT: I changed my code to the following new version:
static inline uint32_t get_be_unaligned_u32(const void* p)
{
uint32_t u32;
memcpy(&u32, (const char*)p, sizeof(u32));
return bswap_32(u32);
}
#define GET32(src) get_be_unaligned_u32(src)
Please answer questions also for the new version:
Is this a workable solution on real hardware? Can anyone check this? Using -fsanitize=alignment produces the proper exceptions without the attribute packed, but the generated assembler simply checks addresses with & 0x3 and raises a trap if it is not zero.
Is this undefined behavior?
Are there better/other methods to detect/fix/simulate unaligned access inside a C/C++ program?
Can I somehow do this using QEmu?
Is the SWAP32 macro UB?
I have a simple code of seven segment deceleration :
#include<avr/io.h>
#include<util/delay.h>
int dp=1<<0;
int a=1<<1;
int b=1<<2;
int c=1<<3;
int d=1<<4;
int e=1<<5;
int f=1<<6;
int g=1<<7;
int ss[]={
a|b|c|d|e|f,
b|c,
a|b|g|e|d,
a|b|g|c|d,
f|g|b|c,
a|f|g|c|d,
a|f|g|c|d|e,
a|b|c,
a|b|c|d|e|f|g,
a|b|c|d|f|g,
0x00
};
int main()
{
while(1){}
}
But this gives me error when I am trying to generate .hex from this .c code:
Here is the error:
main.c:12: error: initializer element is not constant
main.c:12: error: (near initialization for 'ss[0]')
...
Same for all element..
Variables with the static storage duration shall be initialized with compile-time constant expressions.
Instead of the set of the variables use an enumeration. For example
#include <stdio.h>
enum
{
dp=1<<0,
a=1<<1,
b=1<<2,
c=1<<3,
d=1<<4,
e=1<<5,
f=1<<6,
g=1<<7
};
int ss[]={
a|b|c|d|e|f,
b|c,
a|b|g|e|d,
a|b|g|c|d,
f|g|b|c,
a|f|g|c|d,
a|f|g|c|d|e,
a|b|c,
a|b|c|d|e|f|g,
a|b|c|d|f|g,
0x00
};
int main(void)
{
return 0;
}
One way to do this is to ensure they are constants (available at compile time), by changing it to:
#define dp 0x01
#define a 0x02
#define b 0x04
#define c 0x08
#define d 0x10
#define e 0x20
#define f 0x40
#define g 0x80
I wouldn't worry too much about making them 1<<n values since the number of times you'll have to change it will be vanishingly small.
Changing them to const int doesn't seem to help. I suspect constexpr would be an ideal solution for this, except for the fact it's C++ :-)
If you have binary constants available to you, you may also want to lokk into something like:
static const int sevenSegMap[] = {
// .abcdefg
0b01111110, // or use 0xfe if no binary constants.
0b00110000,
: and so on
0b01111011,
};
I have two files main.c and foo.c, I am trying to copy an array of functions from one file to another.
My problem is: Only the first item is getting copied.
This is my code:
foo.c:
void foo1();
void foo2();
void foo3();
void foo4();
void foo5();
void foo6();
void foo7();
void (*myFuncs[7])() = {
foo1,
foo2,
foo3,
foo4,
foo5,
foo6,
foo7
};
void* getMyFuncs(){
return myFuncs;
}
main.c:
void (*things[7])();
void main(){
memcpy(things, getMyFuncs(), sizeof(getMyFuncs()));
}
After running, in debug mode, I inspected my array things and only foo1 pointer has copied.
So, my output has:
void (*things[7])() = {
foo1 (hex address here),
0x00,
0x00,
0x00,
0x00,
0x00,
0x00
};
What I expected:
void (*things[7])() = {
foo1 (hex address here),
foo2 (hex address here),
foo3 (hex address here),
foo4 (hex address here),
foo5 (hex address here),
foo6 (hex address here),
foo7 (hex address here)
};
Why only the first item is getting copied?
Thanks
I found the solution, it was a silly mistake!
My line:
memcpy(things, getMyFuncs(), sizeof(getMyFuncs()));
is wrong, I don't want to copy the size of getMyFuncs().
The write way to copy is by getting the size of my array of functions:
memcpy(things, getMyFuncs(), sizeof(things));
In the following project, the necessary parameters to initialize test.c are arranged in the structure DataStructure (Here I have only a pointer U8* Buffer). During init, the pointer Buffer is initialized (is pointed to an array) and the function test_init passes the initData to test.c. In test.c the content of the array is printed.
main.c
#include <stdio.h>
#include <stdlib.h>
#include "test.h"
void init(DataStructure *pSL);
void main(void);
void main(void) {
DataStructure initData[COUNT];
init(&initData[0]);
test_init(&initData[0]);
test_run();
}
void init(DataStructure *pSL)
{
U8 Buffer[8] = {0xF1 , 0xF2 , 0xF3 , 0xF4 , 0xF5 , 0xF6 , 0xF7 , 0xF8};
DataStructure SL;
U8* pC = &Buffer[0];
SL.Buffer = pC;
*pSL = SL;
}
where test.c and test.h are:
#ifndef TEST_H_
#define TEST_H_
#ifndef U8
typedef unsigned char U8;
#endif
typedef struct{
U8 *Buffer;
} DataStructure;
#define COUNT 1
void test_init (DataStructure *List);
void test_run ();
#endif /* TEST_H_ */
and
#include <stdio.h>
#include <stdlib.h>
#include "test.h"
static DataStructure *pD;
void test_init (DataStructure *_pD)
{
pD = _pD;
printf("\n test_init: ");
for(int i=0;i<8;i++)
printf("0x%0x, ",*(pD->Buffer+i));
}
void test_run (void)
{
printf("\n test_run: ");
for(int i=0;i<8;i++)
printf("0x%0x, ",*(pD->Buffer+i));
}
The output of this code is:
test_init: 0x0, 0x0, 0x0, 0x0, 0xf5, 0xf6, 0xf7, 0xf8,
test_run: 0x0, 0x0, 0x0, 0x0, 0xf5, 0xf6, 0xf7, 0xf8,
which is wrong. But if I print the elements of SL.Buffer within init function as well, i.e if I change the init function as follows:
void init(DataStructure *pSL)
{
U8 Buffer[8] = {0xF1 , 0xF2 , 0xF3 , 0xF4 , 0xF5 , 0xF6 , 0xF7 , 0xF8};
DataStructure SL;
U8* pC = &Buffer[0];
SL.Buffer = pC;
*pSL = SL;
printf("\n main: ");
for(int i=0;i<8;i++)
printf("0x%0x, ",*(SL.Buffer+i));
}
, the array is passed correctly:
main: 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
test_init: 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
test_run: 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
Could anybody explain me whats wrong whit this code and why the problem is fixed just by printing the array in init function?
And is it the right way to initialize and pass a structure containing a pointer?
The code is a simple version of my project. Originaly the DataStructure contains more parameters and the parameter COUNT (size of initData is more than one.
The problem, as I see it is with the usage of Buffer array.
It is local to the init() function, yet you return the address of the first element of the array to be used outside the function, where the array does not exist anymore. Hence, the address is essentially invalid and any attempt to access that memory will cause undefined behavior.
In the second case, it works fine, as you're printing the array before it ceases it's lifetime, so you're getting expected result.
Solution: You need to allocate static storage to the Buffer array, or use memory allocator function so as, the lifetime of the memory supersede the function scope.
I have a C static library and within it I have one function named returnBytes(), this function is defined this way:
extern "C" unsigned char * returnBytes(void)
{
static unsigned char result[50] = { 0xF0, 0xF0, 0xF0 };
return result;
}
on my other project which is using the above static library (.lib) I call the function like this:
unsigned char *output = returnBytes();
but when I print the content of output, its not correct. meaning that calling a custom print function like this does not return the correct values:
print_bytes(output, 50);
On the other hand calling returnBytes() from within the library works fine. Meaning that the values 0xF0, 0xF0, 0xF0 are printed.
Does the static keyword only maintains the variable values within the same project? Could it be that the static keyword doesn't work if used within a static library function that is called from a c lient project?
Should I be using malloc instead and pass a pointer to returnBytes()? is that the only way?
I am running Windows 7, and I using VC12 for compiler for library and client of library.
EDIT: Sorry didn't notice the static. With the static it works.
I just tested your code on osx and it works correctly as below.
test.h:
#ifndef TEST_H
#define TEST_H
#ifdef __cplusplus
extern "C" {
#endif
unsigned char * returnBytes(void);
#ifdef __cplusplus
}
#endif
#endif /* TEST_H */
test.c :
unsigned char * returnBytes(void)
{
static unsigned char result[50] = { 0xF0, 0xF0, 0xF0 };
return result;
}
Built as a library libtest.a and called by main.c in other project
#include <cstdlib>
#include <cstdio>
using namespace std;
#include "./test.h"
int main(int argc, char** argv) {
unsigned char *c = returnBytes();
printf("%x %x %x\n", c[0], c[1], c[2]);
c[1]= 0xd0;
c = returnBytes();
printf("%x %x %x\n", c[0], c[1], c[2]);
return 0;
}
The output is
f0 f0 f0
f0 d0 f0
which means you can both read and write.
static only works inside your function. Moreover any usual variable (located in the stack) will always die at the end of the function, hence the wrong result.
To fix this, use a dynamic allocation inside your function:
unsigned char *result = calloc(50, 1);
result[0] = 0x50;
result[1] = 0x50;
result[2] = 0x50;
return result;