Verilog 实现一个简单的ALU

简介:
用Verilog实现一个简单的ALU,使其具有进行N位有符号数的加法、减法及大小比较运算的功能。本篇文章实现的ALU以N = 8为例,想要实现其他位宽的数据运算,可以通过修改N的值来实现。
代码实现:

/*----------------------------------------------------------------
Filename: alu.v
Function: 设计一个N位的ALU(可实现两个N位有符号整数加 减 比较运算)
Author: Zhang Kaizhou
Date: 2019-10-31 20:40:42
-----------------------------------------------------------------*/
module alu(ena, clk, opcode, data1, data2, y);
	//定义alu位宽
	parameter N = 8; //输入范围[-128, 127]
	
	//定义输入输出端口
	input ena, clk;
	input [1 : 0] opcode;
	input signed [N - 1 : 0] data1, data2; //输入有符号整数范围为[-128, 127] 
	output signed [N : 0] y; //输出范围有符号整数范围为[-255, 255]
	
	//内部寄存器定义
	reg signed [N : 0] y;
	
	//状态编码
	parameter ADD = 2'b00, SUB = 2'b01, COMPARE = 2'b10;
	
	//逻辑实现
	always@(posedge clk)
	begin
		if(ena)
		begin
			casex(opcode)
				ADD: y <= data1 + data2; //实现有符号整数加运算
				SUB: y <= data1 - data2; //实现有符号数减运算
				COMPARE: y <= (data1 > data2) ? 1 : ((data1 == data2) ? 0 : 2); //data1 = data2 输出0; data1 > data2 输出1; data1 < data2 输出2;
				default: y <= 0;
			endcase
		end
	end
endmodule
/*------------------------------------
Filename: alu_t.v
Function: 测试alu模块的逻辑功能
Author: Zhang Kaizhou
Date: 2019-10-31 20:42:38
------------------------------------*/
`timescale 1ns/1ns
`define half_period 5
module alu_t(y);
	//alu位宽定义
	parameter N = 8;
	
	//输出端口定义
	output signed [N : 0] y;
	
	//寄存器及连线定义
	reg ena, clk;
	reg [1 : 0] opcode;
	reg signed [N - 1 : 0] data1, data2;
	
	//产生测试信号
	initial
	begin
		//设置电路初始状态
		#10 clk = 0; ena = 0; opcode = 2'b00;
			data1 = 8'd0; data2 = 8'd0;
		#10 ena = 1;
		
		//第一组测试
		#10 data1 = 8'd8; data2 = 8'd5; //y = 8 + 5 = 13
		#20 opcode = 2'b01; // y = 8 - 5 = 3
		#20 opcode = 2'b10; // 8 > 5 y = 1
		
		//第二组测试
		#10 data1 = 8'd127; data2 = 8'd127; opcode = 2'b00; //y = 127 + 127 = 254
		#20 opcode = 2'b01; //y = 127 - 127 = 0
		#20 opcode = 2'b10; // 127 == 127 y = 0
		
		//第三组测试
		#10 data1 = -8'd128; data2 = -8'd128; opcode = 2'b00; //y = -128 + -128 = -256
		#20 opcode = 2'b01; //y = -128 - (-128) = 0
		#20 opcode = 2'b10; // -128 == -128 y = 0
		
		//第四组测试
		#10 data1 = -8'd52; data2 = 8'd51; opcode = 2'b00; //y = -52 + 51 = -1
		#20 opcode = 2'b01; //y = -52 - 51 = -103
		#20 opcode = 2'b10; //-52 < 51 y = 2
		
		#100 $stop;
	end
	
	//产生时钟
	always #`half_period clk = ~clk;
	
	//实例化
	alu m0(.ena(ena), .clk(clk), .opcode(opcode), .data1(data1), .data2(data2), .y(y));
endmodule

ModelSim仿真结果:
在这里插入图片描述
总结:
由上面的仿真结果可知,本次设计的ALU的逻辑功能达到的设计预期。
本次设计的关键点在于通过 “singed"的关键字定义输入输出数据为有符号的整数。这样使得加减运算变得十分简单,可以直接采用”+" "-"符号来实现相关运算,从而免去了自己设计有符号加法器的繁琐过程。
附注:
关于原码 反码 补码转换相关问题的总结:
在数字电路中,运算基本单元为0 1 代码构成的二进制数。在计算机存储器中,数字是以其二进制补码的形式存放的。
带符号数的二进制表示是以 符号位 + 数值位表示的。正数符号位为0,负数符号位为1。
例如:假定二进制数长度为8位,其中最高位为符号位。

  1. 原码表示法:
    5 = 0000 0101B -5 = 1000 0101B

  2. 反码表示法:
    5 = 0000 0101B -5 = 1111 1010B

  3. 补码表示法:
    5 = 0000 0101B -5 = 1111 1011B

由以上可知:

  1. 正数的原码,反码,补码均相同。
  2. 负数的反码 = 原码各位取反(除符号位)。
  3. 负数的补码 = 反码 + 1。
  4. +0的补码 = -0的补码 = 0000 0000B

【重要】

  1. 位宽为N的二进制数能够表示的有符号整数的范围为[-2^(n - 1), 2^(n - 1) - 1]。
    例如N = 8,即一个8位二进制数能够表示的有符号整数的范围为[-2^7, 2^7 - 1] = [-128, 127]。
  2. 位宽为N的二进制数能够表示的无符号整数的范围为[0, 2^n - 1]。
    例如N = 8,即一个8位二进制数能够表示的无符号整数的范围为[0, 2^8 - 1] = [0, 255]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值