Electronic – Design simulates perfectly but won’t work on FPGA

digital-logicfpgaverilog

First, thanks for the help yesterday. This time I will document my code correctly.

So, we were tasked with creating a parking meter that would take 4 inputs, one adding 50 seconds, one adding 150 seconds, one adding 250 seconds, and one adding 500 seconds. When there are over 10 seconds remaining, a green led should flash with a period of 2 seconds. When there are less than 10 seconds a red led should flash with period 2 seconds, and when there are no seconds left a red led should flash with period 1 second. Every clock cycle with no input is supposed to subtract one from the meter.

We were tasked with using a debouncer as well a single pulse state machine for the inputs, and a 7 segment display for the outputs. So, I used a state machine for my addition and led flashing, then sent the counter to a binarytoBCD converter and then that one to a BCD to 7 segment display. I'm wondering if I messed up the clock and somehow the simulation ignores my errors, somehow making the FPGA unable to correcly use my code?

without further ado, here are my code snippets:

Top Module

module parkingmeter(clk,rst,b0,b1,b2,b3,out0,out1,out2,out3,GRNLED,REDLED);
    input b0,b1,b2,b3,clk,rst;
    output [6:0] out0,out1,out2,out3;
    output GRNLED,REDLED;
    wire outt0,outt1,outt2,outt3;
    wire [15:0] counter;
    wire [3:0] bcd0,bcd1,bcd2,bcd3;
    wire clkout;
    clockdivider onesec(clk,clkout);
    add_sub yep(b0,clkout,rst,outt0);
    add_sub yesh(b1,clkout,rst,outt1);
    add_sub yeah(b2,clkout,rst,outt2);
    add_sub ok(b3,clk,rst,outt3);
    controlparker Second(outt0,outt1,outt2,outt3,clkout,rst,counter,REDLED,GRNLED);
    EC Third(counter,bcd0,bcd1,bcd2,bcd3,out0,out1,out2,out3);
endmodule

my debounce module

module cleandebounce(clk,rst,I0,out);
    input clk,rst,I0;
    output out;
    reg f0,f1;
    always @ (posedge clk, posedge rst) begin
       if (rst==1) begin
            f0 <= I0;
            f1 <= f0;
        end else begin
            f0 <= 0;
            f1 <= 0;
       end
    end
    assign out = f1;
endmodule

My single pulse state machine

module add_sub(in,clk,rst,out);
    input in,clk,rst;
    output reg out = 1'b0;
    reg state = 1'b0;
    wire outt;
    cleandebounce one(clk,rst,in,outt);
    always @ (posedge clk,posedge rst) begin
        case(state)
            1'b0: begin
                if (rst==1) begin
                    out <= 0;
                    if (outt == 1) begin
                        out <= 1'b1;
                        state <= 1'b1;
                    end else state <= 1'b0;
                end else begin
                    out <= 1'b0;
                    state <= 1'b0;
                end
            end
            1'b1: begin
                out <= 1'b0;
                if (outt == 1) begin
                    out <= 1'b0;
                    state <= 1'b1;
                end else state <= 1'b0;
            end
        endcase
    end
endmodule

And my module for adding the inputs as well as flashing on and off leds

module controlparker(B0,B1,B2,B3,clk,rst,counter,REDLED,GRNLED);
    input B0,B1,B2,B3,clk,rst;
    output reg [15:0] counter = 16'b0000000000000000;
    reg state = 1'b0;
    reg [2:0] area = 3'b000;
    output reg REDLED = 0;
    output reg GRNLED = 0;
    always @ (posedge clk, posedge rst) begin
        case(state)
            0: begin
                if (rst==1) begin
                    if (counter > 0)
                        counter <= counter - 1;
                    if (counter > 9999)begin
                        counter <= 9999;
                    end
                    state <= 1;
                end else begin
                    counter <= 0;
                    state <= 0;
                end
            end
            1: begin
                if (B0 == 1) begin
                    counter <= counter + 16'b00000000000110010;
                    state <= 0;
                end else if (B1 == 1) begin
                    counter <= counter + 16'b00000000010010110;
                    state <= 0;
                end else if (B2 == 1) begin
                    counter <= counter + 16'b00000000011111010;
                    state <= 0;
                end else if (B3 == 1) begin
                    counter <= counter + 16'b00000000111110010;
                    state <= 0;
                end else state <= 0;
            end
        endcase
    end        
    always @ (posedge clk, posedge rst) begin
        case(area)
            3'b000: begin
                if (rst==1)begin
                    if (counter >= 10)begin
                        GRNLED <= 1;
                        REDLED <= 0;
                        area <= 3'b001;
                    end
                    else if (counter < 10 && counter > 0) begin
                        REDLED <= 1;
                        GRNLED <= 0;
                        area <= 3'b010;
                    end
                    else REDLED <= ~REDLED;
                end
                else begin
                    REDLED <= 0;
                    GRNLED <= 0;
                end
            end
            3'b001: begin
                GRNLED <= 0;
                area <= 3'b000;
            end
            3'b010: begin
                REDLED <= 0;
                area <= 3'b000;
            end
        endcase
    end
