运算器——Verilog实现

运算器

本运算器针对32位数的补码运算,以加法器为核心实现加、减、乘、除等运算。

基本模块

  1. 加/减法器
  2. 乘法器
  3. 除法器

加/减法器

源代码

module add_sub(
input [31:0]Operand_X,
input [31:0]Operand_Y,
input Opcode,
output [31:0]Result,
output Cout
);

reg [31:0]B;

assign {Cout,Result} = Operand_X + B + Opcode;

always@(Operand_Y or Opcode)
	if(Opcode)
		B = ~Operand_Y;
	else
		B = Operand_Y;
endmodule

原理

  • 两个数相加,即为补码直接相加;
  • 两个数相减,为被减数加上减数的相反数(各位取反,末位加1)。

乘法器

源代码

module alu(rst,clk,Opcode,Operand_X,Operand_Y,Busy,result,Cout);
input rst,clk;
input [2:0]Opcode;
/*Opcode 100:Add,101:Sub,110:Mul,111:reserved*/
input [31:0]Operand_X,Operand_Y;
output Busy,Cout;
output [63:0]result;

reg Busy,Cout;
reg [64:0]Result;
reg [31:0]Add_A,Add_B,Add_Result;
reg Add_Cin;
reg [4:0]Mul_Counter;
reg [31:0]Multiplicand,Operand_Y_inner;
reg [1:0]Opcode_inner;
/*00:add 0,01:sub multiplicand,10:multiplicand,11:reserved*/
always@(Add_A,Add_B,Add_Cin)
{Cout,Add_Result} = Add_A+Add_B+Add_Cin;

always@(posedge rst,posedge clk)
begin
	if(rst)
		Mul_Counter <= 5'b0;
	else if(Opcode == 3'b110 && Busy == 1'b0)
		Mul_Counter <= 5'b11111;//
	else if(Busy)
		Mul_Counter <= Mul_Counter - 1; 
end

always@(posedge rst, posedge clk)
begin
	if(rst)
		Busy <= 1'b0;
	else if(Opcode == 3'b110 && Busy == 1'b0)
		Busy <= 1'b1;
	else if(Busy == 1'b1 && Mul_Counter == 5'b0)
		Busy <= 1'b0;
end

always@(posedge rst, posedge clk)
begin
	if(rst)
		Multiplicand <= 32'b0;
	else if(Opcode == 3'b110 && Busy == 1'b0)
		Multiplicand <= Operand_Y;
end

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

always@(Result)
begin
	if(Busy)
		Add_A <= Result[64:33];
	else
		Add_A <= Operand_X;
end

always@(Busy, Multiplicand, Operand_Y)
begin
	if(Busy)
		Operand_Y_inner <= Multiplicand;
	else
		Operand_Y_inner <= Operand_Y;
end

