cstructsystem-verilogtext-manipulation

Converting SystemVerilog Structs Into C/C++ Structs


Somewhere in my environment, there's a large file that contains (among other stuff) many System Verilog structs of 64 bits, e.g.:

typedef struct packed {  
  logic [63:63]  my_field_1;  
  logic [62:60]  my field_2;  
  ...  
  logic [0:0]  my field_n;
} my_struct_1_t;

I need a way to convert this into a C/CPP structs with bit fields. e.g.

struct my_struct_1_t {  
  uint64_t my_field_n:1;//This is the LSB
  ...  
  uint64_t my_field_2:3;  
  uint64_t my_field_1:1;//This is the MSB
};

I have no idea how to do that, so would appreciate any help (In any language / shell script etc.).

Thanks!


Solution

  • As many of the comments suggest, C bit fields can be a bit dicey to use. There's no defined in-memory representation, so it's a matter of experimentation with compilers and, probably, a bunch of #pragmas to get a workable combination.

    Three options exist.

    1. Write code

    You could write code to explicitly manipulate the data to isolate each field's bits, and create a structure that simply has ints / bools (no bit fields) in it to contain the parsed data. A simple function to isolate and return any given bit / bit sequence as an int64 would make this a lot easier.

    1. Use ASN.1

    This is a serialisation technology that has multiple wire formats. The one of interest is uPER - unaligned packed encoding rules. You can relatively easily write an ASN.1 schema that - used with uPER - would be able to generate and parse your data. For example, in uPER a BOOLEAN turns into a single bit. An INTEGER (0..15) becomes 4 bits. If you had an ASN.1 PDU such as

    MyStruct ::= SET OF
    {
       my_field_1 [0] BOOLEAN,          -- 1 bit
       my_field_2 [1] INTEGER (0..7),   -- 3 bits as an integer
       etc
    }
    

    the ASN.1 compiler would generate C/C++ code that parses / writes that in uPER wireformat, and that will just so happen to match your data structure. It's a bit like option 1, except that the ASN.1 compiler is writing the code and we're exploiting the uPER wireformat specification to "line up" with your data.

    This ASN.1 compiler is probably up to the job, and I can recommend this web page for an overview, this playground to try things out, and Dubuisson's book available here for free. You can also convert ASN.1 schema to XML schema (XSD), which gives you more options for passing the data on with both you and the recipient working off the same schema.

    1. Use CSN.1

    Whereas ASN.1 is "Abstract syntax notation #1", CSN.1 is "Concrete Syntax Notation #1".

    ASN.1 is all about defining what information needs to be exchanged without a care in the world about how it's represented on the wire (hence the proliferation of binary and text wireformats for it). CSN.1 is all about defining what information needs to be exchanged, and be totally explicit about how it is to be represented on the wire.

    Thus with CSN.1 one can define any arbitrary bit stream, and have a compiler automatically build code that can interpret and write your bit stream. However, there's far fewer tools for this, and things often go wrong. If you are interested in this approach, you're probably looking at one of the commercial tools (such as Objective Systems inc, whose ASN.1 compiler now also handles CSN.1 I think).

    Recommendation: I'd use the ASN.1 approach. The nice thing is that, once you've got that working, your C code can easily re-emit the data in a variety of different formats including XML. That might make life a bit easier if there are onward systems to receive data.

    The ASN.1 compiler from Objective Systems now also supports JER (JSON encoding rules), so it can send data web-wards pretty easily without the recipient necessarily having to know anything about ASN.1 as such.

    If you don't feel like experimenting with ASN.1 uPER, I'd go with writing some code to explicitly handly bits yourself. It's boring boilerplate code, but it's fairly simply and sure. It'd be a lot better than relying on a C compiler to always lay out bit fields in the way you want.