Verilog HDL 定点数探索实验(加&乘)

#实验一:不同长度的2补码进行运算时,先进行符号扩展和数据对齐,然后再进行加、减法运算
——————————————————————————————————————————————————————
##设计方案一

###<font color=“#0000dd”>方案描述

- **使用Verilog语言,设计两个计数器**
- **计数器1 字长3比特,无符号数制,从0计数到7**
- **计数器2 字长4比特,二补码数制,从-7计数到7**
- **设计符号扩展规则(此处采用位拼接符),将两计数器的输出扩展为相同bit数**
- **分别设计相加之后的字长为4bit与5bit,对比验证两个计数器相加之后的正确性**

###Verilog HDL程序代码以及输出仿真文件

  • 计数器1 字长3比特,无符号数制,从0计数到7
  • 波形仿真文件,显示计数器1的动态变化
    • 注意此时的计数值(CNTVAL)为无符号数unsigned,则计算机的输出显示方式应选择为Hexadecimal(之后不再赘述)

这里写图片描述

module cnt_0to7_unsigned   //cnt_counter
(		        
 CLK   ,   // clock_50M
 CNTVAL    // counter value
 );  
input CLK;
output [3-1:0] CNTVAL;
parameter MAX_VAL = 7;
reg [3-1:0] CNTVAL;

always @ (posedge CLK) 
begin
  if(CNTVAL >= MAX_VAL)
	CNTVAL <= 0;
  else
	CNTVAL <= CNTVAL + 1'b1;
end

endmodule 

  • 计数器2 字长4比特,二补码数制,从-7计数到7
  • 计数器2 signal tap截图,显示其计数值的变化
  • 注意此时的计数值(CNTVAL)为二进制补码signed,则计算机的输出显示方式应选择Signed Decimal in Two’s Complement (之后不再赘述)

这里写图片描述

module cnt_fu7to7_signed     //cnt_counter
(		      
 CLK   ,   // clock
 CNTVAL    // output counter value
 );  
input CLK;
output [4-1:0] CNTVAL;

reg signed [4-1:0] CNTVAL; 

initial
begin
 CNTVAL <= 4'b1001;
end

always @ (posedge CLK) 
begin
  if(CNTVAL[3]== 0 && CNTVAL[2]==1 && CNTVAL[1]==1 && CNTVAL[0]==1)
   CNTVAL <= 4'b1001;
  else
    CNTVAL <= CNTVAL + 4'b0001;
end
 
endmodule  

  • 将两个计数器的输出扩展为4位。后将两个计数器的输出进行扩展到4bit匹配相加,代码及Signal Tap仿真图如下:
    这里写图片描述
    分析:从Signal Tap截图中可以看到本该是0 -6 -4 -2 0 2 4 6 8 的顺序,但变成了-8,这是由于4bit二进制补码的变化范围是-8到7,故8溢出
//以下部分代码为两计数器扩展为4bit后相加,相加字长被定义为4bit。计数器1与计数器2的代码同上显示,这里不再赘述
module and_counter       
//The output values of the two counters are summed
(
CLK,       //clock_50M
SUM        //The sum of the outputs of the two counters
);

input CLK;
output [4-1:0] SUM;
reg signed [4-1:0] SUM; 
reg signed [4-1:0] CNTVAL_1_3to4; 
//The output of the second counter is converted to a four-digit binary number 
wire  signed [3-1:0] CNTVAL_1;
wire  signed [4-1:0] CNTVAL_2;

integer A = 1'b0;

cnt_0to7_unsigned cnt_0to7_unsigned_1
(
CLK,
CNTVAL_1    //The output of the first counter
);

always @ (CNTVAL_1)
begin
 CNTVAL_1_3to4 = {A,CNTVAL_1};
end

cnt_fu7to7_signed cnt_fu7to7_signed_1
(
CLK,
CNTVAL_2    //The output of the second counter
);

always @ (CNTVAL_1_3to4 or CNTVAL_2)
begin
 SUM = CNTVAL_1_3to4 + CNTVAL_2;
end

