1

我目前正在使用从我学校获得的 FPGA 进行 Verilog HDL 项目(我正在运行 Quartus II 版本 10.1 和 11.0(我都尝试过))。我遇到了一个非常奇怪的错误,我一生都无法弄清楚。

我正在开发一个摩尔斯电码程序,它检测点和破折号,然后根据这个输入在十六进制显示器上输出适当的字母。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

模块的输入是 FPGA 上的一个 KEY。由 UserInput 模块表示的 FSM 在 t=0 时键处于“UP”状态。然后,如果有输入,它会经过 SHORT0 或 SHORT1,最后是 LONG。如果密钥在这些状态中的任何一个被释放,它们将进入其适当的中间 UP 状态并提供“DOT”或“DASH”的输出。

但是,当我将它连接到我的 FPGA 时,我什么也得不到。从我的测试来看,它似乎永远不会离开“UP”状态。甚至我的模拟也没有给我任何东西。其次,我尝试从不同的项目(我知道一个有效的)连接不同的 UserInput 模块,但仍然没有。我错过了 Verilog 的背景是否发生了什么?

这是仿真波形的图像:模拟波形

DFf 0、1 和 2 是 PS 的位 0、1 和 2。我的模拟不允许显示 NS。

4

1 回答 1

2

你的代码对我来说看起来很糟糕(我猜你想听到你的代码不起作用)。它看起来像是时序问题和设计缺陷的结合。

让我们浏览一下您的波形视图,看看我们是否无法弄清楚发生了什么。

信号输入变高,这会触发始终阻塞。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;

那么这里发生了什么:我认为这应该是相当明显的。当 in 信号从高电平变为低电平时,我们要输出当前状态(LONG 作为 DASH,SHORT1 和 SHORT2 作为 DOT),否则我们输出 IDLE。如果输入信号为高电平,那么我们希望根据它处于高电平的时间来移动状态。

这段代码有一个错误,它不会影响仿真,但几乎肯定会影响你对 FPGA 的影响:如果你从外部源获取输入,那么你需要通过一个(系列?)翻转缓冲它触发器以防止亚稳态问题。这可以通过添加一系列 D 触发器来捕获 in 信号,然后将这个“清理过的”buffered_in 传递给 UserInput 来解决。

IE:

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
于 2012-06-29T06:48:48.043 回答