0

I have been toying with SpinalHDL and its SoCs and modules, but came to a general problem - almost none of the code that uses FSMs works. I nailed this issue down to Yosys, which does something weird when it detects a FSM. Here below is a simple and straightforward Verilog (generated by SpinalHDL) that does NOT work as expected unless you pepend FSM state register "state" with ( fsm_encoding = "none" ) attribute. Doing so makes it working well, but that is definitely not a solution because you cannot modify tonns of existing Verilog, neither I could find a way to make SpinalHDL do this. I discussed this issue on SpinalHDL gitter already, the guys there advised to file a bug report on Yosys which I think is not the case, I think I'm missing some option.

I'm using the latest Yosys from github:

Yosys 0.9+3667 (git sha1 e7f36d01, gcc 7.3.0-27ubuntu1~18.04 -fPIC -Os)

Verilog that does not work:

// Generator : SpinalHDL v1.4.2    git head : 804c7bd7b7feaddcc1d25ecef6c208fd5f776f79
// Component : MyTopLevel



module MyTopLevel (
  input               io_but0,
  input               io_but1,
  output     [1:0]    io_leds,
  input               clk,
  input               reset
);
  reg        [31:0]   counter;
  //(* fsm_encoding = "none" *) reg        [1:0]    state;
  reg        [1:0]    state;
  reg        [1:0]    leds;

  assign io_leds = leds;
  always @ (posedge clk) begin
    if(reset) begin
      counter <= 32'h0;
      state <= 2'b00;
      leds <= 2'b00;
    end else begin
      counter <= (counter + 32'h00000001);
      if((state == 2'b00))begin
        if(((io_but0 == 1'b0) && (io_but1 == 1'b0)))begin
          state <= 2'b10;
          leds[0] <= 1'b1;
          leds[1] <= 1'b1;
        end
      end else begin
        if((state == 2'b01))begin
          if(((io_but0 == 1'b1) && (io_but1 == 1'b1)))begin
            state <= 2'b00;
            leds[0] <= 1'b0;
            leds[1] <= 1'b0;
          end
        end else begin
          if(((io_but0 == 1'b0) && (io_but1 == 1'b1)))begin
            state <= 2'b01;
            leds[0] <= 1'b1;
            leds[1] <= 1'b0;
          end
          if(((io_but0 == 1'b1) && (io_but1 == 1'b0)))begin
            state <= 2'b01;
            leds[0] <= 1'b0;
            leds[1] <= 1'b1;
          end
        end
      end
    end
  end


endmodule

I'm using the following command to invoke Yosys from my Makefile:

yosys -v2 -p "synth_ice40 -top MyTopLevel -json MyTopLevel.json" MyTopLevel.v
dave_59
  • 39,096
  • 3
  • 24
  • 63
  • Please can you describe the behaviour you are seeing in a bit more detail? – gatecat Nov 29 '20 at 19:51
  • Hello David. Basically, what I expect to see is when I press two buttons (active low) at once two LEDs go up, but this is not happening. Instead (without **fsm_encoding** attribute) I register some random behaviour of LEDs, they go up and down without any buttons pressed. I looked into output of **prep** Verilog and could see that my "state" register was converted into one-hot 32 bit reg by yosys, which I did not ask it for, and seems never used further. – pointcheck Nov 29 '20 at 22:15
  • @pointcheck Please edit the question then. "It does not work" is never sufficient to understand what is the problem. – Petr Gladkikh Dec 16 '20 at 22:21

1 Answers1

0

Well, I have found the root of the problem, but cannot find a decent solution.

Yosys indeed does FSM recoding (with synth_ice40 command) without any permission to do so, it converts FSM state register into one-hot which is zero initialized during boot (FPGA configuration) and so we get to invalid FSM state on power-on. There are three solutions here, as it seems to me: 1) do not rely on FPGA reset, implement my own hard reset instead, 2) prepend each FSM state register with fsm_encoding none attribute, 3) assign initial state reg value in Verilog - after this yosys stops doing its nasty FSM tricks. Unfortunately none of these are good for me. I do really want to rely on FPGA reset and I do not want to modify someone else's code (SpinalHDL framework) just to please yosys. According to yosys manual one can disable FSM recoding with fsm -recode option, but that does not work when you use a synth_ command - it appeared to be a hard-coded script that overrides whatever you give it on the command line. Can this be considered as a bug in yosys ? I think so!

  • Ultimately, this is not a bug imo because without an explicit initial statement the state register starts off undefined - in a simulation it would start off as 'x' and the FSM wouldn't work either. The best solution is to add an initial statement if you want a register to start in a known state without a reset. – gatecat Nov 30 '20 at 08:38
  • There is some discussion about the same problem, and an already open ticket to discuss alternative behaviour, here: https://github.com/YosysHQ/yosys/issues/188 – gatecat Nov 30 '20 at 08:41
  • David, thanks for your comments and the link. I completely support **azonenberg**'s point, stating that selecting a random state initial value is a bug, esp selecting zero for one-hot. To solve that, what Clifford did is he just "increased verbosity", what a joke! – pointcheck Nov 30 '20 at 22:04
  • I still cannot find a way for **fsm -recode** to work. Basically I want yosys to stop messing with my FSM state regs. – pointcheck Nov 30 '20 at 22:07