实施后如何调试?我在仿真中完美运行的代码显示了硬件中的奇怪行为

时间:2013-03-02 23:52:19

标签: hardware verilog fpga hdl

我的反应测试代码完美无缺,在仿真中也应如此。但是当我将它移动到我的FPGA设备时,只要按下开始按钮就会停止,我无法弄清楚出现了什么问题,因为它在模拟中完美运行。

概念是,当按下重置时,屏幕上会显示Hi,当按下start时,从LFSR中选择一个随机值并计算到最大值,从而使其成为最大值随机延迟。当达到此注册表的最大计数时,打开指示灯,启动计时器并等待按下stop按钮。

以下是仿真代码的截图:

enter image description here

这里0000是正常的,因为通知自动收报机开始递增,当它达到所需的值时,它会使计时器递增0001,所以如果我向前滚动它会显示正确的操作。

以下是注释代码,我添加了(* KEEP = "TRUE" *)reg [1:0] sel;,因为在优化期间,sel信号在声明时被删除但从未被调用过,但显然我需要它原样。

  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

这是显示电路,它将采用regd0-regd3值。

    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

当我在重置时将其移动到我的FPGA设备时“Hi”显示为应该显示,但是当我按下start时,显示屏只显示0000并保持不变。 led也不会打开,这意味着在按下start按钮后,时间从未初始化。我一直试图解决这个问题几天,似乎无法弄清楚为什么会这样。当某些东西在模拟中工作但在硬件中不起作用时,人们会做什么?

使用已修复的锁存器更新代码:

    //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 

3 个答案:

答案 0 :(得分:4)

您是否已清除合成日志中的警告或错误等内容?我要做的第一件事就是弄清楚sel信号发生了什么。如果综合认为它没有被使用那么它就会出现问题,你不应该用任何特殊的KEEP指令覆盖它。

有一件事我注意到你在sel上推断了一个锁存器,因为你没有在每个状态下分配它。推断锁存器对于仿真没有问题,但您的FPGA可能不喜欢它。

可能需要阅读:Why are Inferred Latches Bad?

您还有很多其他推断锁存器:outledregd0-3random_donego_start以及其他人。在尝试调试FPGA上的任何内容之前,您应该尝试清理这些内容。

答案 1 :(得分:2)

当模拟良好且合成代码不起作用时,现实生活与模拟之间存在差异。我总是希望发现差异在我的模拟中,因为它比现实生活更容易解决:)

一些例子:

  • 模拟假设逻辑延迟是无关紧要的。如果你有良好的时序约束是真的。如果关键路径未被时序约束所覆盖,则不再适用。至少你需要一个时钟上的最大频率约束。

  • 其他时序问题可能来自外部设备 - 您需要告诉FPGA工具它们的设置和保持和输出延迟,以便可以根据FPGA逻辑的能力检查它们

    < / LI>
  • 如果你已经从数据表中创建了自己的外部零件模型,那么它们很可能在至少一些小细节上是不正确的

  • 启动行为可能不同 - 如果您已初始化(使用重置)任何信号,请检查综合日志以确保它们已传输到FPGA比特流,否则你可能会失去一些东西。

  • 数字信号实际上是模拟信号,特别是一旦它们是片外信号。默认情况下,FPGA输出通常设置为快速设置,因此数字看起来不会很糟糕。如果你在没有良好返回路径的情况下将它们向下驱动一些随机线路,信号将变为“非常类似”!

答案 2 :(得分:0)

在FPGA上运行时,您可以尝试调试问题的其他方法是使用逻辑分析仪来查看您的硬件正在做什么以及与您的模拟进行比较。

Xilinx提供了一个名为Chipscope

的工具

和Altera提供Signaltap

在解决所有模拟器/路由器警告并且仍然存在问题后,这些是使用的好工具。