0

I have the following memory structure:

struct {
   uint16_t MSB_VALUE : 8;
   uint16_t : 8;
   uint16_t LSB_VALUE;
} BIG_VALUE;

This structure, all together, represents a 32-bit section of memory that is fixed by hardware. The value of BIG_VALUE can be represented using Verilog concatenation notation thus:

BIG_VALUE = { MSB_VALUE[7:0], LSB_VALUE[15:0] } 

I would like to be able to write a union (or something) such that I can access the value of BIG_VALUE using dot notation. Maybe something stupid like this:

union {
   uint32_t val;
   struct {
      uint16_t MSB_VALUE : 8;
      uint16_t : 8;
      uint16_t LSB_VALUE;
   } sub;
} BIG_VALUE;

But, the issue is that the MSB comes before the LSB in memory (with an 8-bit gap too), and so calling BIG_VALUE.val isn't going to get the hoped-for value.

I have a vague idea of something to try, but I'm just confusing myself. Is there a way to do this within the union/struct formalism, or should I give up now? Giving up, I guess, means having to manually split up the 24-bit value and then to store those into the appropriate fields. Maybe I could write a function to do that later, if it makes sense.

Having this work means that I could store a 24-bit value using dot notation and have the data go into the appropriate locations in memory. For example:

BIG_VALUE.val = 0x0031FFFE
Then 
BIG_VALUE.MSB_VALUE == 0x31
and
BIG_VALUE.LSB_VALUE == 0xFFFE

But the memory layout would be
addr    : 0x0031
addr +4 : 0xFFFE
beeflobill
  • 317
  • 1
  • 10
  • 1
    Why are you doing 8-bit bitfields on 16-bit fixed width types instead of just using 8-bit fixed width types (`uint8_t`)? – Christian Gibbons Dec 10 '19 at 23:36
  • I hadn't considered doing it like that. However, the ultimate goal is to build a table that will be written to registers that are 16 bits wide per address. So, I was just thinking of things in terms of 16-bits. – beeflobill Dec 10 '19 at 23:40
  • FYI, `sizeof(BIG_VALUE)` will be >= 48-bits (because of padding). Also it's technically invalid to access a different member of a union than the one which was instantiated. – LegendofPedro Dec 10 '19 at 23:45
  • I would use `malloc` (guaranteed contiguous memory) for an array of `uint8_t` and write getter/setter functions that shift and mask as appropriate. You could then use `memcpy` with a pointer to the base address. – LegendofPedro Dec 10 '19 at 23:47
  • @LegendofPedro I see how the padding is problematic, but perhaps careful use of the "packing" pragma can make this work. But, I'm getting the sense that what I'm trying to do here is wishful thinking. – beeflobill Dec 11 '19 at 00:04
  • 1
    @LegendofPedro It's only illegal in C++ to access unions that way. It's fine in C. There's a footnote somewhere in the C11 standard that clarifies this point, but I don't have it in front of me right now. – Christian Gibbons Dec 11 '19 at 01:03
  • @christiangibbons that's good to know! I looked into it, it's called type-punning. https://stackoverflow.com/a/11996970/5495906 : c11 standard 6.5.2.3 Structure and union members 95 – LegendofPedro Dec 11 '19 at 03:18

0 Answers0