以32bit加法器为核心的加法、减法、乘法和除法计算器(ALU)

1 任务概述

实现一个以加法器为核心的计算器。
加法:能够实现32bit加法
减法:能够实现32bit减法
乘法:能够实现两个32bit数字的乘法,乘积为64bit
除法:能够实现两个32bit无符号数的除法,商为32bit,余数为32bit
解读:该部分的关键在于串并转换,状态数并不多,也没有必要简化;串并转换的关键在于计数器信号和使能信号;而且对于线路空闲时发送无效字节同样很重要,需要借助已存在的或者需要新建信号来支持。 

2 系统模块设计

在这里插入图片描述

图2-1 系统模块图
输入端口

  • Operand_X-32bit
    加数、被减数、乘数、被除数
  • Operand_Y-32bit
    加数、减数、乘数、除数
  • Opcode
    运算选择信号;3’b001-加法、3’b010-减法、3’b110-乘法、3’b111-除法、其余无效
  • clk
    时钟信号
    输出端口
  • Result-64bit
    64bit运算结果
    内部模块连线图
    在这里插入图片描述

图2-2 内部模块连线图
详细设计
3.1 加减法
引入补码可以将加法和减法统一起来,可以采用“联通符号位在内,按位取反,末位加一”的方法,由[y]_补求[-y]_补。
在这里插入图片描述

图3-1以加法器为核心的加减法器电路原理示意图
3.2 乘法
如果使用“符号位单独处理(异或运算),数值按照无符号数乘法”的方法处理有符号数乘法的话,因为一般机器采用补码表示,所以需要在补码和原码之间来回做变换,增加了操作步骤。
Booth乘法算法:
进行n轮加法、移位,最后再多来一次加法
每次加法可能+0 、+[x]补、+[-x]
每次移位是“补码的算数右移”
符号位参与运算
在2中,需要根据部分积 y 中的最低两位来确定加什么:
表2-1 最低两位操作表
y_i y
(i+1) y
(i+1) y_i 操作
0 0 0 +0
0 1 1 +[x]_补
1 0 -1 +[-x]_补
1 1 0 +0
在这里插入图片描述

图3-2以加法器为核心的Booth乘法电路原理示意图
3.3 除法
第三个版本将商寄存器和余数寄存器合并为一个左移的64-bit寄存器,从余数移位开始计算,运算完成后,结果的高低两个部分需要通过移位互换位置(处理器设计中低位是商,高位是余数)。
在这里插入图片描述

图3-3除法算法流程图
除法器采用一个32-bit的除法寄存器、一个32-bit的ALU和一个64-bit的余数寄存器:
在这里插入图片描述

图3-4除法模块示意图
笔者也编写了补码乘法——加减交替法,但是由于对于该算法理解不是很透彻,导致无法验证,遂放弃,于是只简单开发了无符号数乘法。
在这里插入图片描述

图3-5加减交替法有符号数除法电路示意图

4 对编码的说明

加法器
通过补码可以将加法和减法统一起来,如果是减法的话,可以通过+[y]_补 来实现。