always@(Opcode_inner, Operand_Y_inner)
begin
	if(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;
end

always@(Opcode_inner)
begin
	if(Opcode_inner == 2'b11)
		Add_Cin = 1'b1;
	else
		Add_Cin = 1'b0;
end

always@(Busy, Result, Opcode)
begin
	if(Busy)
	begin
		if(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
	begin
		if(Opcode == 3'b100)
			Opcode_inner <= 2'b10;
		else if(Opcode == 3'b101)
			Opcode_inner <= 2'b11;
		else
			Opcode_inner <= 2'b00;
	end
end 

assign result = Result[64:1];
endmodule

原理

使用booth乘法的基本原理,根据乘积寄存器的后两位,选择适当的数放入加法器,计算出结果后,将其放在高32位上,再右移一位,如此往复32次;

除法器

源代码

module divider(rst,clk,Opcode,Operand_X,Operand_Y,Busy,Result,Cout);
input rst;
input clk;
input [2:0]Opcode;
input [31:0]Operand_X;
input [31:0]Operand_Y;
output reg Busy;
output [31:0]Result;
output reg Cout;

reg [31:0]Add_A,Add_B,Add_Result;
reg Add_Cin;
reg [4:0]Div_Counter;
reg [63:0]Remainder;

always@(Add_A,Add_B,Add_Cin)
{Cout,Add_Result} = Add_A+Add_B+Add_Cin;

always@(posedge rst,posedge clk)
begin
	if(rst)
		Div_Counter <= 5'b0;
	else if(Opcode == 3'b111 && Busy == 1'b0)
		Div_Counter <= 5'b11111;
	else if(Busy)
		Div_Counter <= Div_Counter - 1; 
end

always@(posedge rst, posedge clk)
begin
	if(rst)
		Busy <= 1'b0;
	else if(Opcode == 3'b111 && Busy == 1'b0)
		Busy <= 1'b1;
	else if(Busy == 1'b1 && Div_Counter == 5'b0)
		Busy <= 1'b0;
end

always@(posedge rst, posedge clk)
begin
	if(rst)
		Remainder <= 64'b0;
	else if(Opcode == 3'b111 && Busy == 1'b0)
	begin
		if(Operand_X[31])
			Remainder[32:1] <= ~Operand_X + 1;
		else
			Remainder[32:1] <= Operand_X;
	end
	else
		begin
			if(Add_Result[31] == 0)
				Remainder <= {Add_Result[30:0],Remainder[31:0],1'b1};
			else
				Remainder <= {Remainder[62:0],1'b0};
		end
end

always@(Result)
begin
	if(Busy)
		Add_A <= Remainder[63:32];
	else
		Add_A <= Operand_X;
end

always@(Operand_Y)
begin
	if(!Operand_Y[31])
	begin
		Add_B = ~Operand_Y;
		Add_Cin = 1'b1;
	end
	else
	begin
		Add_B = Operand_Y;
		Add_Cin = 1'b0;
	end
end

assign Result = (Operand_X[31] ^ Operand_Y[31]) ? ~Remainder[31:0] + 1:Remainder[31:0];

endmodule

原理

补码除法运算运用恢复余数法,其执行流程如下:

  1. 将被除数与除数都转换成对应的无符号数;
  2. 使用恢复余数法,每次检测到高32位能够减去除数时,减去除数,左移一位,商1;否则恢复原来的余数寄存器,左移一位,商0;
  3. 用计数器记录到32位,即为最终的结果。
  • 5
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
实验一 简单组合逻辑电路的设计 一 实验要求 用verilog HDL语言描写出简单的一位数据比较及其测试程序; 用测试程序对比较进行波形仿真测试;画出仿真波形; 总结实验步骤和实验结果。 二 实验原理与内容 这是一个可综合的数据比较,很容易看出它的功能是比较数据a与数据b,如果两个数据相同,则给出结果1,否则给出结果0。在Verilog HDL中,描述组合逻辑时常使用assign结构。注意equal=(a==b)?1:0,这是一种在组合逻辑实现分支判断时常使用的格式。 模块源代码 测试模块: Verilog-实验报告全文共8页,当前为第1页。 Verilog-实验报告全文共8页,当前为第1页。 波形图: 四 结实验步骤和实验结果 由图可看出,每当输入的电位值不同时输出为0,这与实验要求一致,相同时输出为1,故此程序是可行的。 Verilog-实验报告全文共8页,当前为第2页。 Verilog-实验报告全文共8页,当前为第2页。 实验三 在verilog HDL中使用函数 一 实验要求 掌握函数在模块中的使用 用测试程序进行波形仿真测试;画出仿真波形 总结实验步骤和实验结果 二 实验原理与内容 与一般的程序设计语言一样;verilog HDL也可以使用函数已是应对不同变量采取同一运算的操作。verilog HDL函数在综合时被理解成具有独立运算功能的电路,每调用一次函数相当于改变这部分电路的输入以得到相应的计算结果。 模块源代码: module ex3(clk,n,result,reset); output[31:0] result; input[3:0] n; input reset,clk; reg[31:0] result; always @(posedge clk) begin if(!reset)result <= 0; else begin result <= n*factorial(n)/((n*2)+1); end end function[31:0] factorial; input[3:0] operand; reg[3:0] index; begin factorial = operand ? 1:0; for(index = 2;index <= operand;index = index+1) factorial = index*factorial; end endfunction endmodule `timescale 1ns/100ps `define clk_cycle 50 module ex3_t(); reg[3:0] n,i; Verilog-实验报告全文共8页,当前为第3页。 reg reset,clk; Verilog-实验报告全文共8页,当前为第3页。 wire[31:0] result; initial begin n=0; reset=1; clk=0; #100 reset=0; #100 reset = 1; for(i=0;i <= 15;i=i+1) begin #200 n=i; end #100 $stop; end always #`clk_cycle clk =~ clk; ex3 ex30(.clk(clk),.n(n),.result(result),.reset(reset)); always @(negedge clk) $display("at n=%d,result=%d",n,result); endmodule 波形图 : Verilog-实验报告全文共8页,当前为第4页。 Verilog-实验报告全文共8页,当前为第4页。 实验四 在verilog HDL中使用任务 一 实验要求 掌握任务在结构化verilog HDL设计中的应用 用测试程序进行波形仿真测试;画出仿真波形 总结实验步骤和实验结果 二 实验原理与内容 仅有函数并不能满足verilog HDL中的运算需求。当我们希望能够将一些信号进行运算并输出多个结果时,采用函数结构就显得非常不方便,而任务结构在这方面的优势十分的突出。任务本身并不返回计算值,但是它通过类似C语言中形参与实参的数据交换,非常快捷的实现运算结果的调用。 模块源代码: output[3:0] ra,rb,rc,rd; input[3:0] a,b,c,d; reg[3:0] ra,rb,rc,rd; reg[3:0] va,vb,vc,vd; always @(a or b or c or d) begin {va,vb,vc,vd} = {a,b,c,d}; sort2(va,vc); sort2(vb,vd); sort2(va,vb); sort2(vc,vd); sort2(vb,vc); {ra,r
MATLAB与FPGA数字信号处理系列(6)——verilog实现并行FIR滤波。在数字信号处理中,FIR滤波是一种常用的滤波类型,它可以通过对信号进行加权求和的方式来实现滤波操作。Verilog是一种硬件描述语言,可以用于FPGA的设计与实现。在这个系列中,我们将介绍如何使用Verilog语言在FPGA上实现并行FIR滤波。 在Verilog实现并行FIR滤波的关键是将滤波操作并行化,以提高滤波的运算速度。首先,我们需要将滤波的系数转化为二进制形式,并存储在FPGA的寄存中。然后,我们可以使用Verilog语言编写并行的加法和乘法模块,来对输入信号和滤波系数进行并行运算。最后,将并行运算的结果进行累加,即可得到滤波的输出信号。 在MATLAB中,我们可以通过FIR滤波的设计工具箱来设计滤波的系数,并将其导出为二进制文件。然后,我们可以使用Verilog语言编写FIR滤波的硬件描述,包括并行加法、乘法和寄存操作等。最后,我们可以使用FPGA开发工具将Verilog代码综合为FPGA可执行的比特流文件,用于加载到FPGA中进行并行FIR滤波实现。 通过这个方式,我们可以在FPGA上实现高性能的并行FIR滤波,以满足对于实时性能要求较高的数字信号处理应用。这种并行实现方式能够充分利用FPGA的并行计算能力,提高FIR滤波的运算速度,同时也为数字信号处理系统的设计与实现提供了一种有效的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alfred young

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值