0

My code for a reaction tester works perfectly and as it should in simulation. But when I move it to my FPGA device it just stalls as soon as I press the start button and I cannot figure out what goes wrong as it is working perfectly in simulation.

The concept is, when reset is pressed display Hi on the screen, when start is pressed, pick a random value from LFSR and count up to max value, thus making it a random delay. When max count for this reg is reached turn on the led, start the timer and wait for the stop button to be pressed.

Here is a screenshot of the code working in simulation:

enter image description here

Here 0000 is normal as notice that ticker starts incrementing and when it reaches its desired value it increments the timer making it 0001, so if I scroll forward enough it shows proper operation.

Here is the commented code, I added the (* KEEP = "TRUE" *)reg [1:0] sel; because during optimization the sel signal was removed as it was declared but never called, but obviously I needed it as it is.

  reg [12:0] random, random_next, random_done; //**13 bit for simulation purposes

reg [4:0] count_r, count_next_r; //to keep track of the shifts. 5 bit register to count up to 30


wire feedback = random[12] ^ random[3] ^ random[2] ^ random[0]; //**for simulation

always @ (posedge clock or posedge reset)
begin
    if (reset)
    begin
        random <= 13'hF; //**An LFSR cannot have an all 0 state, thus reset to FF
        count_r <= 0;
    end

    else
    begin
        random <= random_next;
        count_r <= count_next_r;
    end
end

always @ (*)
begin
    random_next = random; //default state stays the same
    count_next_r = count_r;

        random_next = {random[11:0], feedback}; //**shift left the xor'd every posedge clock
        count_next_r = count_r + 1;

    if (count_r == 13) //**for implementation its 30, simulation its 13
    begin
        count_next_r = 0;
        random_done = random; //assign the random number to output after 13 shifts
    end

end
//random number block ends

reg outled;

reg [3:0] reg_d0, reg_d1, reg_d2, reg_d3; //registers that will hold the individual counts
(* KEEP = "TRUE" *)reg [1:0] sel;
localparam [1:0]
                        idle = 2'b00,
                        starting = 2'b01,
                        time_it = 2'b10,
                        done = 2'b11;

reg [1:0] state_reg, state_next;
reg [12:0] count_reg, count_next; //**change for simulation, 30 bits for implementation, 13 bits for simulation

always @ (posedge clock or posedge reset)
begin
    if(reset)
        begin 
            state_reg <= idle;
            count_reg <= 0;
        end
    else
        begin
            state_reg <= state_next;
            count_reg <= count_next;
        end
end

reg go_start;
always @ (*)
begin
    state_next = state_reg; //default state stays the same
    count_next = count_reg;

    case(state_reg)
        idle:
            begin
                //DISPLAY HI HERE
                sel = 2'b00;
                if(start)
                begin
                    count_next = random_done; //get the random number from LFSR module
                    state_next = starting;
                end
            end
        starting:
            begin
                if(count_next == 8191) // **750M equals a delay of 15 seconds.
                begin                           //and starting from 'rand' ensures a random delay
                    outled = 1'b1; //turn on the led 
                    state_next = time_it; //go to next state
                end

                else
                    count_next = count_reg + 1; 
            end     
        time_it:
            begin
                    sel = 2'b01; //start the timer
                    state_next = done;                  
            end

        done:
            begin
                if(stop)
                    begin
                        sel = 2'b10; //stop the timer
                        outled = 1'b0;
                    end
            end

        endcase

    case(sel)
        2'b00: //hi
        begin
            go_start = 0; //make sure timer module is off
            regd0 = 4'd12; 
            regd1 = 4'd11;
            regd2 = 4'd10;
            regd3 = 4'd12;
        end

        2'b01: //timer
        begin

            go_start = 1'b1; //enable start signal to start timer
            regd0 = reg_d0;
            regd1 = reg_d1;
            regd2 = reg_d2;
            regd3 = reg_d3;
        end

        2'b10: //stop timer
        begin
            go_start = 1'b0;
        end

        default:
        begin
            regd0 = 4'bx;
            regd1 = 4'bx;
            regd2 = 4'bx;
            regd3 = 4'bx;
        end
    endcase         
end


//the stopwatch block


reg [15:0] ticker; //**16 bits needed to count up to 50K bits, 10 bit for simulation
wire click;

//the mod 50K clock to generate a tick ever 0.001 second

always @ (posedge clock or posedge reset)
begin
    if(reset)

        ticker <= 0;

    else if(ticker == 50000) //**if it reaches the desired max value of 50K reset it, 500 for simulation
        ticker <= 0;
    else if(go_start) //only start if the input is set high
        ticker <= ticker + 1;
