我定义了一个二进制到 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
我看到的一个潜在综合问题是
Binary2BCDTranscoder
中的敏感度列表:
always @(state, convStart) begin
对于组合逻辑,列表应包括
always
块中发生变化的所有信号。 但是,该列表缺少 i
和 j
。
使用隐式敏感度列表是良好的编码习惯,它将自动包含所有必要的信号(并且仅必要的信号):
always @* begin
如果您在工具中启用 SystemVerilog 功能,请使用:
always_comb begin
这可以更好地传达设计意图并隐式地进行进一步检查。