完整的工程代码:链接: https://pan.baidu.com/s/1b7RX3H2DqMatHpkn5Mm7LA?pwd=sean 提取码: sean
目录
3.4根据generate语法 和下面代码的启发——电路结构
4.2 initial 块进行初始化——定义了三种测试方式!!!
1.信号定义
2.RTL/bin2bcd.v编写
2.0Cycle级pipeline切分
因为要进行Pipeline切分,所以bin_vld实际上要进行扩展——移位寄存器!!!
图中写错了,少了一位,比如第一次执行为:0000 bin_vld_5——pipeline分成五份,所以为[4:0]一共5位的数据。
2.1绝对值操作+符号位
正数——绝对值操作其实就是把最前面的 符号位 取出来,把剩余的数据放到保存绝对值的变量里面即可。 负数——最高位为1——数据位需要取反+1
定义寄存符号sign的变量:reg sign;绝对值 reg [9:0] bin_abs,中间寄存:wire[9:0] bin_abs_w。 根据符号位的正负:条件运算符 ——?
2.2计算BCD码的千位
需要定义几个变量???!!!我的思路直接错了,无法与电路图对应——笔记本上有解释+变量定义原因(图上解释不太好看)
错误写法:
变量定义的原因:需要定义reg bin_sign_d0,因为新来的数据会把bin_sign更新掉!需要将之前的bcd编码不断向后传递。
2.3计算BCD码的百位
1.定义
2.组合逻辑——减法器,计算差值
3.时序逻辑——求得百位的编码 以及求十位/个位的差值,同时向下传递符号位和千位的编码。
2.4计算BCD码的十位,同时个位自然就有了
有了百位的计算过程,十位的过程就自然而然了
2.5输出bcd编码
2.6代码汇总——不保证完全正确
//---00:Signal Definition
module bin2bcd(
bin ,
bin_vld ,
bcd ,
bcd_vld ,
clk ,
rstn
);
input wire [10:0] bin ; //signed num [-1023,1023]
input wire bin_vld ;
output wire [16:0] bcd ; //{sign, bcd_th, bcd_hu, bcd_ten, bcd}
output wire bcd_vld ;
input wire clk, rstn;
//---01: cycle pipeline divide
reg [4:0] bin_vld_d ;
always @(posedge clk or negedge rstn) begin
if (~rstn) begin
bin_vld_d <= 'd0;
end
else begin
bin_vld_d <= {bin_vld_d[3:0], bin_vld}; //SFT,left shift 1 bit !!!
end
end
//---1: cal abs value of bin
wire [9:0] bin_abs_W ; //reg the value of bin[9:0]
reg bin_sign ; //bin_sign = bin[10]
reg [9:0] bin_abs ; //reg the abs value of bin[9:0]
assign bin_abs_W = (bin[10]) ? ( (~{bin[9:0]} ) + 1'b1) : bin[9:0];
always @(posedge clk or negedge rstn) begin
if (~rstn) begin
bin_sign <= 'd0;
bin_abs <= 'd0;
end else if (bin_vld) begin
bin_sign <= bin[10];
bin_abs <= bin_abs_W;
end
end
//---2: cal thousand section of BCD
// by referencing the fake code writing in language C
wire [10:0] abs_sub_1000 ; //abs_sub_1000 = bin_abs - 1000
reg [9:0] res_thousand ; //residual after thousand
reg bcd_th ; //BCD code for thousand
reg bin_sign_d0 ; //reg and hand bcd_sign down
//write in a logic circuit, don't write in a time circuit
//substrct circuit is a logic circuit
assign abs_sub_1000 = {1'b0, bin_abs} - 11'd1000;
always @(posedge clk or negedge rstn) begin
if (~rstn) begin
res_thousand <= 'd0;
bcd_th <= 1'b0; //bcd_th [0~1]
bin_sign_d0 <= 1'b0;
end else if (bin_vld_d[0]) begin //pipeline divide: bin_vld_d[0]
//abs_sub_1000[10] = 1: bin_abs < 1000 ---- res_thousand = bin_abs - 0
res_thousand <= (abs_sub_1000[10]) ? bin_abs : abs_sub_1000[9:0];
//abs_sub_1000[10] = 1: bin_abs < 1000 ---- bcd_th = 0
bcd_th <= (abs_sub_1000[10]) ? 1'b0 : 1'b1;
bin_sign_d0 <= bin_sign;
end
end
//---3: cal hundred section of BCD
// definition width of signal has trick!!!!! ↓↓↓↓↓↓↓↓↓↓↓↓
wire [10:0] abs_sub_900 ; //[999-900,0-900]--[-900,99]--sign + 2^10--[10:0] 11bit
wire [10:0] abs_sub_800 ;
wire [10:0] abs_sub_700 ;
wire [10:0] abs_sub_600 ; //[699-600,0-600]--[-600,99]--sign + 2^10--[10:0] 11bit
wire [9:0] abs_sub_500 ; //[599-500,0-500]--[-500,99]--sign + 2^9--[9:0] 10bit
wire [9:0] abs_sub_400 ;
wire [9:0] abs_sub_300 ;
wire [8:0] abs_sub_200 ;
wire [7:0] abs_sub_100 ;
reg [6:0] res_hundred ; //residual after hundred
reg [3:0] bcd_hu ; //BCD code for hundred
reg bin_sign_d1 ; //reg and hand bcd_sign down
reg bcd_th_d0 ; //reg and hand bcd_th down
assign abs_sub_900 = {1'b0, res_thousand} - 11'd900;
assign abs_sub_800 = {1'b0, res_thousand} - 11'd800;
assign abs_sub_700 = {1'b0, res_thousand} - 11'd700;
assign abs_sub_600 = {1'b0, res_thousand} - 11'd600;
//599 > res_thousand >= 500, bit width need 10 bit, so res_thousand
//with sign, width is 11bit --- 11'd500
assign abs_sub_500 = {1'b0, res_thousand} - 11'd500;
//499 > res_thousand >= 400, bit width need 9 bit, so res_thousand[8:0]
//with sign, width is 10bit --- 10'd400
assign abs_sub_400 = {1'b0, res_thousand[8:0]} - 10'd400;
assign abs_sub_300 = {1'b0, res_thousand[8:0]} - 10'd300;
//299 > res_thousand >= 200, bit width need 9 bit, so res_thousand[8:0]
//with sign, width is 10bit --- 10'd200
assign abs_sub_200 = {1'b0, res_thousand[8:0]} - 10'd200;
//199 > res_thousand >= 100, bit width need 8 bit, so res_thousand[7:0]
//with sign, width is 9bit --- 9'd100
assign abs_sub_100 = {1'b0, res_thousand[7:0]} - 9'd100;
always @(posedge clk or negedge rstn) begin
if (~rstn) begin
res_hundred <= 'd0;
bcd_hu <= 'd0; //bcd_hu [0~9]
bin_sign_d1 <= 1'b0;
bcd_th_d0 <= 1'b0; //bcd_th_d0 [0~1]
end else if(bin_vld_d[1]) begin
//through sign to select bcd_hu and residual
//if sign = 1'b0, then res_thousand is bigger than present number
if (abs_sub_900[10] == 1'b0) begin //sign is in the top [10]
res_hundred <= abs_sub_900[6:0];
bcd_hu <= 'd9;
end else if(abs_sub_800[10] == 1'b0) begin
res_hundred <= abs_sub_800[6:0];
bcd_hu <= 'd8;
end else if(abs_sub_700[10] == 1'b0) begin
res_hundred <= abs_sub_700[6:0];
bcd_hu <= 'd7;
end else if(abs_sub_600[10] == 1'b0) begin
res_hundred <= abs_sub_600[6:0];
bcd_hu <= 'd6;
end else if(abs_sub_500[9] == 1'b0) begin
res_hundred <= abs_sub_500[6:0];
bcd_hu <= 'd5;
end else if(abs_sub_400[9] == 1'b0) begin
res_hundred <= abs_sub_400[6:0];
bcd_hu <= 'd4;
end else if(abs_sub_300[9] == 1'b0) begin
res_hundred <= abs_sub_300[6:0];
bcd_hu <= 'd3;
end else if(abs_sub_200[8] == 1'b0) begin
res_hundred <= abs_sub_200[6:0];
bcd_hu <= 'd2;
end else if(abs_sub_100[7] == 1'b0) begin
res_hundred <= abs_sub_100[6:0];
bcd_hu <= 'd1;
end else begin //not 9~1, then is 0
res_hundred <= res_thousand[6:0];
bcd_hu <= 'd0;
end
//reg and hand bin_sign_d0 and bcd_th down
bin_sign_d1 <= bin_sign_d0 ;
bcd_th_d0 <= bcd_th ;
end
end
//---4: cal tenth section of BCD
wire [7:0] abs_sub_90 ;
wire [7:0] abs_sub_80 ;
wire [7:0] abs_sub_70 ;
wire [6:0] abs_sub_60 ; //[-60, 9]
wire [6:0] abs_sub_50 ;
wire [6:0] abs_sub_40 ;
wire [5:0] abs_sub_30 ; //[-30, 9]
wire [5:0] abs_sub_20 ;
wire [4:0] abs_sub_10 ; //[-10, 9]
reg [3:0] res_ten ; //residual after tenth——BCD code for last bcd
reg [3:0] bcd_ten ; //BCD code for tenth
reg bin_sign_d2 ; //reg and hand bcd_sign down
reg bcd_th_d1 ; //reg and hand bcd_th down
reg bcd_hu_d0 ; //reg and hand bin_hu down
assign abs_sub_90 = {1'b0, res_hundred} - 8'd90;
assign abs_sub_80 = {1'b0, res_hundred} - 8'd80;
assign abs_sub_70 = {1'b0, res_hundred} - 8'd70;
assign abs_sub_60 = {1'b0, res_hundred} - 8'd60; // maybe res_hundred > 64
assign abs_sub_50 = {1'b0, res_hundred[5:0]} - 7'd50;
assign abs_sub_40 = {1'b0, res_hundred[5:0]} - 7'd40;
assign abs_sub_30 = {1'b0, res_hundred[5:0]} - 7'd30; // maybe res_hundred > 32
assign abs_sub_20 = {1'b0, res_hundred[4:0]} - 6'd20;
assign abs_sub_10 = {1'b0, res_hundred[4:0]} - 6'd10; // maybe res_hundred > 16
always @(posedge clk or negedge rstn) begin
if (~rstn) begin
res_ten <= 'd0;
bcd_ten <= 'd0;
bin_sign_d2 <= 1'b0;
bcd_th_d1 <= 1'b0;
bcd_hu_d0 <= 'd0;
end else if(bin_vld_d[2]) begin
bin_sign_d2 <= bin_sign_d1 ;
bcd_th_d1 <= bcd_th_d0 ;
bcd_hu_d0 <= bcd_hu ;
//through sign to select bcd_ten and residual res_ten---bcd
//if sign = 1'b0, then res_thousand is bigger than present number
if (abs_sub_90[7] == 1'b0) begin //sign is in the top [10]
res_ten <= abs_sub_90[3:0];
bcd_ten <= 'd9;
end else if(abs_sub_80[7] == 1'b0) begin
res_ten <= abs_sub_80[3:0];
bcd_ten <= 'd8;
end else if(abs_sub_70[7] == 1'b0) begin
res_ten <= abs_sub_70[3:0];
bcd_ten <= 'd7;
end else if(abs_sub_60[6] == 1'b0) begin
res_ten <= abs_sub_60[3:0];
bcd_ten <= 'd6;
end else if(abs_sub_50[6] == 1'b0) begin
res_ten <= abs_sub_50[3:0];
bcd_ten <= 'd5;
end else if(abs_sub_40[6] == 1'b0) begin
res_ten <= abs_sub_40[3:0];
bcd_ten <= 'd4;
end else if(abs_sub_30[5] == 1'b0) begin
res_ten <= abs_sub_30[3:0];
bcd_ten <= 'd3;
end else if(abs_sub_20[5] == 1'b0) begin
res_ten <= abs_sub_20[3:0];
bcd_ten <= 'd2;
end else if(abs_sub_10[4] == 1'b0) begin
res_ten <= abs_sub_10[3:0];
bcd_ten <= 'd1;
end else begin
res_ten <= res_hundred[3:0];
bcd_ten <= 'd0;
end
end
end
//---5: generate output
//[16:0] bcd; bcd_vld;
//[4:0] bin_vld_d —— bin_vld bin_vld[0] 1 2 3 —— 5 pipe
assign bcd_vld = bin_vld_d[3];
//as thousand only 1bit, bcd_thousand[0 0 0 bcd_th_d1, xxxx, xxxx, xxxx]
//so has 3'h0
assign bcd = {bin_sign_d2, 3'h0, bcd_th_d1, bcd_hu_d0, bcd_ten, res_ten};
endmodule
3.pattern/bin2bcd.model.v编写
实现除法的bin2bcd编码电路——用于“形式仿真”做对比验证
3.1信号定义
3.2做仿真模型——使用function函数
task里只能操作reg型中间变量,不能操作wire型。 task/function 作用是:重复的逻辑,不需要多次书写。 function可综合、task不写时延也可以综合(一般不可以综合)。函数如果要综合的话,里面都不能有延时符号,综合出来以后,在电路结构上是组合逻辑。
!!!function在时间上可以认为是不消耗一点时间的!!!!
function <返回值的类型或范围>(函数名);
<端口说明语句> // input XXX
<变量类型说明语句> // reg YYY
......
begin
<语句>
......
函数名 = ZZZ; // 函数名就相当于输出变量;
end
endfunction
里面有除法和取余,除法本质还是使用多个减法器串行实现(没有乘法的 CSA串联的 Wallace Tree 结构),相对延时比较大。 而且在generate结构里面写 乘法,如“*8”,assign语句会被重复写8次。
3.3流水线设计
Generate语法学习:1.Verilog中generate的用法 2.Verilog中generate的使用
Generate 语句基本概念——generate 语句可以动态地生成 Verilog 代码,常用于编写许多结构相同但参数不同的赋值语句或逻辑语句,方便参数化模块的生成。 1.generate 语句主要有以下三种用途:①对矢量中的多个位进行重复操作②重复操作多个模块的实例引用③根据参数定义来确定程序中是否应该包括某段 Verilog 代码 2.generate 语句有主要三种结构:①generate - for 语句结构 ②generate - if 语句结构 ③generate - case 语句结构
看懂这段代码的关键:Verilog:generate、for、always 语句用法与电路结构对比
3.4根据generate语法 和下面代码的启发——电路结构
4个实例名称:gen_bcd_pipe[0] gen_bcd_pipe[1] gen_bcd_pipe[2] gen_bcd_pipe[3]
3.5代码汇总——不保证完全正确
module bin2bcd_model(
bin ,
bin_vld ,
bcd ,
bcd_vld ,
clk ,
rstn
);
parameter PIPE_STAGE = 4;
input wire [10:0] bin ; //signed num [-1023,1023]
input wire bin_vld ;
output wire [16:0] bcd ; //{sign, bcd_th, bcd_hu, bcd_ten, bcd}
output wire bcd_vld ;
input wire clk, rstn;
//--------the only use of funtion is to call the "abs" parts-----------
//--------then by using dividing generating the bcd code -----------
//function return value's function name
function [16:0] bin2bcd;
// input define
input [10:0] bin ; //signed num
reg bin_sign ;
reg [9:0] bin_abs ;
reg [3:0] bcd_th ;
reg [3:0] bcd_hu ;
reg [3:0] bcd_ten ;
reg [3:0] bcd_last ;
//function description
begin
if (bin[10]) begin
bin_sign = 1'b1;
bin_abs = {~(bin[9:0])} + 1'b1;
end else begin
bin_sign = 1'b0;
bin_abs = bin[9:0];
end
//--- cal bcd_last
bcd_last = bin_abs % 10;
bin_abs = bin_abs / 10;
//--- cal bcd_ten
bcd_ten = bin_abs % 10;
bin_abs = bin_abs / 10;
//--- cal bcd_hu
bcd_hu = bin_abs % 10;
bin_abs = bin_abs / 10;
//--- cal bcd_th
bcd_th = bin_abs % 10;
bin2bcd = {bin_sign, bcd_th, bcd_hu, bcd_ten, bcd_last};
end
endfunction
//------------------------------------------------------------------
wire [16:0] bcd_tmp ;
reg [16:0] bcd_pipe [0:PIPE_STAGE-1];
reg bin_vld_pipe [0:PIPE_STAGE-1];
//function call
assign bcd_tmp = bin2bcd(bin); //get temp bcd code
generate
genvar cnt;
for (cnt = 0; cnt < PIPE_STAGE; cnt = cnt + 1) begin: gen_bcd_pipe
if (cnt == 0) begin
always @(posedge clk or negedge rstn) begin
if (~rstn) begin
bcd_pipe[cnt] <= 'd0;
bin_vld_pipe[cnt] <= 'd0;
end else begin
bcd_pipe[cnt] <= bcd_tmp;
bin_vld_pipe[cnt] <= bin_vld;
end
end
end else begin
always @(posedge clk or negedge rstn) begin
if (~rstn) begin
bcd_pipe[cnt] <= 'd0;
bin_vld_pipe[cnt] <= 'd0;
end else begin
bcd_pipe[cnt] <= bcd_pipe[cnt-1];
bin_vld_pipe[cnt] <= bin_vld_pipe[cnt-1];
end
end
end
end
endgenerate
assign bcd_vld = bin_vld_pipe [PIPE_STAGE - 1];
assign bcd = bcd_pipe [PIPE_STAGE - 1];
wire [16:0] bcd_d0 ;
wire bcd_vld_d0 ;
wire [16:0] bcd_d1 ;
wire bcd_vld_d1 ;
wire [16:0] bcd_d2 ;
wire bcd_vld_d2 ;
endmodule
4.测试激励 pattern/tb.v实现
4.1信号定义
4.2 initial 块进行初始化——定义了三种测试方式!!!
fixed test中——bin_vld信号始终有效,会将【-1023 ,1023】整个区间的bin转bcd输出。 进行:0 1 2 3 4 ... 1023 -0 -1 ... -1023 整个进行bin2bcd的转换
random test中——bin_vld信号随机有效,会将【-1023 ,1023】整个区间的bin随机转成bcd输出。 进行:0 1 2 3 4 ... 1023 -0 -1 ... -1023 随机进行bin2bcd的转换。
重要的是会随机产生bin_vld=0信号,测试此时需要bcd输出无效!
因为编码能够bin2bcd编码的功能,在固定测试中已经全部覆盖了!
4.3激励输入
4.4代码汇总——不保证完全正确
`timescale 1ns/10ps
module tb();
parameter CYC_TIME = 10.0;
//input
reg clk, rstn ;
reg [10:0] bin ;
reg bin_vld ;
//output
wire [16:0] bcd_dut ;
wire bcd_vld_dut ;
//output_model
wire [16:0] bcd_model ;
wire bcd_vld_model ;
//test time/data define
reg [15:0] cnt ;
reg [15:0] rand_val ;
reg [3:0] wait_cnt ;
//CYC_TIME = 10.0
always # (CYC_TIME / 2.0) clk = ~ clk;
initial begin
$fsdbDumpfile("tb.fsdb");
$fsdbDumpvars(0,tb) ;
end
initial begin
clk = 0;
rstn = 0;
bin = 0;
bin_vld = 0;
//delay 10 cycle_time
//#1 maybe for better look of wave
repeat(10) @(posedge clk); #1;
rstn = 1;
//--- fixed test
repeat(2) @(posedge clk); #1;
for (cnt = 0; cnt < 2048; cnt = cnt + 1) begin
bin_vld = 1;
if (cnt == (1<<10)) //1 mean negtive, <<10 menas 2^10
bin = 0; //bin is 11bit, so 1<<10 means -1024
else
bin = cnt; //0 1 2 3
@(posedge clk); #1;
end
bin_vld = 0;
wait_cnt= 0;
//--- random test (more bin_vld)
for (cnt = 0; cnt<(( 1<<11 )- 1); cnt = cnt + 1) begin // +2047
rand_val = $random() % 256;
if (rand_val <= 128) begin
wait_cnt = 0;
end else if(rand_val <= 128+64) begin
wait_cnt = 1;
end else if(rand_val <= 128+64+32) begin
wait_cnt = 2;
end else
wait_cnt = rand_val[3:0];
if (wait_cnt != 0) begin
repeat(wait_cnt) @(posedge clk);
#1;
end
bin_vld = 1'b1;
if (cnt == (1<<10)) begin // -1024
bin = 0;
end else
bin = cnt[10:0]; // 0 1 2 3 4 ... 1023 -0 -1 -2 ... -1023
@(posedge clk); #1;
bin_vld = 1'b0;
end
//--- random test (less bin_vld)
for (cnt = 0; cnt<(( 1<<11 )- 1); cnt = cnt + 1) begin // +2047
rand_val = $random() % 256;
if (rand_val <= 128) begin
wait_cnt = rand_val[3:0];
end else if(rand_val <= 128+64) begin
wait_cnt = 2;
end else if(rand_val <= 128+64+32) begin
wait_cnt = 1;
end else
wait_cnt = 0;
if (wait_cnt != 0) begin
repeat(wait_cnt) @(posedge clk);
#1;
end
bin_vld = 1'b1;
if (cnt == (1<<10)) begin // -1024
bin = 0;
end else
bin = cnt[10:0]; // 0 1 2 3 4 ... 1023 -0 -1 -2 ... -1023
@(posedge clk); #1;
bin_vld = 1'b0;
end
repeat (10) @(posedge clk);
$display("Info: bin2bcd sim pass.");
$finish();
end
//stimulation insert
bin2bcd_model #(.PIPE_STAGE(4)) u_bin2bcd_model(
.bin (bin ),
.bin_vld (bin_vld ),
.bcd (bcd_model ),
.bcd_vld (bcd_vld_model ),
.clk (clk ),
.rstn (rstn )
);
bin2bcd u_bin2bcd(
.bin (bin ),
.bin_vld (bin_vld ),
.bcd (bcd_dut ),
.bcd_vld (bcd_vld_dut ),
.clk (clk ),
.rstn (rstn )
);
//--- check result ---//
always @(posedge clk or negedge rstn) begin
if (~rstn) begin
end else if(bcd_vld_model) begin
if ((bcd_vld_model !== bcd_vld_dut) || (bcd_model !== bcd_dut)) begin
#1;
$display("Info: bin2bcd sim fail.");
$finish();
end
end
end
endmodule
5.仿真测试
5.1首先解决了源文件bat无法使用下面代码运行的问题
解决的关键问题:Debussy的环境变量配置到bin目录下,不要直接配置到Debussy.exe
5.2运行bat文件,打开Debussy检查代码
0.仿真文件Modelsim文件夹
仿真目录下只需要上面这些文件即可,原文件夹中的很多文件是运行过代码才有的
wave.do文件是modelsim第一次加载完wave,设置好信号才出现的,所以现在理论上没有,在第3步才会生成!
最后剩的没讲文件是:rum_sim_cover.do文件,是检查测试文件覆盖率的!
1.双击bat文件
多两个文件
2.剩余步骤按照《RTL仿真工具介绍》一文进行!
第一步change directory 到 modelsim文件夹
3.代码出现错误,使用modelsim进行debug
意味着到200时,bcd编码错误——检查穷举法计算百位的代码
计算电路没问题,说明每次计算得到的百位都是正确的,但是百位1 到 百位2 的进位在仿真上确实发生了错误——因此,检查百位进位向下pipe传递过程中的问题!
修改好代码,选择nodesign(可以不退出:在tcl命令处输入 quit -sim退出仿真),重新运行do sim.do代码! 仿真通过!!!!!!!!
取fixed test波形如下:
4.剩余步骤按照《RTL仿真工具介绍》一文进行!
进行覆盖率等测试