end

assign click = ((ticker == 50000)?1'b1:1'b0); //**click to be assigned high every 0.001 second

always @ (posedge clock or posedge reset)
begin
    if (reset)
        begin
            reg_d0 <= 0;
            reg_d1 <= 0;
            reg_d2 <= 0;
            reg_d3 <= 0;
        end

    else if (click) //increment at every click
        begin
            if(reg_d0 == 9) //xxx9 - the 0.001 second digit
            begin  //if_1
                reg_d0 <= 0;

                if (reg_d1 == 9) //xx99 
                begin  // if_2
                    reg_d1 <= 0;
                    if (reg_d2 == 5) //x599 - the two digit seconds digits
                    begin //if_3
                        reg_d2 <= 0;
                        if(reg_d3 == 9) //9599 - The minute digit
                            reg_d3 <= 0;
                        else
                            reg_d3 <= reg_d3 + 1;
                    end
                    else //else_3
                        reg_d2 <= reg_d2 + 1;
                end

                else //else_2
                    reg_d1 <= reg_d1 + 1;
            end 

            else //else_1
                reg_d0 <= reg_d0 + 1;
        end
end

And here is the display circuit that will take the regd0-regd3 values.

    localparam N = 18; //18 for implementation, 8 for simulation

reg [N-1:0]count;

always @ (posedge clock or posedge reset)
    begin
        if (reset)
            count <= 0;
        else
            count <= count + 1;
    end

reg [3:0]sseg;
reg [3:0]an_temp;
reg reg_dp;
always @ (*)
    begin
        case(count[N-1:N-2]) //MSB and MSB-1 for multiplexing

            2'b00 : 
                begin
                    sseg = first;
                    an_temp = 4'b1110;
                    reg_dp = 1'b1;
                end

            2'b01:
                begin
                    sseg = second;
                    an_temp = 4'b1101;
                    reg_dp = 1'b0;
                end

            2'b10:
                begin
                    sseg = third;
                    an_temp = 4'b1011;
                    reg_dp = 1'b1;
                end

            2'b11:
                begin
                    sseg = fourth;
                    an_temp = 4'b0111;
                    reg_dp = 1'b0;
                end
        endcase
    end
assign an_m = an_temp;

reg [6:0] sseg_temp;    
always @ (*)
    begin
        case(sseg)
            4'd0 : sseg_temp = 7'b1000000; //display 0
            4'd1 : sseg_temp = 7'b1111001; //display 1
            4'd2 : sseg_temp = 7'b0100100;// display 2
            4'd3 : sseg_temp = 7'b0110000;
            4'd4 : sseg_temp = 7'b0011001;
            4'd5 : sseg_temp = 7'b0010010;
            4'd6 : sseg_temp = 7'b0000010;
            4'd7 : sseg_temp = 7'b1111000;
            4'd8 : sseg_temp = 7'b0000000;
            4'd9 : sseg_temp = 7'b0010000;
            4'd10 : sseg_temp = 7'b0001001; //to display H
            4'd11 : sseg_temp = 7'b1001111; //to display I
            default : sseg_temp = 7'b0111111; //dash
        endcase
    end
assign {g_m, f_m, e_m, d_m, c_m, b_m, a_m} = sseg_temp; 
assign dp_m = reg_dp;

endmodule

When I move it on to my FPGA device at reset "Hi" is displayed as it should but when I press start the display just shows 0000 and stays at that. The led wont turn on either so that means the times was never initialized after the start button was pressed. I have been trying to sort this out for days now and cant seem to figure out why this is happening. What does one do when something works in simulation but does not work as its supposed to in hardware?

Update code with the latches fixed:

    //Block for LFSR random number generator        
reg [12:0] random, random_next, random_done; //**13 bit for simulation purposes
//reg [29:0] random, random_next, random_done; //30 bit register to keep track upto 15 seconds
reg [4:0] count_r, count_next_r; //to keep track of the shifts. 5 bit register to count up to 30

//wire feedback = random[29] ^ random[5] ^ random[3] ^ random[0]; 
wire feedback = random[12] ^ random[3] ^ random[2] ^ random[0]; //**for simulation

always @ (posedge clock or posedge reset)
begin
    if (reset)
    begin
        random <= 13'hF; //**An LFSR cannot have an all 0 state, thus reset to FF
        count_r <= 0;
    end

    else
    begin
        random <= random_next;
        count_r <= count_next_r;
    end
end

