Verilog HDL, пользовательский ввод с FPGA

В настоящее время я работаю над проектом в Verilog HDL с ПЛИС, полученной из моей школы (я использую Quartus II версий 10.1 и 11.0 (я пробовал оба)). Я получаю очень странную ошибку, которую я не могу понять за свою жизнь.

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

module UserInput(Clock, reset, in, out);
input Clock, reset, in;
output reg [1:0] out;

wire [2:0] PS;
reg [2:0] NS;

parameter NONE = 2'b00, DOT = 2'b01, DASH = 2'b11; //For Output
parameter UP = 3'b000, SHORT0 = 3'b001, SHORT1 = 3'b010, UP_DOT = 3'b011, LONG = 3'b100, UP_DASH = 3'b101;

//Active High
always@(PS or in)
    case (PS)
        UP: if (in)         NS = SHORT0;
             else               NS = UP;

        SHORT0: if (in) NS = SHORT1;
                 else           NS = UP_DOT;

        SHORT1: if (in) NS = LONG;
                 else           NS = UP_DOT;

        UP_DOT:                 NS = UP;

        LONG:   if (in)     NS = LONG;
                else            NS = UP_DASH;

        UP_DASH:            NS = UP;
    default: NS = 3'bxxx;
    endcase

always@(PS)
    case (PS)
        UP:     out = NONE;
        SHORT0: out = NONE;
        SHORT1: out = NONE;
        UP_DOT: out = DOT;
        LONG:   out = NONE;
        UP_DASH: out = DASH;
        default: out = 2'bxx;
    endcase

D_FF dff0 (PS[0], NS[0], reset, Clock);
D_FF dff1 (PS[1], NS[1], reset, Clock);
D_FF dff2 (PS[2], NS[2], reset, Clock);

endmodule

module D_FF (q, d, reset, clk);
    input d, reset, clk;
    output reg q;

    always@(posedge clk or posedge reset)
    begin
        if (reset) q = 0;
        else       q = d;
    end
endmodule

Вход для модуля - КЛЮЧ на ПЛИС. FSM, представленный модулем UserInput, имеет ключ в состоянии "UP" при t=0. Затем, если есть ввод, он будет перемещаться через SHORT0 или SHORT1 и, наконец, LONG. Если ключ выпущен в любом из этих состояний, они переходят в соответствующие промежуточные состояния UP и выдают "DOT" или "DASH".

Однако, когда я подключаю это к своей FPGA, я ничего не получаю. Из моего тестирования кажется, что он никогда не уходит из состояния "ВВЕРХ". Даже мои симуляции ничего не дают. Во-вторых, я попытался подключить другой модуль UserInput из другого проекта (который, я знаю, работает), но все еще ничего. Что-то происходит на фоне Verilog, которого мне не хватает?

Вот изображение формы волны моделирования:Форма волны моделирования

DFf 0, 1 и 2 - это биты 0, 1 и 2 PS. Моя симуляция не позволяет показывать NS.

1 ответ

Ваш код выглядит плохо для меня (что, я думаю, вы хотите услышать, так как ваш код не работает). Это выглядит как сочетание проблем с выбором времени и недостатком дизайна.

Давайте пройдемся по вашему представлению формы волны и посмотрим, сможем ли мы понять, что происходит.

высокий уровень сигнала, который вызывает блокировку всегда. PS равен 0, поэтому мы устанавливаем NS в 1. Это не вовремя для нарастающего фронта тактового сигнала, поэтому он не срабатывает в DFF (как вы могли бы предположить), не говоря уже о том, что он будет зафиксирован на следующем фронте тактового сигнала.

Сигнал на входе становится низким, что вызывает блокировку всегда, PS равен 0, поэтому мы устанавливаем NS на 0. Это происходит во времени для нарастающего фронта тактового сигнала и фиксируется в DFF (хотя мы пропустили сигнал NS, идущий к 1, как мы хотели),

Кроме того, кто-то упомянул, что произошла ошибка с утверждением вашего триггера во время сброса. Это не проблема: сброс происходит синхронно. Таким образом, на следующем фронте тактового сигнала DFF сбрасывается на 0.

Итак, каково решение (для меня это выглядит как домашнее задание, так что, надеюсь, вы уже исправили это!):

Это должно выглядеть примерно так (я не имитировал, так что никаких гарантий):

Module UserInput (clk, reset, in, out);
input clk, reset, in;
output [1:0] out;

// output parameters
parameter IDLE = 2'b00;
parameter DOT = 2'b01;
parameter DASH = 2'b10;

// FSM states
parameter LOW = 3'b000;
parameter SHORT1 = 3'b001;
parameter SHORT2 = 3'b010;
parameter LONG = 3'b100;

reg [2:0] state;
wire [1:0] next_out;
wire [2:0] next_state;

always @(posedge clk)
begin
    if (reset)
    begin
        out <= IDLE;
        state <= LOW;
    end;
    else
    begin
        out <= next_out;
        state <= next_state;
    end
    end if;
end

always @(*)
begin
    case (state)
    LOW:
        next_out = IDLE;
        next_state = (in? SHORT1 : LOW);
    SHORT1:
    begin
        next_state = (in? SHORT2: LOW);
        next_out = (in? IDLE : DOT);
    end;
    SHORT2:
        next_state = (in? LONG: LOW);
        next_out = (in? IDLE : DOT);
   LONG:
        next_state = (in? LONG : LOW);
        next_out = (in? IDLE : DASH);
   default:
        // we shouldn't get here!!
        next_state = LOW;
        next_out = IDLE;
   end;
   end module;

Итак, что здесь происходит: я думаю, что это должно быть довольно очевидно. Когда входной сигнал перемещается от высокого к низкому уровню, мы хотим вывести текущее состояние (LONG как DASH, SHORT1 и SHORT2 как DOT), в противном случае мы выводим IDLE. Если входной сигнал высокий, то мы хотим переместить состояние в зависимости от того, как долго оно было высоким.

В этом коде есть ошибка, которая не повлияет на симуляцию, но почти наверняка повлияет на вас на ПЛИС: если вы получаете входные данные из внешнего источника, вам нужно будет буферизовать их через (серию?) провалы для предотвращения проблем с метастабильностью. Это можно исправить, добавив серию D-триггеров для захвата входного сигнала, а затем передав этот "очищенный" buffered_in в UserInput.

то есть:

module in_buffer (clk, reset, in, out);
input clk, reset, in;
output out;

reg buf1, buf2;

always @ (posedge clk)
begin
    if (reset)
    begin
        out <= 0;
        buf1 <= 0;
        buf2 <= 0;
    end
    else
        out <= buf2;
        buf2 <= buf1;
        buf1 <= in;
    end
end
Другие вопросы по тегам