SystemRDL / PeakRDL-regblock

Generate SystemVerilog RTL that implements a register block from compiled SystemRDL input.
http://peakrdl-regblock.readthedocs.io
GNU General Public License v3.0
52 stars 42 forks source link

SW = rw, HW = rw behavior seems incorrect #94

Closed paul-demo closed 7 months ago

paul-demo commented 7 months ago

This is my first time using SystemRDL so I could be just using the wrong SystemRDL input or missing some feature. But anyway, here's my problem as I compare PeakRDL to 2-3 other commercial CSR generators I use now and in the past.

When I set SW=rw and HW=rw, I would expect that SW has a register that is readable and writable from AXI-LITE where:

While PeakRDL-regblock does do this, it only momentarily pulses the "hw_out" value to the written value for a single cycle (and doesn't provide a "strobe", by default, so there's no way to register it). The written value is active for a single cycle then "hw_out" immediately registers the value derived from hardware on "hw_in".

An example is here: 0xC is provided by hardware. 0xA is written by software and the value from SW -> HW only goes to 0xA for a single cycle then reverts back to 0xC. This is not what I would expect. The behavior I would like to have is basically AirHDL's "volatile", where writes set the SW -> HW value, and reads read the HW -> SW value, but the hardware value does not register hw_out <= hw_in when writes are not occurring.

image

paul-demo commented 7 months ago

Actually I see there is the "we" write enable feature. That only partially solves the issue because it overwrites the value which was written from software. So whoever wrote the value most recently (software or hardware) overwrites the other's settings.

What I want is a feature where the SW -> HW value and the SW <- HW value are independent. It seems the only way to do that in PeakRDL-regblock is to create two registers with SW=rw, HW=r and SW=r, HW=w.

amykyta3 commented 7 months ago

You're very close. In SystemRDL, this would be considered two separate fields with opposing access policies. Fortunately the language allows you to overlap registers or fields, as long as their access policies do not conflict. So to accomplish what you want you would do:

reg {
    field {
        sw = r;
        hw = w;
    } ro_field[31:0];
    field {
        sw = w;
        hw = r;
    } wo_field[31:0];
} volatile_rw_reg;
paul-demo commented 7 months ago

Great, I'll try that out. Thanks for your help!