我定义了一个二进制到 BCD 转换器,用于 Basys 3 开发板。在模拟中,结果符合预期,并且完全遵循时序。
我将 BCD 转换器包含在顶部模块中,在那里我使用通过另一个模块创建的输入脉冲启动转换过程。
在船上,结果很奇怪,因为大多数输入值都给出完整的零,唯一的例外是 1,它显示 BCD 值为 15|15|15|14。
因为问题仅存在于板上,所以我相信模块的合成存在问题,但我还无法找出原因。
Synthesis 向我发出以下警告:
[Synth 8-567] referenced signal 'i' should be on the sensitivity list ["C:/Xilinx/VivadoProjects/BCD/BCD.srcs/sources_1/new/Binary2BCDTranscoder.v":80]
[Synth 8-567] referenced signal 'j' should be on the sensitivity list ["C:/Xilinx/VivadoProjects/BCD/BCD.srcs/sources_1/new/Binary2BCDTranscoder.v":80]
[Synth 8-567] referenced signal 'state' should be on the sensitivity list ["C:/Xilinx/VivadoProjects/BCD/BCD.srcs/sources_1/new/Binary2BCDTranscoder.v":150]
[Synth 8-567] referenced signal 'iEn' should be on the sensitivity list ["C:/Xilinx/VivadoProjects/BCD/BCD.srcs/sources_1/new/Binary2BCDTranscoder.v":150]
[Synth 8-567] referenced signal 'inner_in' should be on the sensitivity list ["C:/Xilinx/VivadoProjects/BCD/BCD.srcs/sources_1/new/Binary2BCDTranscoder.v":150]
[Synth 8-567] referenced signal 'jEn' should be on the sensitivity list ["C:/Xilinx/VivadoProjects/BCD/BCD.srcs/sources_1/new/Binary2BCDTranscoder.v":150]
[Synth 8-327] inferring latch for variable 'inner_out_reg' ["C:/Xilinx/VivadoProjects/BCD/BCD.srcs/sources_1/new/Binary2BCDTranscoder.v":155]
[Synth 8-7080] Parallel synthesis criteria is not met
以下是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
我看到的一个潜在综合问题是敏感度列表
Binary2BCDTranscoder
:对于组合逻辑,列表应包括
always
块中所有发生变化的信号。然而,列表缺失i
,并且j
。使用隐式敏感度列表是一种很好的编码习惯,它将自动包含所有必要的信号(并且只包含必要的信号):
如果您在工具中启用了 SystemVerilog 功能,请使用:
这更好地传达了设计意图并隐式地实现了进一步的检查。
以下情况同样如此:
这是另一个潜在问题:
convDone
是组合逻辑的输出,这意味着它可能会出现故障。最好只对时钟信号使用顺序逻辑输出。或者,更好的方法是使用边沿检测器来确定该信号何时变高,具体方法如下clk
:对于如此小的设计,不需要2个时钟域;所有逻辑都依赖于一个时钟:
clk
。查看综合日志文件中是否存在任何警告或错误消息。