assign Result[32:0] = Operand_X+B+add_cin;always @(Operand_Y or Opcode) beginif (Opcode == 3'b010) B = ~Operand_Y;else if (Opcode == 3'b001)B = Operand_Y;endalways @(Opcode) beginif (Opcode == 3'b010)add_cin = 1'b1;else if (Opcode == 3'b001)add_cin = 1'b0;endassign Result = {{31{Result[32]}},Result[32:0]};

乘法器
以加法器为核心,经过33个周期实现两个32bit的数据相乘。

always @(posedge clk or posedge rst) beginif (rst) Result <= 65'b0;else if (Opcode == 3'b110) beginResult <= {32'b0,Operand_X,1'b0};end else beginResult <= {Add_Result[31],Add_Result,Result[32:1]};endend

加法器两个输入信号的生成

always @(posedge rst or Result or Operand_X or Busy) beginif (rst)Add_A <= 32'b0;  else if (Busy) Add_A <= Result[64:33];elseAdd_A <= Operand_X;endalways @(Busy or Multiplicand or Operand_Y) beginif (Busy) Operand_Y_inner <= Multiplicand;else Operand_Y_inner <= Operand_Y;endalways @(Opcode_inner or Operand_Y_inner) beginif (Opcode_inner == 2'b10)Add_B <= Operand_Y_inner;else if (Opcode_inner == 2'b11)Add_B <= ~Operand_Y_inner;else Add_B <= 32'b0;endalways @(Opcode_inner) beginif (Opcode_inner == 2'b11)Add_Cin <= 1'b1;else Add_Cin <= 1'b0; 
endif (Result[1:0] == 2'b00 || Result[1:0] == 2'b11)Opcode_inner <= 2'b00;else if (Result[1:0] == 2'b01) Opcode_inner <= 2'b10;else Opcode_inner <= 2'b11;

除法器
32bit无符号数除法,经过33个周期得出结果。

always @(posedge clk or posedge rst) beginif (rst) beginresult <= 64'b0; end else if (Opcode == 3'b111) beginresult <= {31'b0,Operand_X,1'b0};end else if (result[63:32] >= Operand_Y)result = {mid_result[30:0],result[31:0],1'b1};else result = {result[62:32],result[31:0],1'b0} ;endalways @(result) beginmid_result = result[63:32] - Operand_Y;
endassign Remainder= (Operand_Y == 32'b0)?32'bz:{1'b0,result[63:33]};assign Quotient = result[31:0];
加减交替法实现补码有符号除法:未仿真验证

在这里插入图片描述

图4-1 加减交替法算法步骤

//符号扩展assign operand_x = {Operand_X[31],Operand_X};assign operand_y = {Operand_Y[31],Operand_Y};//0 不等,1 相等always @(Add_A or Add_B or Add_Cin) beginResult = Add_A + Add_B + Add_Cin;endalways @(posedge rst or posedge clk) beginif (rst) Mul_Counter <= 5'b0;else if (Opcode == 3'b110) Mul_Counter <= 5'b11111;else if (Busy) Mul_Counter <= Mul_Counter - 1;endalways @(posedge clk or posedge rst) beginif (rst)Busy <= 1'b0;else if (Opcode == 3'b110) Busy <= 1'b1;else if (Busy == 1'b1 && Mul_Counter == 5'b00000) beginBusy <= 1'b0;endendalways @(operand_x or Busy or Add_A) beginif (Busy) Add_A <= {Add_A[32:1],1'b0};elseAdd_A <= operand_x;end// 1 同号,0 异号always @(Opcode_inner or operand_y) beginif (Opcode_inner == 1'b0)Add_B <= operand_y;else if (Opcode_inner == 1'b1)Add_B <= ~operand_y;endalways @(Opcode_inner) beginif (Opcode_inner == 1'b1)Add_Cin <= 1'b1;else Add_Cin <= 1'b0; endalways @(Opcode_inner or Quotient or Busy) beginif (!Busy) beginQuotient <= 32'b0;end else beginif (Opcode_inner == 1'b1) Quotient <= {Quotient[31:1],1'b1};elseQuotient <= {Quotient[31:1],1'b0};endendalways @(Busy or Result or Opcode or operand_y) beginif (Busy) beginif (Result[32:31] == operand_y[32:31])Opcode_inner <= 1'b1;else Opcode_inner <= 1'b0;end else begin if (Opcode == 3'b100) Opcode_inner <= 1'b0;else if (Opcode == 3'b101) Opcode_inner <= 1'b1;else Opcode_inner <= 1'b0; endendassign Remainder = Result[31:0];

顶层设计模块
为了使得获取乘法和除法结果的设计更为简便,将muler和divider模块中的计数器改为计33计数器,使得在最后一个周期,即第33个周期输出结果,该周期之后,对应的Busy信号将清零。
reg [63:0] Result;
wire [63:0] Result1,Result2,Result3;
wire Buys1,Busy2;
assign Opc = Opcode;
add_sub as1(
.Operand_X(Operand_X),
.Operand_Y(Operand_Y),
.Opcode(Opc),
.Result(Result1)
);
muler m1(
.clk(clk),
.rst(rst),
.Opcode(Opc),
.Operand_X(Operand_X),
.Operand_Y(Operand_Y),
.Busy(Busy1),
.Cout(Cout),
.Product(Result2)
);
divider D1(
.clk(clk),
.rst(rst),
.Opcode(Opc),
.Operand_X(Operand_X),
.Operand_Y(Operand_Y),
.Busy(Busy2),
.Result(Result3)
);
always @(Result3 or Result1 or Result2) begin
if (Opcode == 3’b010||Opcode == 3’b001)
Result <= Result1;
else if (Busy1)
Result <= Result2;
else if (Busy2)
Result <= Result3;
else
Result <= 64’bz;
end
Testbench开发
5.1. Testbench开发思路
该题目的仿真并不算难点,仅有的难点在于计算下一个计算周期的Busy信号的产生,即下一次测试数据的打入时间至少在前一次数据计算完成后。
由于该计算器由三个部分完成,所以采用三个部分先单独测试,然后在进行整体测试的思路。
在这里插入图片描述

图5-1 项目文件结构图
5.2. Testbench说明
加减法
表5-1 加减法测试用例及测试结果表
X Y 是否通过

{$random}%{2^32}	{$random}%{2^32}32'h0007 (7)	32'hfffffff4(-12)32'h7fff	32'h7fff	是
32'hffff_fffd(-3)	32'hffff_fff4(-12)32'h8000_0000( -2^31)	32'h0001(1)	是代码initial begin Operand_X = {$random}%{2^32};Operand_Y = {$random}%{2^32};Opcode = 3'd1;res = Operand_X+Operand_Y;#10;res1 = Result;if (res == res1) begin$display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);end else begin$display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);//$finish;end#10; Operand_X = 32'h0007; Operand_Y = 32'hfffffff4;Opcode = 3'd1;#10;res1 = Result; //7+(-12)= -5;if (64'hffff_ffff_ffff_fffb == res1) begin$display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);end else begin$display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);//$finish;end#10; Operand_X = 32'h7fff;Operand_Y = 32'h7fff;Opcode = 3'd1;#10;res1 = Result;if (64'h0000_FFFE == res1) begin$display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);end else begin$display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);//$finish;end#10;Operand_X = 32'hffff_fffd;//-3Operand_Y = 32'hffff_fff4;//-12Opcode = 3'd2;#10;res1 = Result; //-3-(-12) = 9if (64'h0000_0009 == res1) begin$display("[time@%t]: x=%h,y=%h,Opcode=%h-------PASS",$time,Operand_X,Operand_Y,Opcode);end else begin$display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);//$finish;end#10;Operand_X = 32'h8000_0000;//-2^31Operand_Y = 32'h0001;//1Opcode = 3'd2;#10;res1 = Result; //if (64'hffff_ffff_7fff_ffff == res1) begin$display("[time@%t]: x=%h,y=%h,Opcode=%h-------PASS",$time,Operand_X,Operand_Y,Opcode);end else begin$display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);//$finish;end#20;$finish;end

乘法

always begin#5; clk = ~clk;endinitial begin#15;Operand_X = 32'b0000_0000_0000_0000_0000_0111_0110_0001;Operand_Y = 32'b0000_0000_0000_0000_1001_0111_0110_0001;// Operand_X = 32'h6;// Operand_Y = 32'h2;#330;#15;Operand_X = $random;Operand_Y = $random;#330;#15;Operand_X = 32'b1000_0000_0000_0000_0000_0111_0110_0001;Operand_Y = 32'b1000_0000_0000_0000_1001_0111_0110_0001;#330;#15;Operand_X = 32'b0111_1111_1111_1111_1111_1111_1111_1111;Operand_Y = 32'b1000_0100_1001_0111_1110_1100_0111_1000;#330;endalways beginOpcode = 3'b000;#15;Opcode = 3'b110;#5;Opcode = 3'b000;#330;endinitial beginclk = 0;rst = 0;endalways begin#5;rst = 1;#5;rst = 0;#10;#330;end

除法

always begin#5; clk = ~clk;endinitial begin#15;Operand_X = 32'h000A;Operand_Y = 32'h0002;#330;#15;Operand_X = 2;Operand_Y = 0;#330;#15;Operand_X = 32'd18;Operand_Y = 32'h5;#330;#15;Operand_X = 32'd34;Operand_Y = 32'h6;#330;endalways beginOpcode = 3'b000;#15;Opcode = 3'b111;#5;Opcode = 3'b000;#330;endinitial beginclk = 0;rst = 0;endalways begin#5;rst = 1;#5;rst = 0;#10;#330;end

整体测试
//初始化模块

alu_top al_tp1(.Operand_X(Operand_X),.Operand_Y(Operand_Y),.Opcode(Opcode),.clk(clk),.rst(rst),.Opc(Opc),.Busy1(Busy1),.Busy2(Busy2),.Result1(Result1),.Result2(Result2),.Result3(Result3),.Result(Result));always begin#5;clk = ~clk;endinitial begin#5;//加法器Operand_X = 32'h0007; Operand_Y = 32'hfffffff4; #10;res1 = Result; //7+(-12)= -5;if (64'hffff_ffff_ffff_fffb == res1) begin$display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);end else begin$display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);end//乘法器#15;Operand_X = 32'b0000_0000_0000_0000_0000_0111_0110_0001;Operand_Y = 32'b0000_0000_0000_0000_1001_0111_0110_0001;#330;//除法器#15;Operand_X = 32'd18;Operand_Y = 32'h5;endalways beginOpcode = 3'b000;#5;Opcode = 3'd1;#10;//乘法器Opcode = 3'b000;#10;Opcode = 3'b110;#5;#5;Opcode = 3'b000;#325;//除法器Opcode = 3'b000;#10;Opcode = 3'b111;#5;#5;Opcode = 3'b000;#330;endinitial begin#5;#10;//乘法器clk = 1;rst = 0;#15;#330;//除法器clk = 1;rst = 0;#15;#330;endalways begin#5;#10;//乘法器#5;rst = 1;#5;rst = 0;#10;#325;//除法器#5;rst = 1;#5;rst = 0;#10;#330;end
### 6仿真结果

6.1 加减法

图6-1 加减法仿真成功图
6.2 乘法

图6-2 乘法测试用例1仿真成功

图6-3乘法测试用例2仿真成功

图6-3乘法测试用例3仿真成功

图6-4乘法测试用例4仿真成功
6.3 除法

图6-5除法测试用例1仿真成功

图6-6除法测试用例2(除数为零)仿真成功

图6-7除法测试用例3仿真成功

图6-8除法测试用例4仿真成功
总结
编写Testbench文件时,首先要搞清楚每个信号是怎么产生的,其次要弄清楚信号之间的产生逻辑,结合实际想要完成的功能,在仿真过程中,发现并修改Design Source文件的错误。
在复杂逻辑,以及类似于多bit数据寄存器等难以通过肉眼直接观察正误的项目中,要优先理清楚Design Source文件中的逻辑,避免逻辑错误,而不是想着在仿真过程中发现逻辑错误,尽可能节 省项目完成时间。
仿真过程中尽可能把出现的所有信号都显示出来,这样的话更容易发现问题所在。
针对次题目,仿真过程中需要将十进制和二进制补码等相互转换才更容易观察出正误,如果采用自行判断的话,笔者目前还没有掌握方法——将十进制转化成二进制补码,因为计算机中多采用补码,所以待学习。
附:代码
alu_top.v

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/09/30 20:51:22
// Design Name: 
// Module Name: alu_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//module alu_top(input   [31:0]  Operand_X,Operand_Y,input   [2:0]   Opcode,input           clk,input           rst,input   [63:0]  Result1,Result2,Result3,input           Busy1,Busy2,output  [2:0]   Opc,output  [63:0]  Result);//reg     [31:0]  Operand_X,Operand_Y;reg   [63:0]  Result;wire [63:0] Result1,Result2,Result3;//reg     [2:0]   Opcode;//reg             clk,rst;wire            Buys1,Busy2;assign Opc = Opcode;add_sub as1(.Operand_X(Operand_X),.Operand_Y(Operand_Y),.Opcode(Opc),.Result(Result1));muler m1(.clk(clk),.rst(rst),.Opcode(Opc),.Operand_X(Operand_X),.Operand_Y(Operand_Y),.Busy(Busy1),.Cout(Cout),.Product(Result2));divider D1(.clk(clk),.rst(rst),.Opcode(Opc),.Operand_X(Operand_X),.Operand_Y(Operand_Y),.Busy(Busy2),.Result(Result3));// always @(posedge clk) begin//     Result <= 64'b1;// end// assign Result = (Opcode == 3'b010||Opcode==3'b001)?Result1://                     (Opcode == 3'b110)?Result2://                     (Opcode == 3'b111)?Result3://                     64'bZ;always @(Result3 or Result1 or Result2) beginif (Opcode == 3'b010||Opcode == 3'b001) Result <= Result1;else if (Busy1) Result <= Result2;else if (Busy2)Result <= Result3;else Result <= 64'bz;end
endmodule

add_sub.v

module add_sub (input [31:0]    Operand_X,Operand_Y,input [2:0]     Opcode,output[63:0]    Result
);wire Cout;reg [31:0] B;reg add_cin;wire [31:0] res;assign {Cout,res} = Operand_X+B+add_cin;always @(Operand_Y or Opcode) beginif (Opcode == 3'b010) B = ~Operand_Y;else if (Opcode == 3'b001)B = Operand_Y;endalways @(Opcode) beginif (Opcode == 3'b010)add_cin = 1'b1;else if (Opcode == 3'b001)add_cin = 1'b0;endreg c;assign Result ={{32{c}},res};always @(Cout or res) beginif ((Operand_X[31]^Operand_Y[31])==0) beginif (Opcode == 3'b001&&Cout) c = Operand_X[31];else c = res[31];end else beginif (Opcode == 3'b010&&Cout) c = Operand_X[31];else c = res[31];endend
endmodule

muler.v


module muler(input           rst,input           clk,input  [2:0]    Opcode,input  [31:0]   Operand_X,input  [31:0]   Operand_Y,output          Busy,output          Cout,output [63:0]   Product         
);reg         Busy,Cout;reg [64:0]  Result;reg [31:0]  Add_A,Add_B,Add_Result;reg         Add_Cin;reg [5:0]   Mul_Counter;reg [31:0]  Multiplicand,Operand_Y_inner;reg [1:0]   Opcode_inner;//00:add 0,01:sub multiplicand; 10:add multipicand;11:reservedalways @(Add_A or Add_B or Add_Cin) begin{Cout,Add_Result} = Add_A+Add_B+Add_Cin;endassign Product = Result[64:1];always @(posedge rst or posedge clk) beginif (rst) Mul_Counter <= 6'b0;else if (Opcode == 3'b110) Mul_Counter <= 6'b100000;else if (Busy) Mul_Counter <= Mul_Counter - 1;endalways @(posedge clk or posedge rst) beginif (rst)Busy <= 1'b0;else if (Opcode == 3'b110) Busy <= 1'b1;else if (Busy == 1'b1 && Mul_Counter == 6'b000000) beginBusy <= 1'b0;endendalways @(posedge clk or posedge rst) beginif (rst) Multiplicand <= 32'b0;else if (Opcode == 3'b110) Multiplicand <= Operand_Y;endalways @(posedge clk or posedge rst) beginif (rst) Result <= 65'b0;else if (Opcode == 3'b110) beginResult <= {32'b0,Operand_X,1'b0};end else beginResult <= {Add_Result[31],Add_Result,Result[32:1]};endendalways @(posedge rst or Result or Operand_X or Busy) beginif (rst)Add_A <= 32'b0;  else if (Busy) Add_A <= Result[64:33];elseAdd_A <= Operand_X;endalways @(Busy or Multiplicand or Operand_Y) beginif (Busy) Operand_Y_inner <= Multiplicand;else Operand_Y_inner <= Operand_Y;endalways @(Opcode_inner or Operand_Y_inner) beginif (Opcode_inner == 2'b10)Add_B <= Operand_Y_inner;else if (Opcode_inner == 2'b11)Add_B <= ~Operand_Y_inner;else Add_B <= 32'b0;endalways @(Opcode_inner) beginif (Opcode_inner == 2'b11)Add_Cin <= 1'b1;else Add_Cin <= 1'b0; endalways @(Busy or Result or Opcode) beginif (Busy) beginif (Result[1:0] == 2'b00 || Result[1:0] == 2'b11)Opcode_inner <= 2'b00;else if (Result[1:0] == 2'b01) Opcode_inner <= 2'b10;else Opcode_inner <= 2'b11;end else beginif (Opcode == 3'b100) Opcode_inner <= 2'b10;else if (Opcode == 3'b101) Opcode_inner <= 2'b11;else Opcode_inner <= 2'b00; endendendmodule

divider.v


module divider (input           rst,input           clk,input  [2:0]    Opcode,input  [31:0]   Operand_X,input  [31:0]   Operand_Y,output          Busy,// output          Cout,output [31:0]   Quotient,output [31:0]   Remainder,  output [63:0]   Result  
);wire[31:0]  Quotient,Remainder;reg [63:0]  result;//hi-remainder,lo-quotient;reg         Busy;reg [5:0]   Mul_Counter;reg [31:0]  mid_result;wire[63:0]  Result;assign Result = {Remainder,Quotient};//高位是余数,低位是商always @(posedge clk or posedge rst) beginif (rst) beginresult <= 64'b0; end else if (Opcode == 3'b111) beginresult <= {31'b0,Operand_X,1'b0};end else if (result[63:32] >= Operand_Y)result = {mid_result[30:0],result[31:0],1'b1};else result = {result[62:32],result[31:0],1'b0} ;endalways @(result) beginmid_result = result[63:32] - Operand_Y;endalways @(posedge clk or posedge rst) beginif (rst) beginBusy <= 1'b0;end else if (Opcode == 3'b111) beginBusy <= 1'b1;end else if (Mul_Counter == 6'b0)Busy <= 1'b0;endalways @(posedge rst or posedge clk) beginif (rst) Mul_Counter <= 6'b0;else if (Opcode == 3'b111) Mul_Counter <= 6'b100000;else if (Busy) Mul_Counter <= Mul_Counter - 1;endassign Remainder= (Operand_Y == 32'b0)?32'bz:{1'b0,result[63:33]};assign Quotient = result[31:0];
endmodule

alu_top.v

module alu_top_tb();reg     [31:0]  Operand_X,Operand_Y;wire    [63:0]  Result,Result1,Result2,Result3;reg     [2:0]   Opcode;wire     [2:0]   Opc;reg             clk,rst;reg     [63:0]  res1;wire            Busy1,Busy2;alu_top al_tp1(.Operand_X(Operand_X),.Operand_Y(Operand_Y),.Opcode(Opcode),.clk(clk),.rst(rst),.Opc(Opc),.Busy1(Busy1),.Busy2(Busy2),.Result1(Result1),.Result2(Result2),.Result3(Result3),.Result(Result));always begin#5;clk = ~clk;endinitial begin#5;//加法器Operand_X = 32'h0007; Operand_Y = 32'hfffffff4; #10;res1 = Result; //7+(-12)= -5;if (64'hffff_ffff_ffff_fffb == res1) begin$display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);end else begin$display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);end//乘法器#15;Operand_X = 32'b0000_0000_0000_0000_0000_0111_0110_0001;Operand_Y = 32'b0000_0000_0000_0000_1001_0111_0110_0001;#330;//除法器#15;Operand_X = 32'd18;Operand_Y = 32'h5;endalways beginOpcode = 3'b000;#5;Opcode = 3'd1;#10;//乘法器Opcode = 3'b000;#10;Opcode = 3'b110;#5;#5;Opcode = 3'b000;#325;//除法器Opcode = 3'b000;#10;Opcode = 3'b111;#5;#5;Opcode = 3'b000;#330;endinitial begin#5;#10;//乘法器clk = 1;rst = 0;#15;#330;//除法器clk = 1;rst = 0;#15;#330;endalways begin#5;#10;//乘法器#5;rst = 1;#5;rst = 0;#10;#325;//除法器#5;rst = 1;#5;rst = 0;#10;#330;end
endmodule

add_sub_tb.v

module add_sub_tb;// 定义信号reg  [31:0] Operand_X, Operand_Y;reg  [2:0]  Opcode;wire [63:0] Result;// 实例化被测试模块add_sub uut (.Operand_X(Operand_X),.Operand_Y(Operand_Y),.Opcode(Opcode),.Result(Result));reg [63:0] res,res1;// 初始化信号initial begin Operand_X = {$random}%{2^32};Operand_Y = {$random}%{2^32};Opcode = 3'd1;res = Operand_X+Operand_Y;#10;res1 = Result;if (res == res1) begin$display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);end else begin$display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);//$finish;end#10; Operand_X = 32'h0007; Operand_Y = 32'hfffffff4;Opcode = 3'd1;#10;res1 = Result; //7+(-12)= -5;if (64'hffff_ffff_ffff_fffb == res1) begin$display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);end else begin$display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);//$finish;end#10; Operand_X = 32'h7fff;Operand_Y = 32'h7fff;Opcode = 3'd1;#10;res1 = Result;if (64'h0000_FFFE == res1) begin$display("[time@%t]: x=%h,y=%h,Opcode=%h -------PASS",$time,Operand_X,Operand_Y,Opcode);end else begin$display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);//$finish;end#10;Operand_X = 32'hffff_fffd;//-3Operand_Y = 32'hffff_fff4;//-12Opcode = 3'd2;#10;res1 = Result; //-3-(-12) = 9if (64'h0000_0009 == res1) begin$display("[time@%t]: x=%h,y=%h,Opcode=%h-------PASS",$time,Operand_X,Operand_Y,Opcode);end else begin$display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);//$finish;end#10;Operand_X = 32'h8000_0000;//-2^31Operand_Y = 32'h0001;//1Opcode = 3'd2;#10;res1 = Result; //if (64'hffff_ffff_7fff_ffff == res1) begin$display("[time@%t]: x=%h,y=%h,Opcode=%h-------PASS",$time,Operand_X,Operand_Y,Opcode);end else begin$display("[time@%t]ERROR: x=%h,y=%h,Opcode=%h",$time,Operand_X,Operand_Y,Opcode);//$finish;end#20;$finish;endendmodule

tb_muler.v


module tb_muler( );reg         rst,clk;wire        Busy,Cout;  reg [2:0]   Opcode;wire[63:0]  Result;reg [31:0]  Operand_X,Operand_Y;muler m1(.rst(rst),.clk(clk),.Opcode(Opcode),.Operand_X(Operand_X),.Operand_Y(Operand_Y),.Busy(Busy),.Cout(Cout),.Product(Result));always begin#5; clk = ~clk;endinitial begin#15;Operand_X = 32'b0000_0000_0000_0000_0000_0111_0110_0001;Operand_Y = 32'b0000_0000_0000_0000_1001_0111_0110_0001;// Operand_X = 32'h6;// Operand_Y = 32'h2;#330;#15;Operand_X = $random;Operand_Y = $random;#330;#15;Operand_X = 32'b1000_0000_0000_0000_0000_0111_0110_0001;Operand_Y = 32'b1000_0000_0000_0000_1001_0111_0110_0001;#330;#15;Operand_X = 32'b0111_1111_1111_1111_1111_1111_1111_1111;Operand_Y = 32'b1000_0100_1001_0111_1110_1100_0111_1000;#330;endalways beginOpcode = 3'b000;#15;Opcode = 3'b110;#5;Opcode = 3'b000;#330;endinitial beginclk = 0;rst = 0;endalways begin#5;rst = 1;#5;rst = 0;#10;#330;end
endmodule

tb_divider.v


module tb_muler( );reg         rst,clk;wire        Busy,Cout;  reg [2:0]   Opcode;wire[63:0]  Result;reg [31:0]  Operand_X,Operand_Y;muler m1(.rst(rst),.clk(clk),.Opcode(Opcode),.Operand_X(Operand_X),.Operand_Y(Operand_Y),.Busy(Busy),.Cout(Cout),.Product(Result));always begin#5; clk = ~clk;endinitial begin#15;Operand_X = 32'b0000_0000_0000_0000_0000_0111_0110_0001;Operand_Y = 32'b0000_0000_0000_0000_1001_0111_0110_0001;// Operand_X = 32'h6;// Operand_Y = 32'h2;#330;#15;Operand_X = $random;Operand_Y = $random;#330;#15;Operand_X = 32'b1000_0000_0000_0000_0000_0111_0110_0001;Operand_Y = 32'b1000_0000_0000_0000_1001_0111_0110_0001;#330;#15;Operand_X = 32'b0111_1111_1111_1111_1111_1111_1111_1111;Operand_Y = 32'b1000_0100_1001_0111_1110_1100_0111_1000;#330;endalways beginOpcode = 3'b000;#15;Opcode = 3'b110;#5;Opcode = 3'b000;#330;endinitial beginclk = 0;rst = 0;endalways begin#5;rst = 1;#5;rst = 0;#10;#330;end
endmodule

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/147272.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【算法|贪心算法系列No.3】leetcode334. 递增的三元子序列

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

【MySQL入门到精通-黑马程序员】MySQL基础篇-DML

文章目录 前言一、DML-介绍二、DML-添加数据三、DML-修改数据四、DML-删除数据总结 前言 本专栏文章为观看黑马程序员《MySQL入门到精通》所做笔记&#xff0c;课程地址在这。如有侵权&#xff0c;立即删除。 一、DML-介绍 DML&#xff08;Data Manipulation Language&#xf…

湖南特色农产品销售系统APP /基于android的农产品销售系统/基于android的购物系统

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的APP应运而生&#xff0c;各行各业相继进入信息管理时代&#x…

25-多线程

多线程 线程(Thread)是一个程序内部的一条执行流程。 程序中如果有一条执行流程&#xff0c;那这个程序就是单线程的程序 多线程是指从软硬件上实现的多条执行流程的技术&#xff08;多条线程由CPU负责调度执行&#xff09;。 再例如&#xff1a;消息通信、淘宝、京东系统都离…

【Excel】快速提取某个符号前面的数据内容

【问题描述】 在使用excel整理数据过程中&#xff0c;经常与需要调整数据后&#xff0c;进行使用。 例如凭证导出后&#xff0c;科目列是包含科目编码和科目名称的。 但由于要将数据复制到其他的导入模板上使用&#xff0c;对应的模板只需要科目编码&#xff0c;不需要科目名称…

基于Java的校园失物招领平台设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

愚蠢的代码?某程序员强行编写了一段开发阶段无法调试的代码,大佬们快来救救他!

文章目录 一、开场白1. 程序员打赌的故事2. 目标&#xff1a; 尽量在不修改代码的情况下将springmvc框架以独立jar方式运行 二、出师不利方案一、Spring Web工程转Spring Boot方案二、引入内置服务器jetty其余备用方案 三、柳暗花明遇见jetty-runner测试验证准备工作:部署工作 …

Echarts 教程一

Echarts 教程一 可视化大屏幕适配方案可视化大屏幕布局方案Echart 图表通用配置部分解决方案1. titile2. tooltip3. xAxis / yAxis 常用配置4. legend5. grid6. series7.color Echarts API 使用全局echarts对象echarts实例对象 可视化大屏幕适配方案 rem flexible.js 关于flex…

基于 QT 实现一个 Ikun 专属桌面宠物

Step0、实现思路 想到的思路有两种&#xff1a; 1、使用 QT 的状态机模式&#xff0c;参考官网文档&#xff0c;这个模式的解耦最佳 2、使用原生 Wigets&#xff0c;将窗口设置为透明无框&#xff0c;循环播放桌面宠物的状态 本文采用第二种思路&#xff0c;实现一个极简版…

修炼k8s+flink+hdfs+dlink(一:安装flink)

一&#xff1a;standalone的ha环境部署。 创建目录&#xff0c;上传安装包。 mkdir /opt/app/flink 上传安装包到本目录。 tar -zxvf flink-1.13.6-bin-scala_2.12.tgz配置参数。 在flink-conf.yaml中添加zookeeper配置 jobmanager.rpc.address: node01 high-availability: …

Django基础入门操作 (Django-01)

一 背景介绍 Django是一个开源的 Web应用框架&#xff0c;由Python写成。采用了MTV的框架模式&#xff0c;它最初是被用来做CMS&#xff08;内容管理系统&#xff09;软件。 官方中文文档&#xff1a;Django 文档 | Django 文档 | Django 应用&#xff1a;做内容管理系统(新…

selenium下载安装 -- 使用谷歌驱动碰到的问题

安装教程参考: http://c.biancheng.net/python_spider/selenium.html 1. 谷歌浏览器和谷歌驱动版本要对应(但是最新版本谷歌对应的驱动是没有的,因此要下载谷歌历史其他版本): 谷歌浏览器历史版本下载: https://www.chromedownloads.net/chrome64win/谷歌浏览器驱动下载: http:…

spark SQL 任务参数调优1

1.背景 要了解spark参数调优&#xff0c;首先需要清楚一部分背景资料Spark SQL的执行原理&#xff0c;方便理解各种参数对任务的具体影响。 一条SQL语句生成执行引擎可识别的程序&#xff0c;解析&#xff08;Parser&#xff09;、优化&#xff08;Optimizer&#xff09;、执行…

gwas数据根据eaf Z 和N 求beta和se

https://www.nature.com/articles/s41590-023-01588-w#Sec10

C++基础_Day02

文章目录 四、流程控制语句4.1 选择结构4.1.1 if语句 4.1.2 三目运算符4.1.3 switch语句注意事项 4.1.4 if和switch的区别【CHAT】4.2 循环结构4.2.1 while循环语句4.2.2 do...while循环语句 4.2.3 for循环语句九九乘法表 4.3 跳转语句4.3.1 break语句4.3.2 continue语句4.3.3 …

Nat. Commun. | 大规模高分辨单光子成像

本文由论文作者团队(课题组)投稿 单光子雪崩二极管(Single Photon Avalanche Diode,简称SPAD)阵列因其极佳的单光子灵敏度而受到广泛关注,已广泛应用于量子通信与计算、荧光寿命成像、时间飞行成像等各个领域。与同样具有较高灵敏度的EMCCD和sCMOS相比,SPAD阵列能够在极…

macOS使用官方安装包安装python

新手程序员可能想知道如何在 Mac 上正确安装 Python&#xff0c;这里介绍在 macOS 上安装 Python 的方法。 操作步骤 1.从 Python 官方网站 (python.org) 下载最新的 Python 版本. 单击 macOS 链接并选择最新的 Python 版本。 2.下载完成后&#xff0c;双击包开始安装Python…

【iptables 实战】05 iptables设置网络转发实验

一、网络架构 实验效果&#xff0c;通过机器B的转发功能&#xff0c;将机器A的报文转发到机器C 本实验准备三台机器分别配置如下网络 机器A ip:192.168.56.104 机器C ip:10.1.0.10 机器B 两张网卡&#xff0c;分别的ip是192.168.56.106和10.1.0.11 如图所示 如下图所示 二、…

vertx的学习总结2

一、什么是verticle verticle是vertx的基本单元&#xff0c;其作用就是封装用于处理事件的技术功能单元 &#xff08;如果不能理解&#xff0c;到后面的实战就可以理解了&#xff09; 二、写一个verticle 1. 引入依赖&#xff08;这里用的是gradle&#xff0c;不会吧&#…

ChatGPT多模态升级,支持图片和语音,体验如何?

一、前言 9 月 25 日&#xff0c;ChatGPT 多模态增加了新的语音功能和图像功能。这些功能提供了一种新的、更直观的界面&#xff0c;允许我们与 ChatGPT 进行语音对话或展示我们正在谈论的内容。 ChatGPT 现在可以看、听、和说话了&#xff0c;而不单单是一个文本驱动的工具了。…