endmodule

  • 将两个计数器的输出扩展为5位。后将两个计数器的输出进行扩展到5bit匹配相加,代码及Signal Tap仿真图如下:
    这里写图片描述
    分析:从Signal Tap截图中可以看到顺序有一段为0 2 4 6 0 2 4 6 8 10 12 14 -7 -5 -3 -1 1,经验证该段及未显示段均正确。(由于图形显示不全,剩余部分由读者自行验证)
//以下部分代码为两计数器扩展为5bit后相加,相加字长被定义为5bit。计数器1与计数器2的代码同上显示,这里不再赘述
module and_counter       //The output values of the two counters are summed
(
CLK,       //clock
SUM        //The sum of the outputs of the two counters
);

input CLK;
output [5-1:0] SUM;
reg signed [5-1:0] SUM; 
reg signed [5-1:0] CNTVAL_1_3to5; 
reg signed [5-1:0] CNTVAL_2_4to5; 
//The output of the second counter is converted to a four-digit binary number

wire  signed [3-1:0] CNTVAL_1;
wire  signed [4-1:0] CNTVAL_2;

integer A = 2'b00;
integer B = 1'b0;
integer C = 1'b1;

cnt_0to7_unsigned cnt_0to7_unsigned_1
(
CLK,
CNTVAL_1    //The output of the first counter
);


always @ (CNTVAL_1)
begin
 CNTVAL_1_3to5 = {A,CNTVAL_1};
end

cnt_fu7to7_signed cnt_fu7to7_signed_1
(
CLK,
CNTVAL_2    //The output of the second counter
);

always @ (CNTVAL_2)
begin
 if(CNTVAL_2[3] == 0)
  CNTVAL_2_4to5 = {B,CNTVAL_2};
 else
  CNTVAL_2_4to5 = {C,CNTVAL_2};
end

always @ (CNTVAL_1_3to5 or CNTVAL_2_4to5)
begin
 SUM = CNTVAL_1_3to5 + CNTVAL_2_4to5;
end

endmodule
##<font color=“#0000dd”>设计方案二

###方案描述

  • 使用Verilog语言,设计两个计数器
  • 计数器1 字长5比特,无符号数制,从0计数到31
  • 计数器2 字长4比特,二补码数制,从-7计数到7
  • 设计符号扩展规则(此处采用位拼接符),将两计数器的输出扩展为相同bit数
  • 分别设计相加之后的字长为6bit与7bit,对比验证两个计数器相加之后的正确性
  • 所用代码,所得输出文件,与设计方案一大同小异,请读者参考设计方案一,此处不再赘述
##<font color=“#0000dd”>实验一总结(定点数相加字长问题):
- **首先将两个定点数扩展为相同bit数,建议与和的bit数相同**
- **简单计算相加和的最大值,从而确定和的bit数。&注意此时要考虑到符号位是否存在,若符号位存在,应预留出符号位,即扩展为实际长度+1**
——————————————————————————————————————————————————————
#<font color=“#0000dd”>实验二:2补码的溢出回绕特性
——————————————————————————————————————————————————————
##<font color=“#0000dd”>溢出回绕特性:

###<font color= red>原理
- **设有N个2补码数相加**
- **即使中间结果溢出**
- **如果理论计算的结果不溢出**
- **则实际运算的结果也不溢出**

###<font color= red>计算举例
- **-3 -7 +5 = -5**
- **1101 +1001 +0101 =1011**

##方案描述

  • 设计3个2补码数相加
  • 使得中间结果溢出
  • 使得理论计算的结果不溢出
  • 检验实际运算的结果是否溢出
  • 为使实验简单易于理解,采用计算举例中的-3 -7 +5 = -5
