diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc index 9cffbf95a..5f491a16c 100644 --- a/passes/fsm/fsm_detect.cc +++ b/passes/fsm/fsm_detect.cc @@ -199,8 +199,15 @@ static void detect_fsm(RTLIL::Wire *wire, bool ignore_self_reset=false) } SigSpec sig_y = sig_d, sig_undef; - if (!ignore_self_reset && ce.eval(sig_y, sig_undef)) - is_self_resetting = true; + if (!ignore_self_reset) { + if (cellport.first->type == ID($adff)) { + SigSpec sig_arst = assign_map(cellport.first->getPort(ID::ARST)); + if (ce.eval(sig_arst, sig_undef)) + is_self_resetting = true; + } + else if (ce.eval(sig_y, sig_undef)) + is_self_resetting = true; + } } if (has_fsm_encoding_attr) diff --git a/tests/various/fsm-arst.ys b/tests/various/fsm-arst.ys new file mode 100644 index 000000000..2cfca1d57 --- /dev/null +++ b/tests/various/fsm-arst.ys @@ -0,0 +1,133 @@ +read_verilog << EOT +module non_self_rs_fsm ( + input wire clk, + input wire reset, + output wire s1 +); + localparam [7:0] RST = 8'b10010010; + localparam [7:0] S1 = 8'b01001000; + localparam [7:0] S2 = 8'b11000111; + + reg [7:0] current_state, next_state; + always @(posedge clk or posedge reset) begin + if (reset) begin + current_state <= RST; + end else begin + current_state <= next_state; + end + end + + always @(*) begin + next_state = current_state; + + case (current_state) + RST: next_state = S1; + S1: next_state = S2; + S2: next_state = S1; + default: next_state = RST; + endcase + end + + assign s1 = next_state == S1; +endmodule + +module semi_self_rs_fsm ( + input wire clk, + inout wire reset, + input wire test, + output wire s1 +); + localparam [7:0] RST = 8'b10010010; + localparam [7:0] S1 = 8'b01001000; + localparam [7:0] S2 = 8'b11000111; + + reg [7:0] current_state, next_state; + reg [1:0] reset_test; + + assign reset = (test || (reset_test == 2)); + + always @(posedge clk or posedge reset) begin + if (reset) begin + current_state <= RST; + reset_test <= 0; + end else begin + current_state <= next_state; + if (current_state == S2) + reset_test = reset_test + 1; + end + end + + + always @(*) begin + next_state = current_state; + + case (current_state) + RST: next_state = S1; + S2: next_state = S1; + S1: next_state = S2; + + default: next_state = RST; + endcase + end + + assign s1 = next_state == S1; +endmodule + +module self_rs_fsm ( + input wire clk, + inout wire reset, + output wire s1 +); + localparam [7:0] RST = 8'b10010010; + localparam [7:0] S1 = 8'b01001000; + localparam [7:0] S2 = 8'b11000111; + + reg [7:0] current_state, next_state; + reg reset_reg; + + wire reset = (reset_reg || next_state == S1); + always @(posedge clk or posedge reset) begin + if (reset) begin + current_state <= RST; + reset_reg = 0; + end else begin + current_state <= next_state; + end + end + + always @(*) begin + next_state = current_state; + + case (current_state) + RST: next_state = S1; + S1: next_state = S2; + S2: next_state = S1; + default: begin + reset_reg = 1; + next_state = RST; + end + endcase + end + + assign s1 = next_state == S1; +endmodule + +EOT + +proc +opt_expr +opt_clean +check +opt -nodffe -nosdff + +fsm_detect +fsm_extract + +cd non_self_rs_fsm +select -assert-count 1 t:$fsm + +cd semi_self_rs_fsm +select -assert-count 1 t:$fsm + +cd self_rs_fsm +select -assert-none t:$fsm