Преобразование схемы конечного автомата в код Verilog

Мне нужно преобразовать следующую диаграмму конечных состояний в код Verilog. введите здесь описание изображения

Я включил код, который написал ниже. Мне кажется, что я правильно реализовал всю логику, и код работает для первых нескольких входных комбинаций. Однако в конце концов это терпит неудачу, и я не могу понять, почему.

module FiniteStateMachine(output reg out_z, input in_x, in_y, clk, reset_b);

    parameter   S0 = 2'b00, S1 = 2'b01, S2 = 2'b10, S3 = 2'b11;
    reg         state;

    always @(posedge clk, negedge reset_b) begin

        // set state
        if (reset_b || !in_x) state <= S0;
        else
            case (state)
                S0: state <= (in_y == 1) ? S1 : S3;
                S1: state <= S2;
                S2: state <= S3;
                S3: state <= S3;
            endcase

        // set output
        out_z <= (state == S2 || state == S3) ? 1 : 0;

    end

endmodule

person Conor McCauley    schedule 21.03.2018    source источник
comment
Объясните, что вы имеете в виду под «работает» и «не работает».   -  person dave_59    schedule 22.03.2018
comment
и какой сигнал должен переключать состояния? case (state) неверно. я думаю, вы хотели использовать что-то вроде case ({in_x,in_y}) вместо этого. Также я бы предложил использовать разные имена для состояний и условий.   -  person Serge    schedule 22.03.2018
comment
@ dave_59 тестовый стенд, написанный для его проверки, регистрирует неверный вывод.   -  person Conor McCauley    schedule 22.03.2018
comment
@Serge, состояние должно изменяться по переднему фронту часов или сбрасываться в состояние 0 по заднему фронту сброса.   -  person Conor McCauley    schedule 22.03.2018


Ответы (2)


На самом деле есть ряд проблем с вашей реализацией, как сейчас:

  1. Ваша переменная state имеет ширину всего в один бит, когда она должна быть двухбитной: reg state -> reg [1:0] state
  2. Вполне вероятно, что вы на самом деле не хотите, чтобы out_z был регистром, поскольку он должен следовать за состоянием на том же такте, а не на тактовый цикл позже.
  3. Ваша логика reset_b обратная, для сброса negege вам нужно проверить утверждение через !reset_b или ~reset_b.
  4. Как уже упоминалось, вам действительно не следует комбинировать асинхронный сброс с каким-либо синхронным вводом, даже с синхронным сбросом, как вы сделали с reset_b и in_x. Хотя это будет хорошо работать в моделировании, большинство инструментов синтеза, вероятно, не смогут правильно с этим справиться. Изучая Verilog, я совершил ту же ошибку, и мне потребовались дни, чтобы обнаружить и исправить ее.

Вот более чистая версия вашего кода с этими исправлениями, реализованными и прокомментированными, чтобы вы могли видеть эти 4 точки:

module FiniteStateMachine(output reg out_z, input in_x, in_y, clk, reset_b);

  parameter S0 = 2'b00, S1 = 2'b01, S2 = 2'b10, S3 = 2'b11;
  reg [1:0] state; // Fix state variable

  // Set output combinationally (no need for turning operator)
  always @(*) begin
    out_z = (state == S2 || state == S3);
  end

  always @(posedge clk, negedge reset_b) begin
    // Invert the logic for reset and keep it separate
    if (!reset_b) begin
      state <= S0;
    end
    else begin
      // You can case on inputs as was suggested, but I think casing on state is fine
      // I include only logic for changing state
      case (state)
        S0: begin
          if (in_x && in_y) begin
            state <= S1;
          end
          else if (in_x && !in_y) begin
            state <= S3;
          end
        end
        S1: begin
          if (in_x) begin
            state <= S2;
          end
          else begin
            state <= S0;
          end
        end
        S2:  begin
          if (in_x) begin
            state <= S3;
          end
          else begin
            state <= S0;
          end
        end
        S3: begin
          if (!in_x) begin
            state <= S0;
          end
        end
      endcase
    end
  end

endmodule
person Unn    schedule 21.03.2018

Похоже, вы пытались упростить FSM, рассматривая in_x как вторичный сброс. Я не думаю, что это упрощение правильно, и в любом случае вы пытаетесь быть слишком умным. Просто запишите все переходы для каждого случая либо в виде вложенного оператора case, либо в виде серии if под каждым состоянием. Например:

case (state)
  S0: case ({in_x, in_y})
    2'b00: state <= S0;
    2'b01: state <= S0;
    2'b10: state <= S3;
    2'b11: state <= S1;
  endcase
  S2: case ({in_x, in_y})
    …
person Community    schedule 21.03.2018
comment
Я реализовал эту логику и снова протестировал код, но проблема с моим кодом, похоже, связана со значением, которое установлено для out_z. - person Conor McCauley; 22.03.2018