-1

I am trying to get my system verilog code to work with my c code, but I am getting a strange output. My exp_data_out should be the output of my encoder but it is zzzzxzzzzzxzxzz instead. Can someone tell me why the output is this?

C

void encoder(
            int data_in,
            int* data_out,
            int* parity_out

    )
{
int i, a[10], c[4], r[14], clk[4], n, sum = 0;
printf("%d\n", data_in);
a[0]= data_in & 1;
a[1]= data_in>>1 & 1;
a[2]= data_in>>2 & 1;
a[3]= data_in>>3 & 1;
a[4]= data_in>>4 & 1;
a[5]= data_in>>5 & 1;
a[6]= data_in>>6 & 1;
a[7]= data_in>>7 & 1;
a[8]= data_in>>8 & 1;
a[9]= data_in>>9 & 1;
a[10] =data_in>>10 & 1;
printf("%x\n", data_in&(512));    
printf("%x\n", a[0]);
c[0]=(a[0] + a[1] + a[3] + a[4] + a[6] + a[8] + a[10])%2;
c[1]=(a[0] + a[2] + a[3] + a[5] + a[6] + a[9] + a[10])%2;
c[2]=(a[1] + a[2] + a[3] + a[7] + a[8] + a[9] + a[10])%2;
c[3]=(a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + a[10])%2;

printf("data bits after hamming code is\n");

for(i=10;i>=0;i--) {
    printf("%d",a[i]&1);
}
printf("\n");
for(i=3;i>=0;i--) {
    printf("%d",c[i]);
}
printf("\n");
*data_out = data_in;
*parity_out = ((c[3]&1) << 3) | ((c[2]&1) << 2) | ((c[1]&1) << 1) | ((c[0]&1));
 }

System Verilog

  import "DPI-C" context encoder= function void encoder(input int data, output logic [14:0] outData,  output int parity );


module dpi_example ();
  parameter size = 15;
  parameter p_size = 4;
   logic   [10:0] rtl_data_in;
   logic   [14:0] rtl_data_out;
   logic   [14:0] exp_data_out;
   logic   [p_size-1:0] parity_out;
   bit clk;       

   initial begin
      clk =0;
      #80;
      $finish;
   end

   always #1 clk = ~clk;

   always @(posedge clk) begin

      rtl_data_in = $urandom % 2048; //generate random data
      $display("rtl_data_in: %b", rtl_data_in); 
      encoder(rtl_data_in, exp_data_out, parity_out); 

   end

   // generate the rtl output
   ham_enc L1( .enc_data_in(rtl_data_in), .enc_data_out(rtl_data_out));
   ham_dec L2( .data_in(rtl_data_out), .data_out(decoder_data_out));

   //compare expected data and encoder output
   always @(negedge clk) begin
       if (exp_data_out == rtl_data_out) begin
           $display("%t: PASS, Input: %b, Output (EXP/RTL) (%b/%b)", $time, rtl_data_in, exp_data_out, rtl_data_out);
       end else begin
           $display("%t: FAIL, Input: %b, Output (EXP/RTL) (%b/%b)", $time, rtl_data_in, exp_data_out, rtl_data_out);
       end
   end


endmodule

This is the output

78: FAIL, Input: 10000010100, Output (EXP/RTL) (zzzzxzzzzzxzxzz/100000100100000)
Greg
  • 18,111
  • 5
  • 46
  • 68
excode
  • 1
  • 1

1 Answers1

3

Your problem is the prototype for the data_out argument in your SystemVerilog import statement does not match the C code. You have it declared as logic [14:0] in the import and int in the C code. It should be int in both. Since output arguments are copied by value, data_out will be cast to 15 bits when assigned to exp_data_out. The way your code is written now, you have data_out as an int type, but the SystemVerilog compiler is expecting the format of the argument to be a 4-state logic vector, which needs to be written is a special structure.

When using the DPI, I strongly recommend keeping all arguments C-compatible (int, char/byte, and arrays or structures of those types). You will get much better performance, as well as run into fewer issues dealing with non-C compatible types on the C side.

If you are using Modelsim/Questa, you can compile your code and generate a C header file

vlog mysource.sv -dpiheader dpi.h mysource.c

and then #include that header file in you C source code. That way the C compiler will give you an error if the prototypes do not match, instead of a run time error, or worse a fatal error that could be very difficult to locate.

dave_59
  • 39,096
  • 3
  • 24
  • 63