amaranth icon indicating copy to clipboard operation
amaranth copied to clipboard

Can I create an active-low (asynchronous) reset?

Open hofstee opened this issue 5 years ago • 13 comments

Refiling here instead of other repo. Sorry if it's a duplicate.

Specifically, I'm looking to mimic the following SystemVerilog code:

always_ff @(posedge clk, negedge rst_n)
  if (~rst_n) q <= 0;
  else q <= d;

async_reset=True gets halfway there, but it's still an active-high reset. Any way of making it active-low or somehow creating one manually with this behavior where I can also control the port name?

hofstee avatar Apr 22 '20 11:04 hofstee

Currently there's no way to do so; it is something on my radar for a while, but also not trivial to add in a backward compatible way. Please see the discussion here: https://github.com/nmigen/nmigen/issues/185#issuecomment-596256493.

whitequark avatar Apr 22 '20 11:04 whitequark

Regarding the port name, you can create a clock domain and then rename the signal using cd.rst.name = "foobar", for example. (nMigen guarantees that it will never mangle names of signals you use for ports, unless two of them clash.)

whitequark avatar Apr 22 '20 11:04 whitequark

I'm not sure if I should put this here on in the other thread, but one case where an async active-low reset would be useful (even in FPGAs) is when you want to connect or adhere to something like an AHB/AXI interface. Currently, it wouldn't be possible to do this solely in nmigen unless you wrote a wrapper module around the generated code inverting the reset.

hofstee avatar Apr 22 '20 11:04 hofstee

You'd have to write a wrapper module anyway to instantiate a clock domain, wouldn't you?

whitequark avatar Apr 22 '20 11:04 whitequark

If the AXI clock is the same as your system/reference clock then I don't see why you would?

hofstee avatar Apr 22 '20 11:04 hofstee

The reset is synchronous unless you explicitly configure it async. Maybe I'm missing some part of your plan here; could you illustrate what you mean with some code?

whitequark avatar Apr 22 '20 11:04 whitequark

For example, a Zynq exposes AXI ports as one of the main means of communicating between the processing system and the programmable logic. Those might actually be synchronous resets but I don't recall. In either case, they're active-low.

So if you're taking the clock from the processing system to use as your clock in the programmable logic, then you're on the same clock domain as the AXI port you would be communicating on, so everything there is just on a single clock domain.

hofstee avatar Apr 22 '20 12:04 hofstee

Yeah, I understand that. My question is on a much more practical level. If you make a single-clock AXI component in nMigen that creates its own clock domain, then it would be, in general, not reusable in nMigen code (at least nMigen code that follows the conventions) since such components shouldn't have their own clock domains but refer, through late binding, to existing sync domain in the design. On the other hand, if you want to get Verilog for that component with the domain configured for asynchronous reset, you do need to create a clock domain for it explicitly. Another relevant aspect is that nMigen's definitions of buses do not, in general, follow Verilog conventions for the signal names, so you'd have to rename the signals there as well.

This, as far as I can tell, implies that a wrapper is necessary anyway. (Such a wrapper doesn't have to be verbose or laborous--it could be a simple invocation of a Python function provided by the same library that contains the AXI bus definitions.) And if you have a wrapper, you might as well invert the reset polarity there.

whitequark avatar Apr 22 '20 12:04 whitequark

@hofstee Not really about nMigen, but in the Zynq you have a reset synchronizer that provides both high and low resets in it's outputs. From there, you can have cores with both low and high synchronic resets. Also if you are thinking about using the "Automation" provided by Vivado, you'll have to explicitly configure the reset port of the nmigen-generated core as "active high" beforehand (in the block design) and it'll do everything for you correctly (for some reason it assumes a low reset).

akukulanski avatar May 07 '20 21:05 akukulanski

where do i start if i were to implement active-low reset?

github-4o avatar Jan 27 '21 12:01 github-4o

https://github.com/nmigen/nmigen/blob/818c8bc46485ada0f31ad8ec23182ad01a6c7da1/nmigen/back/rtlil.py#L994 looks promissing. fixing this for negedge produces

sync negedge \rst
      update \v \v$next

in rtlil (look ok so far, is it a valid active-low reset in rtlil?). and verilog:

always @(posedge clk, posedge \$auto$proc_dff.cc:153:gen_dffsr$3 [0], posedge \$auto$proc_dff.cc:154:gen_dffsr$4 [0])
    if (\$auto$proc_dff.cc:154:gen_dffsr$4 [0]) v[0] <= 1'b0;
    else if (\$auto$proc_dff.cc:153:gen_dffsr$3 [0]) v[0] <= 1'b1;
    else v[0] <= \v$next [0];

for every bit of the signal being reset, which is not really an active low reset. i tested it with https://github.com/nmigen/nmigen/blob/master/examples/basic/arst.py example

so is it actually yosys who is unable to generate active low reset from valid rtl, or rtlil should look different?

github-4o avatar Jan 27 '21 14:01 github-4o

can't find explicit confirmation that rtlil supports negedge SyncRules, but yosys source annotation says negedge is a valid type for SyncRule: http://eddiehung.github.io/yosys/d3/dc3/namespaceRTLIL.html#a79713e13c00e4e216c60fb297be1900f update: quick tests show that sync negedge \rst is a valid rtlil SyncRule

github-4o avatar Jan 27 '21 16:01 github-4o

It's not clear what the design for active-low resets should be, so you should write an RFC we can discuss before any code changes will be considered at all.

whitequark avatar Jan 27 '21 18:01 whitequark