1

I am currently working on a project in Verilog HDL with an FPGA obtained from my school (I am running Quartus II vers. 10.1 and 11.0 (I've tried both)). I am getting a very bizarre bug that I cannot figure out for the life of me.

I am developing a Morse Code program which detects dots and dashes, and then outputs the appropriate letter on a HEX display based upon this input. The HEX display works beautifully, but my UserInput module doesn't seem to do anything at all!

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

The input for the module is a KEY on the FPGA. The FSM represented by the UserInput module has the key be in the "UP" state at t=0. Then, if there is input, it will move through SHORT0 or SHORT1, and finally LONG. If it the key is released at any of these states, they go to their appropriate intermediary UP states and provide an output of "DOT" or "DASH".

However, when I connect this to my FPGA, I get nothing. From my testing, it seems that it never moves away from the "UP" state. Even my simulations give me nothing. Secondly, I've tried connecting a different UserInput module from a different project (one I know works), and still nothing. Is there something going on in the background of Verilog I am missing?

Here is an image of the simulation waveform:Simulation Waveform

DFf 0, 1, and 2 are the bits 0, 1, and 2 of PS. My simulation won't allow a showing of the NS.

cjspook
  • 89
  • 2
  • 9
  • 1
    When you say it's not working in simulation, are you saying you're applying the proper reset, clock, and *in* stimulus, and yet the DFFs never change? Can you put up the testbench code? – Tim May 29 '12 at 19:26
  • Yes, that is correct. Unfortunately, I do not know how to write testbench code. I was taught to use the Altera University Program Simulator, which provides a more graphical approach. However, when I do simulate with the Altera UP Simulator, and provide the proper reset, clock, and in stimulus, the DFFs do not change. – cjspook May 30 '12 at 00:36
  • Hmm without more information I'm not sure what to say. I think that what you have there should work, provided that you haven't got the reset polarity mixed up or something. If you're debugging waves, maybe you could put up a screenshot of the waves showing relevant signals (reset, clk, NS, PS, in) at the time when it's not working? – Tim May 30 '12 at 00:54
  • I added an image of the simulation. I don't know if this helps, but I'm getting a critical warning "Timing Requirements not met." Could that be the culprit? And if so, how would I fix that? Also, thank you for taking the time to help me. I really appreciate it. – cjspook May 30 '12 at 04:18
  • Are you simulating a back-annotated netlist? If timing fails then your simulation won't be useful. –  May 30 '12 at 04:49
  • Something is definitely wrong there, your dff1/q is asserting while the reset is high, which makes no sense. Is that the full extent of the warning that you got? Does it mention any specific path which is not meeting timing? Try reducing the clock frequency, maybe that will help. – Tim May 30 '12 at 05:08
  • Adam12 - I'm not sure what a back-annotated netlist is, but I've noticed similar things happening occasionally with a implementation into an FPGA. – cjspook May 30 '12 at 05:26
  • Tim - lowering the clock frequency in the simulation removes the dff1/q assertion, but doesn't fix the other problems I'm having. – cjspook May 30 '12 at 05:29
  • Does lowering the clock frequency cause the timing requirements to be met? Also, I don't understand why your simulation wouldn't allow showing the `NS` signals... maybe you could you use them to drive a new (temporary debug) output port? – FriendFX Jun 05 '12 at 06:59
  • Toolchains often try to identify state machines and re-implement them with one-hot encoding, in which case the NS vector in the source code would not be available in it's original form. Driving signals you want to see onto outputs is the no-reading-up-on-directives way to make sure they are retained, and in desired form. – Chris Stratton Jun 08 '12 at 12:26

1 Answers1

2

Your code looks bad to me (which I guess you want to hear as your code doesn't work). It looks like a combination of timing problems and a design flaw.

Let's walk through your waveform view and see if we can't work out what's going on.

signal in goes high, which triggers an always block. PS is 0 so we set NS to 1. This is not in time for the rising clock edge so it's not triggered in the DFF (as you'd have suspected), never mind it'll be caught on the next clock edge.

signal in goes low, which triggers an always block, PS is 0 so we set NS to 0. This happens in time for the rising clock edge and is captured in the DFF (argh we missed the NS signal going to 1 as we wanted).

Also, someone mentioned that there's an error with your flip-flop being asserted while reset is asserted. This isn't a problem: the reset is synchronous. So on the next rising clock edge the DFF is reset to 0.

So, what's the solution (looks like homework to me, so hopefully you've fixed this already!):

It should look something like this (I haven't simulated it, so no guarantees):

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;

So what's going on here: I think this should be fairly obvious. When the in signal moves from high to low then we want to output the current state (LONG as a DASH, SHORT1 and SHORT2 as a DOT), otherwise we output IDLE. If the in signal is high then we want to move the state along depending on how long it's been high for.

There's an error with this code which won't effect simulation, but which will almost certainly effect you on the FPGA: if you are getting input from an external source then you'll need to buffer it through a (series?) of flip-flops to prevent metastability problems. This can be fixed by adding a series of D flip-flops to capture the in signal and then passing this "cleaned" buffered_in to the 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
dave
  • 4,812
  • 4
  • 25
  • 38