always @ (*)
begin
    random_next = random; //default state stays the same
    count_next_r = count_r;

        random_next = {random[11:0], feedback}; //**shift left the xor'd every posedge clock
        //count_next_r = count_r + 1;

    if (count_r == 13) //**for implementation its 30, simulation its 13
    begin
        count_next_r = 0;
        random_done = random; //assign the random number to output after 13 shifts
    end
    else
    begin
        count_next_r = count_r + 1;
        random_done = 13'b0;
    end

end
//random number block ends

reg outled;

reg [3:0] reg_d0, reg_d1, reg_d2, reg_d3; //registers that will hold the individual counts
/*(* KEEP = "TRUE" *)*/reg [1:0] sel, sel_next;
localparam [1:0]
                        idle = 2'b00,
                        starting = 2'b01,
                        time_it = 2'b10,
                        done = 2'b11;

reg [1:0] state_reg, state_next;
reg [12:0] count_reg, count_next; //**change for simulation, 30 bits for implementation, 13 bits for simulation

always @ (posedge clock or posedge reset)
begin
    if(reset)
        begin 
            state_reg <= idle;
            count_reg <= 0;
            sel <=0;
        end
    else
        begin
            state_reg <= state_next;
            count_reg <= count_next;
            sel <= sel_next;
        end
end

reg go_start;
always @ (*)
begin
    state_next = state_reg; //default state stays the same
    count_next = count_reg;
    sel_next = sel;
    case(state_reg)
        idle:
            begin
                //DISPLAY HI HERE
                //sel_next = 2'b00;
                if(start)
                begin
                    count_next = random_done; //get the random number from LFSR module
                    state_next = starting;
                end
            end
        starting:
            begin
                if(count_next == 8191) // **750M equals a delay of 15 seconds.
                begin                           //and starting from 'rand' ensures a random delay
                    outled = 1'b1; //turn on the led 
                    state_next = time_it; //go to next state
                end

                else
                begin
                    count_next = count_reg + 1; 
                    outled = 1'b0;
                end
            end     
        time_it:
            begin
                    sel_next = 2'b01; //start the timer
                    state_next = done;                  
            end

        done:
            begin
                if(stop)
                    begin
                        sel_next = 2'b10; //stop the timer
                        outled = 1'b0;
                    end
            end

        endcase

    case(sel_next)
        2'b00: //hi
        begin
            go_start = 0; //make sure timer module is off
            regd0 = 4'd12; 
            regd1 = 4'd11;
            regd2 = 4'd10;
            regd3 = 4'd12;
        end

        2'b01: //timer
        begin

            go_start = 1'b1; //enable start signal to start timer
            regd0 = reg_d0;
            regd1 = reg_d1;
            regd2 = reg_d2;
            regd3 = reg_d3;
        end

        2'b10: //stop timer
        begin
            go_start = 1'b0;
            regd0 = reg_d0;
            regd1 = reg_d1;
            regd2 = reg_d2;
            regd3 = reg_d3;
        end

        2'b11:
        begin
            regd0 = 4'd12;
            regd1 = 4'd12;
            regd2 = 4'd12;
            regd3 = 4'd12;
            go_start = 1'b0;
        end

        default:
        begin
            regd0 = 4'd12;
            regd1 = 4'd12;
            regd2 = 4'd12;
            regd3 = 4'd12;
            go_start = 1'b0;
        end
    endcase         
end


//the stopwatch block


reg [15:0] ticker; //**16 bits needed to count up to 50K bits, 10 bit for simulation
wire click;

//the mod 50K clock to generate a tick ever 0.001 second

always @ (posedge clock or posedge reset)
begin
    if(reset)

        ticker <= 0;

    else if(ticker == 50000) //**if it reaches the desired max value of 50K reset it, 500 for simulation
        ticker <= 0;
    else if(go_start) //only start if the input is set high
        ticker <= ticker + 1;
end

assign click = ((ticker == 50000)?1'b1:1'b0); //**click to be assigned high every 0.001 second

always @ (posedge clock or posedge reset)
begin
    if (reset)
        begin
            reg_d0 <= 0;
            reg_d1 <= 0;
            reg_d2 <= 0;
            reg_d3 <= 0;
        end

    else if (click) //increment at every click
        begin
            if(reg_d0 == 9) //xxx9 - the 0.001 second digit
            begin  //if_1
                reg_d0 <= 0;

                if (reg_d1 == 9) //xx99 
                begin  // if_2
                    reg_d1 <= 0;
                    if (reg_d2 == 5) //x599 - the two digit seconds digits
                    begin //if_3
                        reg_d2 <= 0;
                        if(reg_d3 == 9) //9599 - The minute digit
                            reg_d3 <= 0;
                        else
                            reg_d3 <= reg_d3 + 1;
                    end
                    else //else_3
                        reg_d2 <= reg_d2 + 1;
                end

                else //else_2
                    reg_d1 <= reg_d1 + 1;
            end 

            else //else_1
                reg_d0 <= reg_d0 + 1;
        end
