It seems that the existing dff optimizations don’t detect when ALOAD and AD inputs are driven from the same or complementary signals. This prevents synthesis of designs that contain dffs with parametrized asynchronous reset logic:
read_verilog aldffs.v
proc
hierarchy -check -top top
synth_ice40 -device lp -top top -json top.json
...
4.34. Executing DFFLEGALIZE pass (convert FFs to types supported by the target).
ERROR: FF top.$auto$ff.cc:337:slice$930 (type $_ALDFFE_PNP_) cannot be legalized: dffs with async set and reset are not supported
module aload_gdff(...);
parameter INIT_SOURCE = 1'b1;
parameter INIT_STATE = 1'b1;
parameter ASYNC_SOURCE = 1'b1;
parameter POLARITY = 1'b1;
input CLK;
input CE;
input PT1;
input PT2;
input PT3;
input DIN;
input SET;
input RES;
output wire Q;
wire shared_init;
assign shared_init = INIT_SOURCE == 1'b1 ? PT1 : PT3;
wire por_init;
assign por_init = 1'b0 ^ shared_init;
wire async_init;
assign async_init = ASYNC_SOURCE == 1'b0 ? PT2 : ~ POLARITY;
wire preset;
assign preset = INIT_STATE == 1'b0 ? por_init : async_init;
wire reset;
assign reset = INIT_STATE == 1'b1 ? por_init : async_init;
wire aload;
assign aload = (preset == POLARITY) || (reset == POLARITY);
wire ad;
assign ad = preset == POLARITY;
always @(posedge CLK, posedge aload) begin
if (aload)
Q <= ad;
else if (CE == 1'b1)
Q <= DIN;
end
endmodule // aload_gdff
module top(...);
input CLK;
input CE;
input PT1;
input PT2;
input PT3;
input [3:0] DIN;
output [3:0] Q;
aload_gdff
#(.INIT_SOURCE(1'b1), .INIT_STATE(1'b0), .ASYNC_SOURCE(1'b1), .POLARITY(1'b1))
set_1_dff
(.CLK(CLK), .CE(CE), .PT1(PT1), .PT2(PT2), .PT3(PT3), .DIN(DIN[0]), .Q(Q[0]));
aload_gdff
#(.INIT_SOURCE(1'b1), .INIT_STATE(1'b1), .ASYNC_SOURCE(1'b1), .POLARITY(1'b1))
res_1_dff
(.CLK(CLK), .CE(CE), .PT1(PT1), .PT2(PT2), .PT3(PT3), .DIN(DIN[1]), .Q(Q[1]));
aload_gdff
#(.INIT_SOURCE(1'b1), .INIT_STATE(1'b0), .ASYNC_SOURCE(1'b1), .POLARITY(1'b0))
set_0_dff
(.CLK(CLK), .CE(CE), .PT1(PT1), .PT2(PT2), .PT3(PT3), .DIN(DIN[2]), .Q(Q[2]));
aload_gdff
#(.INIT_SOURCE(1'b1), .INIT_STATE(1'b1), .ASYNC_SOURCE(1'b1), .POLARITY(1'b0))
res_0_dff
(.CLK(CLK), .CE(CE), .PT1(PT1), .PT2(PT2), .PT3(PT3), .DIN(DIN[3]), .Q(Q[3]));
endmodule // top
This is the situation after opt (ALOAD polarity is 1’b1 on both):
- $440 has
PT1connected to both ALOAD and AD - equivalent to AD = 1’b1 - $441 has inverted
PT1connected to AD - equivalent to AD = 1’b0
To get my current project through synthesis, I added functionality to opt_dff that detects situations where AD is the same or complement of ALOAD and replaces the input to AD with the respective constant. The existing opt_dff code then kicks in and replaces the $aldffe with a $adffe.
My changes are at opt_dff: Change AD to const if it’s identical or complementary to ALOAD and work good enough for me.
I could raise a PR if this is interesting for upstream.
