How to debug after implementation? My code that works perfectly in simulation shows strange behaviour in hardware

蹲街弑〆低调 提交于 2020-01-25 07:35:11

问题


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:

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 

回答1:


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.




回答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"!




回答3:


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.



来源:https://stackoverflow.com/questions/15180808/how-to-debug-after-implementation-my-code-that-works-perfectly-in-simulation-sh

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!