endmodule

My module converting BinarytoBCD as well as the 7 segment display output:

module EC(in,bcd0,bcd1,bcd2,bcd3,out0,out1,out2,out3);
    input [15:0] in;
    output reg [3:0] bcd0 = 4'b0000;
    output reg [3:0] bcd1 = 4'b0000;
    output reg [3:0] bcd2 = 4'b0000;
    output reg [3:0] bcd3 = 4'b0000;
    output reg [6:0] out0 = 7'b0000000;
    output reg [6:0] out1 = 7'b0000000;
    output reg [6:0] out2 = 7'b0000000;
    output reg [6:0] out3 = 7'b0000000;
    reg [15:0] temp;
    integer i;
    always @ (in) begin
        bcd0 = 4'b0000;
        bcd1 = 4'b0000;
        bcd2 = 4'b0000;
        bcd3 = 4'b0000;
        temp = in;
        for(i=15; i>=0; i=i-1) begin
            if (bcd3 >= 4'b0101)
                bcd3 = bcd3 + 4'b0011;
            if (bcd2 >= 4'b0101)
                bcd2 = bcd2 + 4'b0011;
            if (bcd1 >= 4'b0101)
                bcd1 = bcd1 + 4'b0011;
            if (bcd0 >= 4'b0101)
                bcd0 = bcd0 + 4'b0011;
            bcd3 = bcd3 << 1;
            bcd3[0] = bcd2[3];
            bcd2 = bcd2 << 1;
            bcd2[0] = bcd1[3];
            bcd1 = bcd1 << 1;
            bcd1[0] = bcd0[3];
            bcd0 = bcd0 << 1;
            bcd0[0] = temp[i];
        end
    end
    always @ (bcd0) begin
        if (bcd0==4'b0000) out0 = 7'b0000001;
        else if (bcd0==4'b0001) out0 = 7'b1001111;
        else if (bcd0==4'b0010) out0 = 7'b0010010;
        else if (bcd0==4'b0011) out0 = 7'b0000110;
        else if (bcd0==4'b0100) out0 = 7'b1001100;
        else if (bcd0==4'b0101) out0 = 7'b0100100;
        else if (bcd0==4'b0110) out0 = 7'b0100000;
        else if (bcd0==4'b0111) out0 = 7'b0001111;
        else if (bcd0==4'b1000) out0 = 7'b0000000;
        else if (bcd0==4'b1001) out0 = 7'b0000100;
        else out0=7'b0000001;
    end
    always @ (bcd1) begin
        if (bcd1==4'b0000) out1 = 7'b0000001;
        else if (bcd1==4'b0001) out1 = 7'b1001111;
        else if (bcd1==4'b0010) out1 = 7'b0010010;
        else if (bcd1==4'b0011) out1 = 7'b0000110;
        else if (bcd1==4'b0100) out1 = 7'b1001100;
        else if (bcd1==4'b0101) out1 = 7'b0100100;
        else if (bcd1==4'b0110) out1 = 7'b0100000;
        else if (bcd1==4'b0111) out1 = 7'b0001111;
        else if (bcd1==4'b1000) out1 = 7'b0000000;
        else if (bcd1==4'b1001) out1 = 7'b0000100;
        else out1=7'b0000001;
    end
    always @ (bcd2) begin
        if (bcd2==4'b0000) out2 = 7'b0000001;
        else if (bcd2==4'b0001) out2 = 7'b1001111;
        else if (bcd2==4'b0010) out2 = 7'b0010010;
        else if (bcd2==4'b0011) out2 = 7'b0000110;
        else if (bcd2==4'b0100) out2 = 7'b1001100;
        else if (bcd2==4'b0101) out2 = 7'b0100100;
        else if (bcd2==4'b0110) out2 = 7'b0100000;
        else if (bcd2==4'b0111) out2 = 7'b0001111;
        else if (bcd2==4'b1000) out2 = 7'b0000000;
        else if (bcd2==4'b1001) out2 = 7'b0000100;
        else out2=7'b0000001;
    end
    always @ (bcd3) begin
        if (bcd3==4'b0000) out3 = 7'b0000001;
        else if (bcd3==4'b0001) out3 = 7'b1001111;
        else if (bcd3==4'b0010) out3 = 7'b0010010;
        else if (bcd3==4'b0011) out3 = 7'b0000110;
        else if (bcd3==4'b0100) out3 = 7'b1001100;
        else if (bcd3==4'b0101) out3 = 7'b0100100;
        else if (bcd3==4'b0110) out3 = 7'b0100000;
        else if (bcd3==4'b0111) out3 = 7'b0001111;
        else if (bcd3==4'b1000) out3 = 7'b0000000;
        else if (bcd3==4'b1001) out3 = 7'b0000100;
        else out3=7'b0000001;
    end
endmodule

And finally, my clock divider I feed to every module requiring a clock to run correctly on FPGA:

module clockdivider(clk,clkout);
    input clk;
    output clkout;
    reg [24:0] q = 0;
    always @ (posedge clk) begin
        q <= q + 1;
    end
    assign clkout = q[0];
endmodule

So there it all is. When I enable my FPGA to it displays random numbers even though I haven't pushed any buttons. How is this possible? I'm relatively new to verilog so if theres any way I can simplify my code it would be greatly appreciated. Again, everything simulates perfectly. Thanks all

Best Answer

There could be many issues since you seem unfamiliar with real FPGAs so I will list them as we go:

  1. Are all external inputs synchronized to your FPGA's clock domain? Signals coming in can transition in the middle of the FPGA clock edges which leads to metastability. The way to deal with this is to pass the external input through a chain of flip-flops before you use it (i.e. copying the input through chain of signals/registers every clock). Each time it is passed, the chances of a metastable signal making it through to your functional core gets less probable until it is vanishingly small. The minimum is two, high reliability equipment might use three. This should be obvious, but I will say it anyways: This has to be the FIRST step of any signal that enters the FPGA. If you want to debounce or filter the signal (like in #2) then you must do it AFTER this step since metastability will not allow anything else to work properly.

  2. Are your external buttons debounced? When electromechanical contacts hit each other they will not mate cleanly and will repeatedly connect and disconnect until things settle down. Electronics are fast enough to pick this up. You can filter inputs in various ways in an FPGA. Some approaches are: (a) Once a transition is detected, ignore all subsequent transitions for a period of time (called blanking) (b) Only pass on the input state to be used by other values if it has stabilized for some amount of samples.

  3. Your FPGA needs a way to know what signals are associated with which pins. It also needs to tell the FPGA what type of pins those need to be. The way this is done is dependent on your synthesis software. This must be correct.

  4. Your FPGA also needs to know what the clock speed will be so that it knows how long it can allow a signal to propagate since all signals (especially clock signals) must arrive at their destinations in time for the circuit to work properly.

  5. Clock signals must go everywhere in an FPGA and must arrive everywhere at approximately the same time. You do not route clocks through the normal FPGA fabric since it is too variable and too slow to run clocks through all the FPGA configurable logic. The clock skew will be too high. FPGAs have dedicated clock networks to distribute the clock across the entire chip with minimum propagation delay. You must use these if you want to distribute a clock.

Keywords like "posedge" and "negedge" are very special and tell the software that this is a clock signal so it gets routed through the dedicated clock distribution network. This will occur automatically with every signal associated with these keywords, but there are only a very few numbers of these on an FPGA. So do not use this keyword for things that are not actual clock signals. If you want to look at a rising edge on a non-clock signal, write a separate module that compares the previous logic state to the current one to see if it is different.

  1. Similarly, do not divide clocks in the FPGA fabric for the same reason. Do not pass the clock through the configurable logic. Either use the clock divider hardware block on the FPGA, or use clock enable signals on your modules.

A clock enable signal is a signal that only goes high for a single clock pulse before falling low again. It triggers when a module will do something but the module is not clocked off of it. The module is still clocked off the main FPGA clock (through the clock distribution network). You can make a module that is clocked off the FPGA clock but outputs a clock enable every N cycles and use this to clock enable to trigger events to happen in other modules. All modules are still clocked off the FPGA clock and the fact that the clock enable expires after one clock cycle ensure that the modules don't continually trigger every clock cycle when they're not supposed to.

  1. Flip flops on the FPGA also have reset hardware so you can have asynchronous resets (since the configurable logic on the FPGA fabric hates asynchronous). A signal placed in the sensitivity list but does NOT have a keyword like "posedge" or "negedge" will be interpreted as a hardware reset. Do NOT use "posedge" or "negedge" with a reset signal.

Sensitivity list rule in HDL