rggen / rggen

Code generation tool for control and status registers

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Output C headers for embedded SW

aignacio opened this issue · comments

Hey @taichi-ishitani,

thanks for this project, it's really impressive the framework. Quick question, are you looking to implement C headers generation as an output? Nothing fancy but something that SW engineers could simply include to start design drivers, like

#define REGISTER_FILE_0_BASE_ADDR  0x00000000
#define REGISTER_FILE_0_BIT_0_MASK 0x00000001
....

Hi @aignacio ,

Thank you for your feedback!
Yes, I'm intend to implement C header generation but I'm troubled.

Width of bit field/register has no limit; we can define a bit field/register of which width is greater than 64 bits. For example:

register:
- name: reg_0
  offset_address: 0x00
  bit_fields:
  - { name: field_0, bit_assignment: { width: 64, lsb:  0 }, type: rw, initial_value: 0 }
  - { name: field_1, bit_assignment: { width:  1, lsb: 64 }, type: rw, initial_value: 0 }

I'm wondering how to define C macros for this case.
Do you have any idea?

@taichi-ishitani,

hmm, I understand the issue you're explaining. Maybe you could add an optional register parameter like c_fmt which would allow either 32 or 64 bits option to format every register into chunks of 32/64 for C header generation, this way it is up to the user to align the bitfields to match its intention. In case the parameter is set and the user configures wrongly the optional parameter c_fmt by making registers wider an error can be thrown explaining the mismatch. I think this error is not a problem because usually when you access the CSRs through a CPU it is either word-aligned or d-word aligned and the AXI txn will match this size of the registers. In my opinion, I don't see any practical reason why we could have a CSR with a width bigger than 32/64b for instance as the main usage of the CSRs are to configure the accelerator to run some task, also enabling 32b / 64b options you cover almost all CPUs in the earth =).

Something like this for instance:

Input cfg

register:
- name: reg_0
  offset_address: 0x00
  c_fmt: 32
  bit_fields:
  - { name: field_0, bit_assignment: { width: 1,   lsb:  0 }, type: rw, initial_value: 0 }
  - { name: field_1, bit_assignment: { width: 1,   lsb:  1}, type: rw, initial_value: 0 }
  - { name: field_2, bit_assignment: { width: 4,   lsb:  3}, type: rw, initial_value: 0 } 

Output C header

#define REG_0_BASE_ADDR        0x0000 // 32-bit fmt, for 64-bit 0xXXXX_XXXX
#define REG_0_FIELD_0_OFFSET   0x0
#define REG_0_FIELD_0_MASK     0x1
#define REG_0_FIELD_1_OFFSET   0x1
#define REG_0_FIELD_1_MASK     0x1
#define REG_0_FIELD_2_OFFSET   0x3
#define REG_0_FIELD_2_MASK     0xF

That's just a suggestion if you think it's irrelevant or that doesn't work it's fine, but having something like that would make it even greater IMO. =)

commented

@taichi-ishitani I have just discovered your work in the last few hours, so I am still getting up to speed so please forgive any misunderstanding.

For registers wider than the bus interface I think it the macro format might be already handled by MISRA. I think previous register tools handled header generation for wider registers.

Not only is there a question about what the macro format is, but also the question about how to provide "coherent" access to wide registers, that is how to avoid race condition in the register access.

A classic example would be how to access a 64bit timer register via a 32bit bus that avoids race condtion.

I will continue to review your tool as it looks promising and something I have been looking for. Thank you for your efforts.

@aignacio ,
Thank you for your suggestion! It's nice idea!
I agree with that an error can be raised for the case that bit field width is greater than bus width.
I thin we can achieve this without any optional parameter because we can also check width of register when we're executing C header generation.

@roowatt ,
Thank you for the information!
I'm not familiar with MISRA so can you give me a code sample?

I've create a ticket for development of C header file generator #105 .
Can you add comments to this issue if you have any idea, feedback?

Hi,
I need your feedback.
The previous RgGen can generate C struct like this.
https://github.com/taichi-ishitani/rggen/blob/411fff9f6618ffdbdc59bcb45a2d6bf39a7e40d5/sample/sample_0.h#L4

I have a problem related to generating such C struct.
The current RgGen allow a write-only register and a read only register of which address ranges are overwrapped.
For example:

  • register_0
    • write only
    • offset: 0x00
    • size: 8 bytes
  • register_1
    • read only
    • offset: 0x04
    • size: 8 bytes

register_0 and register_1 share the address range 0x4 - 0x7.

In this case, how can I map these registers into a C struct? Use union?

commented

Hi,

I have discussed the MISRA related issue I raised with my Embedded SW ENg colleague, it appears I was misguided. While MISRA does have recommendations for coding style, including how C header files and macros are written it does not stipulate how Command and Control register access macros should be written.

I have previously written C structs using unions to provide multiple ways to address the same memory address. Using a union should work, however I think it might be simpler to require the user to not overlap the registers.

I have looked at other register tools before, they handle some of the more diffiult cases by limiting what it supported.

eg Raising an error if the register width is wider than the bus width. Require the user to break the register definition into non-overlapping regions.

I am not a software expert, I usually write early header files etc to support testing of the RTL under design. This is why I am very keen on finding a register tool that can handle this for me.

Hey @taichi-ishitani,

my suggestion follows what was commented by @roowatt. I think your project is really amazing and very flexible, due to the flexibility we have such scenario as you mentioned but in my opinion in a real use-case it is very unlikely that would happen though. I agree that throwing an error to avoid such overlap it'd be the best approach for now because it seems more like a side-effect feature that the user wants, once that overlap could be RW. Also, user can simply fix that by splitting its definitions in the registers file. In the industry side, all the CSR generation tools I have worked with never supported any sort of overlap.

Hi @roowatt , @aignacio ,
Thank you for your feedback! I agree with your opinion.

However there are some IP blocks which have overlapped address ranges.
For example, UART IP may have tx buffer and rx buffer which are mapped into the same address.
In addition, write-only register and read-only register which have the same size and offset address can be mapped into C struct by using union.
Therefore, I think RgGens should support this kind of case.

On the other hand, registers of which address spaces are partially overlapped cannot be mapped into C struct. For this case, RgGen should throw an error.

commented

Hi @taichi-ishitani,

Yes, that is a good point... if the two registers are "fully" overlapped then that makes sense to support, I wasn't thinking of that case.

For the full overlap I agree with the union once it makes sense as it acts like a cast but not for partial overlap, that's actually the case I'm referring there =)

Hi @roowatt , @aignacio
Thank you for your comment!
my issue is cleared because of your help:)

Hi,
I've added sample C header files.
https://github.com/rggen/rggen-sample/blob/master/block_0.h
https://github.com/rggen/rggen-sample/blob/master/block_1.h
Are these header files suitable for your use case?

Hey @taichi-ishitani
it seems fine for me, thanks for implementing this feature!

Hi,
I've just released the plugin for C header file generation.
https://github.com/rggen/rggen-c-header
https://rubygems.org/gems/rggen-c-header
This is an experimental feature so I've released this plugin as an optional plugin.

You can generate C header files by using this plugin like below.

$ rggen --plugin rggen-c-header -c config.yml block_0.yml block_1.yml

Hi @aignacio ,
Can I close this ticket?

Sure, closing now, I have tested on my design and it works fine! =)