end
assign led = outled;
endmodule 
ipunished
  • 684
  • 2
  • 6
  • 22

3 Answers3

4

Have you scrubbed your synthesis logs for anything like warnings or errors? The first thing I would do would figure out what's going on with that sel signal. If synthesis thinks it is not used then something is very wrong with it, you shouldn't have to override it with any special KEEP directive.

For one thing I notice that you have inferred a latch on sel as you don't assign it in every state. Inferring latches is no problem for simulation, but your FPGA may not like it.

May want to read: Why are Inferred Latches Bad?

You have quite a few other inferred latches as well: outled, regd0-3, random_done, go_start, and maybe others. You should try to clean these all up before trying to debug anything on the FPGA.

Community
  • 1
  • 1
Tim
  • 35,413
  • 11
  • 95
  • 121
  • 1
    Agreed, inferred latches often cause problems. If your software supports SystemVerilog then switch `always @ (*)` with `always_comb`. This will give you warnings (or errors) in your log file(s) if there are inferred latches. – Greg Mar 05 '13 at 01:50
  • @Tim Thank you for your answer. I went through the link and it did make me think most say that try to avoid combinational logic and make it as sequential as possible. But I cannot see my code without using combinational logic. So I removed all of the latches but still get this warning: ``FF/Latch (without init value) has a constant value of 0 in block `` And when I program my FPGA with this code it has the same problem as before so this latch must be the problem. I cannot see how this can be a latch I have updated my original post with the latches fixed. Thank you – ipunished Mar 08 '13 at 14:35
  • 1
    I'm not sure what you read that said you should avoid combinational logic, but I think you may have misunderstood it. You certainly will need combinational logic to make any kind of circuit, and there is nothing wrong with it. As to that warning, I don't see the source of it from your code. It seems that maybe somewhere you have defined `sel` as having three bits, but then you only drive two of them? (check your ports). I wouldn't expect that to be fatal though, it's just warning of an unused wire. – Tim Mar 08 '13 at 17:54
2

When the simulation is good and the synthesised code doesn't work there is a discrepancy between real-life and the simulations. I always hope to find that the discrepancy is in my simulations as it's easier to fix than real-life is :)

Some examples:

  • Simulation assumes that logic delays are inconsequential. If you have good timing constraints that is true. If a critical path is not covered by the timing constraints, it is no longer true. At the very least you need an maximum frequency constraint on the clock.

  • Other timing problems can come from the devices externally - you need to tell the FPGA tools about their setup and hold and output delays so that they can be checked against what the FPGA logic is capable of

  • If you've created your own models of the outside parts from the datasheet, they are very likely to be incorrect in at least some small detail

  • The startup behaviour might be different - if you have initialised (not using a reset) any signals, check the synthesis logs to make sure they got carried through to the FPGA bitstream, otherwise you might be losing something.

  • Digital signals are really analogue, especially once they are offchip. FPGA outputs are usually set to a fast setting by default, so that the numbers don't look bad. If you then drive them down a bit of random wire without a good return path, the signals will turn "very-analogue"!

Martin Thompson
  • 16,395
  • 1
  • 38
  • 56
  • Thank you for your answer. I have tried it in simulation and it works perfectly and as it should. But the problem arises in implementation, as @Tim mentioned I had quite a few latches so I got that fixed but I am still presented with a warning which I cannot fix and which must be causing the problem as it is the only warning left to rectify. The warning given is : ``FF/Latch (without init value) has a constant value of 0 in block . This FF/Latch will be trimmed during the optimization process.`` I have update the first post with the latches removed. sel is not a constant – ipunished Mar 08 '13 at 14:40
  • My point is that because you have a working simulation, you need to look at places where the simulation ideal world breaks down. My bullets point to some things to check... – Martin Thompson Mar 11 '13 at 10:33
0

Something else you can try in order to debug issues when running on the FPGA is to use a logic analyzer to see what your hardware is doing and how that compares to you simulations.

Xilinx provides a tool called Chipscope

and Altera provides Signaltap

These are good tools to use after you resolved all simulator/router warnings and are still having issues.

Ciano
  • 554
  • 5
  • 16