Verilog 加法器和减法器(5)

      前面二进制加法运算,我们并没有提操作数是有符号数,还是无符号数。其实前面的二进制加法对于有符号数和无符号数都成立。比如前面的8位二进制加法运算,第一张图我们选radix是unsigned,表示无符号加法,第二张图我们选radix是decimal,表示有符号数,从图中可知结果都是正确的。对于有符号数来说,负数默认是补码的形式存在。假设二进制数是n位,则对于无符号数来说,表示范围是0~(2^n) -1 ,对于有符号数,表示的范围是-(2^(n-1))~2^(n-1) - 1


image


image

对于有符号数来说,通常还要知道加法结果数据是否溢出。有一种直观的方法判断结果是否溢出,就是如果两个加数有相同的符号,但是它们的和与它们有不同的符号,则产生溢出。假设有n位有符号二进制数x,y,它们的和为s,则它们和溢出判断公式是 overflow = xn_1&yn-1&~sn-1 + ~xn_1&~yn-1&sn-1

修改后的有符号数加法代码为:

复制代码
module addern_signed(x, y, s, cout, overflow);
  parameter n=8;
  input [n-1:0] x;
  input [n-1:0] y;
  output reg[n-1:0] s;
  output reg cout;
  output reg overflow;
  reg [n:0] c;
  integer k;


  always @(x,y) begin
    c[0] = 1'b0;
	 for(k = 0; k < n; k = k + 1) begin
	   s[k] = x[k]^y[k]^c[k];
		c[k+1] = (x[k]&y[k])|(x[k]&c[k])|(y[k]&c[k]);
	 end
	 cout = c[n];
	 overflow = (x[n-1]&y[n-1]&~s[n-1])|(~x[n-1]&~y[n-1]&s[n-1]);
	end

endmodule
复制代码
复制代码
module addern_signed(x, y, s, cout, overflow);
  parameter n=8;
  input [n-1:0] x;
  input [n-1:0] y;
  output [n-1:0] s;
  output  cout;
  output  overflow;
  integer k;

  assign {cout, s} = x + y ;
  assign overflow = (x[n-1]&y[n-1]&~s[n-1])|(~x[n-1]&~y[n-1]&s[n-1]);

 endmodule
复制代码


修改后的testbench文件为:

复制代码
`timescale 1ns/1ns
`define clock_period 20

module addern_signed_tb;
  reg [7:0] x,y;

  wire cout;
  wire [7:0] s;
  reg clk;

  addern_signed #(.n(8)) addern_signed_0(
						.x(x),
						.y(y),
						.s(s),
						.cout(cout)
                  );

  initial clk = 0;
  always #(`clock_period/2) clk = ~clk;

  initial begin
     x = 0;
     repeat(20)
	    #(`clock_period) x = $random;

  end

  initial begin
     y = 0;
     repeat(20)
	    #(`clock_period) y = $random;

  end


  initial begin
     #(`clock_period*20)
	  $stop;
  end


endmodule
复制代码


功能验证的波形图如下:


image

对于有符号数的减法,我们也可以用加法来做,但是对于减数,我们要做以下变化,如果减数为正数,则变其为补码表示的负数,如果其为补码表示的负数,则把它转化为正数。

assign y1 = y[n-1]?(~{y[n-1:0]}+1'b1):(~{1'b0,y[n-2:0]}+1'b1);

复制代码
module subn_signed(x, y, s, cout, overflow);
  parameter n=8;
  input [n-1:0] x;
  input [n-1:0] y;
  output reg[n-1:0] s;
  output reg cout;
  output reg overflow;
  wire [n-1:0] y1;
  reg [n:0] c;
  integer k;

  //y commplement, if y=0, to negative with commplement,if y=1, to positive number. 
  assign y1 = y[n-1]?(~{y[n-1:0]}+1'b1):(~{1'b0,y[n-2:0]}+1'b1);

  always @(x,y1) begin
    c[0] = 1'b0;
	 for(k = 0; k < n; k = k + 1) begin
	   s[k] = x[k]^y1[k]^c[k];
		c[k+1] = (x[k]&y1[k])|(x[k]&c[k])|(y1[k]&c[k]);
	 end
	 cout = c[n];
	 overflow = (x[n-1]&y1[n-1]&~s[n-1])|(~x[n-1]&~y1[n-1]&s[n-1]);
	end

endmodule
复制代码

复制代码
module subn_signed(x, y, s, cout, overflow);
  parameter n=8;
  input [n-1:0] x;
  input [n-1:0] y;
  output [n-1:0] s;
  output  cout;
  output  overflow;
  wire [n-1:0] y1;
  integer k;
  //y commplement, if y=0, to negative with commplement,if y=1, to positive number. 
  assign y1 = y[n-1]?(~{y[n-1:0]}+1'b1):(~{1'b0,y[n-2:0]}+1'b1);
  assign {cout, s} = x + y1 ;
  assign overflow = (x[n-1]&y1[n-1]&~s[n-1])|(~x[n-1]&~y1[n-1]&s[n-1]);

 endmodule
复制代码

testbench代码为:

复制代码
`timescale 1ns/1ns
`define clock_period 20

module subn_signed_tb;
  reg [7:0] x,y;

  wire cout;
  wire overflow;
  wire [7:0] s;
  reg clk;

  subn_signed #(.n(8)) subn_signed_0(
						.x(x),
						.y(y),
						.s(s),
						.cout(cout),
						.overflow(overflow)
                  );

  initial clk = 0;
  always #(`clock_period/2) clk = ~clk;

  initial begin
     x = 0;
     repeat(20)
	    #(`clock_period) x = $random;

  end

  initial begin
     y = 0;
     repeat(20)
	    #(`clock_period) y = $random;

  end


  initial begin
     #(`clock_period*20)
	  $stop;
  end


endmodule
复制代码

从功能验证的波形图中,我们可以看到见过是正确的。


image




































posted on   迈克老狼2012  阅读(5153)  评论(0编辑  收藏  举报

编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示