###<font color=“#0000dd”>Verilog HDL程序代码以及输出仿真文件
- **波形仿真文件,显示计数器1的动态变化**
  - **注意此时的计数值(SUM)为有符号数signed,此时计算机的输出显示方式本人选择为signed Decimal**
  ![这里写图片描述](https://img-blog.csdn.net/20170315161253720?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHJvdG9uX2Jva2U=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

```Verilog HDL
module add_3_Twos_complment     
( 
 A,
 B,
 C,
 SUM
 );  
input [4-1:0] A;
input [4-1:0] B;
input [4-1:0] C;
output [4-1:0] SUM;

wire signed [4-1:0] A; 
wire signed [4-1:0] B; 
wire signed [4-1:0] C;  
wire signed [4-1:0] SUM; 

assign SUM = A + B + C;

endmodule
```

##实验二总结(溢出回绕特性):

  • 代码中的A被设置为-3,B被设置为-7,C被设置为5
  • 由于4bit数表示的范围是-8~7,故中间结果-10溢出
  • 如波形仿真图中红色圈出部分所示,最后结果并未溢出
  • 故在以后的2补码相加计算时,只要最后结果未溢出,即可不用进行位数扩展
    ——————————————————————————————————————————————————————
    #实验三:乘法对字长的影响,验证2补码整数的乘法运算
    ——————————————————————————————————————————————————————
    ##设计方案一
###<font color=“#0000dd”>方案描述

- **相乘两数,bit数相同**
- **使用Verilog语言,设计一个计数器 字长4bit,计数范围-8到7**
- **定义参数常量A为-8,字长4bit**
- **计数器的计数值与A皆为signed有符号数输入,使其相乘,结果最大为十进制数64,7bit,但参照前面的2补码加法实验可知,追加一个符号位,故最终显示结果为8bit**
- **即两4bit2补码数相乘,结果最大为8bit**
- **验证其正确性**

###Verilog HDL程序代码以及输出仿真文件

  • 计数器1 字长4比特,有符号数制,从-8计数到7
  • 波形仿真文件,显示计数器的动态变化
    这里写图片描述
module cnt_fu8to7_signed     //cnt_counter
(		      
 CLK   ,   // clock_50MHz
 CNTVAL    // output counter value
 );  
input CLK;
output [4-1:0] CNTVAL;

reg signed [4-1:0] CNTVAL; 

initial
begin
 CNTVAL <= 4'b1000;
end

always @ (posedge CLK) 
begin
  if(CNTVAL[3]== 0 && CNTVAL[2]==1 && CNTVAL[1]==1 && CNTVAL[0]==1)
   CNTVAL <= 4'b1000;
  else
    CNTVAL <= CNTVAL + 4'b0001;
end
 
endmodule  
  • 两4bit2补码数相乘,结果最大为8bit,验证其正确性
    这里写图片描述
//由SignalTap截图可以看出,结果是正确的
module signed_int_mul  //signed integer multiplication
(
 CLK,
 product
);
input CLK;
output [8-1:0] product;

reg signed [8-1:0] product; //The product of two numbers with signed
reg signed [7-1:0] guodu;   //The product of two numbers unsigned

wire  signed [4-1:0] CNTVAL_1;

parameter signed A = 4'b1000;
parameter B = 1'b0;
parameter C = 1'b1;

cnt_fu8to7_signed  cnt_fu8to7_signed_1
(
 CLK,
 CNTVAL_1   //output -8 to 7
);

always @ (CNTVAL_1)
begin
 guodu = CNTVAL_1 * A;
end

always @ (guodu or CNTVAL_1)
begin
 if(CNTVAL_1 == 4'b0000)
  product = {B,guodu[7-1:0]};
 else
 begin
  if(A[3] ^ CNTVAL_1[3] == 0)
   product = {B,guodu[7-1:0]};
  else
   product = {C,guodu[7-1:0]};
 end
end

endmodule 
##<font color=“#0000dd”>设计方案二

###方案描述

  • 相乘两数,bit数不同
  • 使用Verilog语言,设计一个计数器 字长4bit,计数范围-8到7
  • 定义参数常量A为3,字长2bit
  • 计数器的计数值与A皆为signed有符号数输入,使其相乘,结果最大为十进制数-24, 5bit,但参照前面的2补码加法实验可知,追加一个符号位,故最终显示结果为6bit
  • 即4bit与2bit2补码数相乘,结果最大为6bit
  • 验证其正确性
  • 所用代码,所得输出文件,与设计方案一大同小异,请读者参考设计方案一,此处不再赘述
##<font color=“#0000dd”>实验三总结(2补码整数相乘):
- **结果不含符号位最大为两数bit数相加**
- **追加符号位**
#<font color=“#0000dd”>实验四:带小数位的定点数的加法与乘法简单验证实验
——————————————————————————————————————————————————————
##<font color= red>原理
###注:以下(8.8),意思为前8位为整数,后8位为小数
###谓定点小数,就是小数点的位置是固定的。我们是要用整数来表示定点小数,由于小数点的位置是固定的,所以就没有必要储存它(如果储存了小数点的位置,那就是浮点数了)。既然没有储存小数点的位置,那么计算机当然就不知道小数点的位置,所以这个小数点的位置是我们写程序的人自己需要牢记的。
###对于定点小数的二进制表示。我们把小数点之后有n位叫做Qn,例如小数点之后有12位叫做Q12格式的定点小数,而Q0就是我们所说的整数。假如我们用8位二进制表示0.07071(前二位为整数部分,后六位为小数部分)为8'b00101101,即对00.101101做了*2^6处理。
###对于加减法,由于运算前后小数点的位置不会发生变化,故只需对运算结果进行/2^6处理即可。
###对于乘除法,由于运算前后小数点的位置发生了变化,例(8.8)*(8.8)结果为(16*16),需要进行移8位操作才能保持小数点位置不动

##设计方案一(乘法)

##<font color=“#0000dd”>方案描述
- **利用Verilog HDL语言,设计使得两定点数相乘。8'b10011001(2.6)与8'b10010010(2.6)**
- **由计算可知,运算后整数为5,为3位,小数为12位。将结果分别存储为15、14、13、12、11、10、9位,其中位数的变化,只是在逐渐的舍弃小数位的低位,而整数位没有变化。则结果以9位存储时的小数点位置与运算前两数的小数点位置相同**
- **运行程序,验证**
- **计算以不同位数存储时的结果与实际值之间的误差**

###Verilog HDL程序代码以及输出仿真文件

  • 波形仿真文件,显示结果不同位数存储时的值
    这里写图片描述
//注:本人愚笨,翻找资料,未查到如何使数组中向量的长度为变量,故代码繁琐,若各位看客有想法可与我留言
//若使数组中向量的长度为变量,则数据的处理大为方便,计算误差也不是难事,但在这里,几个数据,本人是手工计算,笨拙,勿怪
//结果9位(3.6)存储时,误差8.9*e(-5)
//结果10位(3.6)存储时,误差8.9*e(-5)
//结果11位(3.6)存储时,误差8.9*e(-5)
//结果12位(3.6)存储时,误差8.9*e(-5)
//结果13位(3.6)存储时,误差8.9*e(-5)
//结果14位(3.6)存储时,误差0
//结果15位(3.6)存储时,误差0
module int_dec_mul  //signed decimal_xiaoshu multiplication
(
 CLK,
 product_1,
 product_2,
 product_3,
 product_4,
 product_5,
 product_6,
 product_7
);
input CLK;
output [15-1:0] product_1;
output [14-1:0] product_2;
output [13-1:0] product_3;
output [12-1:0] product_4;
output [11-1:0] product_5;
output [10-1:0]  product_6;
output [9-1:0]  product_7;

reg [15-1:0] product_1;
reg [14-1:0] product_2;
reg [13-1:0] product_3;
reg [12-1:0] product_4;
reg [11-1:0] product_5;
reg [10-1:0]  product_6;
reg [9-1:0]  product_7; //The product of two numbers 

reg [15-1:0] guodu;   

parameter A = 8'b10011001;  //8'b10.011001
parameter B = 8'b10010010;  //8'b10.010010

always @ (CLK)
begin
 guodu <= B * A;
end

always @ (guodu)
begin
 product_1 = {guodu[14:12],guodu[11:0]};
 product_2 = {guodu[14:12],guodu[11:1]};
 product_3 = {guodu[14:12],guodu[11:2]};
 product_4 = {guodu[14:12],guodu[11:3]};
 product_5 = {guodu[14:12],guodu[11:4]};
 product_6 = {guodu[14:12],guodu[11:5]};
 product_7 = {guodu[14:12],guodu[11:6]};
end 

endmodule 
##<font color=“#0000dd”>设计方案二(加法)

##方案描述

猜你喜欢

转载自blog.csdn.net/proton_boke/article/details/62058321
今日推荐