加法器与减法器verilog


减法器中也有类似于半减器、全减器、串行借位减法器之类的,但是为了实现简单和复用代码,计划采用加法器来实现减法器。

无符号加法器

如果两个数都是无符号的,那么可以直接相加,需要有一位作为进位。

有符号加法器

以4bit有符号数为例

  • 大于等于0的数的情况同无符号数一致,最高位保持为0

  • 负数与正数相加,负数的绝对值大于正数
    例如-8+7=1000+0111=01111,计算结果错误(符号位舍去后无误)
    负数的绝对值等于正数
    -7+7=1001+0111=0=10000,计算结果错误(进位舍去后无误)
    负数的绝对值小于正数
    -6+7=1010+0111=0=10001,计算结果错误(进位舍去后无误)

    若是保持输出为4位,则输出结果无误,但是为了兼容无符号加法器,不能舍去。

    处理思路是进行扩位。将4bit扩大到5bit,进位丢弃
    -8+7=11000+00111=11111 correct
    -7+7=11001+00111=00000 correct
    -6+7=11010+00111=00001 correct
    丢掉进位以后,最高位就是符号位。看似数据的范围变小了,但是本来结果就需要5位表达,所以在相加之前扩位对结果没有影响。

  • 负数与负数相加
    -8+(-8)=11000+11000=10000
    -8+(-7)=11000+11001=10001
    结果完全正确。

有符号减法器

继承上面的思想,再运算之前先进行扩位,即,复制最高位

  • 正数减去正数
    7-6=7+(-6)=00111+11010=00001
    可以看到转换为正数加上负数以后,计算十分简单

    问题是如何进行转换
    6=00110 取反11001 加一11010,似乎没问题
    7=00111 取反11000 加一11001,也没毛病

  • 正数减去负数
    7-(-8)=7+8=00111+01000=01111

    问题是如何进行转换
    -8=11000 取反00111 加一01000,没毛病
    -7=11001 取反00110 加一00111,没毛病

    加一的操作可以当做进位

  • 负数减去负数
    -8-(-8)=-8+8=11000+01000=00000
    -8-(-7)=-8+7=11000+00111=11111
    -7-(-8)=-7+8=11001+01000=00001
    么得问题

  • 负数减去正数
    -8-7=-8+(-7)=11000+11001=10001
    -8-8=-8+(-8)=11000+11000=10000
    -6-7=-6+(-7)=11010+11001=10011
    么得问题

    所有情况都已经推理完毕,下面就是代码部分了

    上面废话太多。事实上,因为有符号加法器是完全没有问题的,所以只要能够顺利把减法运算换成加法运算就成功了一半。需要注意的是极端情况的-8,因为运算中没有加8的情况

加减法器

基于串行进位加法器https://blog.csdn.net/I_LOVE_MCU/article/details/126196302
超前进位加法器目前不支持任意位数

module adder_substractor #(
	parameter WIDTH = 4
)(
	input [WIDTH-1:0] 	in1,
	input [WIDTH-1:0] 	in2,
	input 				add_sub,
	output	[WIDTH:0]	sum
);
wire [WIDTH:0] in1_exp;
wire [WIDTH:0] in2_exp;
wire cin;

assign in1_exp = {in1[WIDTH-1], in1};
assign in2_exp = add_sub? {in2[WIDTH-1], in2}: ~{in2[WIDTH-1], in2};
assign cin = ~add_sub;

// 因为对输入进行了扩位,所以WIDTH需要加1,在输出的时候会被截位,但对结果无影响
serial_adder #(
    .WIDTH ( WIDTH+1 ))	
 u_lookahead_carry_adder (
    .in1                     ( in1_exp   ),
    .in2                     ( in2_exp   ),
    .cin                     ( cin   ),

    .sum                     ( sum   )
);

endmodule


TB

 `timescale  1ns / 1ps

module tb_adder_substractor;

// adder_substractor Parameters
parameter PERIOD = 10;
parameter WIDTH  = 4;

// adder_substractor Inputs
reg   [WIDTH-1:0]  in1                     = 0 ;
reg   [WIDTH-1:0]  in2                     = 0 ;
reg   add_sub                              = 0 ;

// adder_substractor Outputs
wire  [WIDTH:0]  sum                       ;


// initial
// begin
//     forever #(PERIOD/2)  clk=~clk;
// end

// initial
// begin
//     #(PERIOD*2) rst_n  =  1;
// end

adder_substractor #(
    .WIDTH ( WIDTH ))
 u_adder_substractor (
    .in1                     ( in1      [WIDTH-1:0] ),
    .in2                     ( in2      [WIDTH-1:0] ),
    .add_sub                 ( add_sub              ),

    .sum                     ( sum      [WIDTH:0]   )
);

initial
begin
	in1 = -7;
	in2 = -7;
	add_sub = 1;
	#10;
	in1 = -7;
	in2 = -7;
	add_sub = 0;
	#10;
	in1 = -7;
	in2 = 8;
	add_sub = 0;
	#10;
	in1 = -7;
	in2 = 8;
	add_sub = 1;
	#10;
	in1 = 8;
	in2 = 8;
	add_sub = 0;
	#10;
	in1 = 8;
	in2 = 8;
	add_sub = 1;
	#10;
	in1 = 8;
	in2 = -7;
	add_sub = 0;
	#10;
	in1 = 8;
	in2 = -7;
	add_sub = 1;
	#10;

    // $finish;
end

endmodule

在这里插入图片描述

Reference

浮点数的加减法器
https://www.cnblogs.com/mikewolf2002/p/10095995.html

  • 3
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值