二进制 - BCD 转换器在 sim 中工作,但在 FPGA 上不起作用

问题描述 投票:0回答:1

我定义了一个二进制到 BCD 转换器以在 Basys 3 开发板上使用。仿真中,结果符合预期,并且完全符合时序。

我将 BCD 转换器包含在顶部模块中,在其中我使用通过另一个模块创建的输入脉冲来启动转换过程。

在船上,结果很奇怪,因为大多数输入值都完全为零,唯一的例外是 1,它显示 BCD 值为 15|15|15|14。

因为问题只出现在板载上,所以我相信模块的合成有问题,但我还没能找出来。

以下是BCD转换代码:

`timescale 1ns / 1ps

module Binary2BCDTranscoder #(parameter INPUT_SIZE = 12, parameter OUTPUT_DIGITS = 4, parameter ICNTR_SIZE = 4, parameter JCNTR_SIZE = 2) (
        input clk,
        input rst,
        input convStart,
        input [INPUT_SIZE-1:0] data,
        output reg convDone,
        output reg [4 * OUTPUT_DIGITS - 1:0] convOut 
    );
    
    localparam WAIT = 2'b00;
    localparam CONV_CHK = 2'b01;
    localparam FINISHED = 2'b11;
    
    reg iRst, jRst, iEn, jEn;
    wire [ICNTR_SIZE-1:0] i;
    wire [JCNTR_SIZE-1:0] j;
    
    reg [1:0] state, next_state;
    reg [INPUT_SIZE-1:0] inner_in;
    reg [4 * OUTPUT_DIGITS - 1:0] inner_out;
    
    always @(posedge clk) begin
    
        if(!rst) state <= WAIT;
        
        else state <= next_state;
    
    end
    
    always @(posedge clk) begin
    
        if(!rst) inner_in <= 0;
    
        else if(convDone) inner_in <= data;
        
    end
    
    always @(posedge convDone) begin
    
        convOut <= inner_out;
    
    end
    
    counter #(.SIZE(ICNTR_SIZE)) iCounter (
        .clk(clk),
        .rst(iRst),
        .en(iEn),
        .out(i)
    );
    
    counter #(.SIZE(JCNTR_SIZE)) jCounter (
        .clk(clk),
        .rst(jRst),
        .en(jEn),
        .out(j)
    );
        
    always @(state, convStart) begin
    
        case(state)
        
            WAIT: begin
            
                convDone = 1;
                iRst = 0;
                iEn = 0;
                jRst = 0;
                jEn = 0;
                next_state = convStart ? CONV_CHK : WAIT;
            
            end
            
            CONV_CHK: begin
                
                if(i == INPUT_SIZE) begin
                    convDone = 1;
                    next_state = FINISHED;
                    iRst = 0;
                    jRst = 0;
                    iEn = 0;
                    jEn = 0;
                end
                
                else if(j == OUTPUT_DIGITS-1) begin
                    next_state = CONV_CHK;
                    convDone = 0;
                    iRst = 1;
                    jRst = 0;
                    iEn = 1;
                    jEn = 0;
                end
                
                else begin
                    next_state = CONV_CHK;
                    convDone = 0;
                    iRst = 1;
                    jRst = 1;
                    iEn = 0;
                    jEn = 1;
                end
            
            end
            
            FINISHED: begin
            
                next_state = WAIT;
                convDone = 1;
                iRst = 0;
                iEn = 0;
                jRst = 0;
                jEn = 0;
                
            end
            
            default: begin
                next_state = WAIT;
                convDone = 1;
                iRst = 0;
                iEn = 0;
                jRst = 0;
                jEn = 0;
            end
        
        endcase
    
    end
    
    always @(i,j) begin
    
        case(state)
        
            WAIT: begin
                inner_out = 0;
            end
        
            CONV_CHK: begin
                if(iEn) begin
                    inner_out = {inner_out[4*OUTPUT_DIGITS - 2 : 0], inner_in[INPUT_SIZE - 1 - i]};
                end
                
                else if(jEn) begin
                    inner_out = inner_out;
                    if(inner_out[4*j+:4] >= 5) inner_out[4*j+:4] = inner_out[4*j+:4] + 3;
                end
                
                else begin
                    inner_out = inner_out;
                end
            end
            
            FINISHED: begin
                inner_out = 0;
            end
        
            default: begin
                inner_out = 0;
            end 
        
        
        endcase
    
    end
endmodule

顶层模块如下:

module top(
        input clk,
        input rst,
        input convStart,
        input [11:0] data,
        output convDone,
        output [15:0] convOut 
    );

    wire convPulse;
    wire [9:0] clkDivOut;
    
    counter #(.SIZE(10)) CLK_DIVIDER(
        .clk(clk),
        .rst(!rst),
        .en(1'b1),
        .out(clkDivOut)
    );
    
    pulseCreator #(.NUM_BITS(2)) convStartPulse (
        .clk(clkDivOut[9]),
        .in(convStart),
        .out(convPulse),
        .regOutput()
    );
    
    Binary2BCDTranscoder #(.INPUT_SIZE(12),.OUTPUT_DIGITS(4),.ICNTR_SIZE(4),.JCNTR_SIZE(2)) B2BCD (
        .clk(clkDivOut[9]),
        .rst(!rst),
        .convStart(convPulse),
        .data(data),
        .convDone(convDone),
        .convOut(convOut)
    );
    
endmodule

为了完整起见,这里是计数器和脉冲发生器的代码:

module counter #(parameter SIZE = 4) (
        input clk,
        input rst,
        input en,
        output reg [SIZE-1:0] out
    );
    
    always @(posedge clk) begin
    
        if(!rst)
            out <= 0;
        else
            if (en) out <= out + 1;
    
    end
    
endmodule

module serialRegister #(SIZE = 4)(
        input clk,
        input rst,
        input in,
        input en,
        output reg [SIZE-1:0] out
    );
    
    always @(posedge clk, negedge rst) begin
    
        if(!rst) begin
        
            out <= 0;
        
        end
        
        else begin
        
            if(en) out <= {out[SIZE-2:0],in};
            
        end

    end
    
endmodule

module pulseCreator #(NUM_BITS=3) (
        input clk,
        input in,
        output out,
        output [NUM_BITS-1:0] regOutput
    );
    
    //wire [NUM_BITS-1:0] regOutput;
    
    serialRegister #(.SIZE(NUM_BITS)) pulseReg(
        .clk(clk),
        .rst(in),
        .en(in),
        .in(in),
        .out(regOutput)
    );
    
    assign out = in & !regOutput[NUM_BITS-1];

endmodule
verilog fpga
1个回答
0
投票

我看到的一个潜在综合问题是

Binary2BCDTranscoder
中的敏感度列表:

always @(state, convStart) begin

对于组合逻辑,列表应包括

always
块中发生变化的所有信号。 但是,该列表缺少
i
j

使用隐式敏感度列表是良好的编码习惯,它将自动包含所有必要的信号(并且必要的信号):

always @* begin

如果您在工具中启用 SystemVerilog 功能,请使用:

always_comb begin

这可以更好地传达设计意图并隐式地进行进一步检查。


这是另一个潜在的问题:

always @(posedge convDone) begin

convDone
是组合逻辑的输出,这意味着它可能会出现故障。 最好只使用时钟信号的顺序逻辑输出。 或者,更好的是,使用边缘检测器根据
clk
:

确定信号何时变高
always @(posedge clk) begin
    if (convDone) ...

采用如此小的设计,无需 2 个时钟域;所有逻辑都依赖于一个时钟:

clk


查看综合日志文件中是否有任何警告或错误消息。

© www.soinside.com 2019 - 2024. All rights reserved.