Verilog实现⼀个简单的ALU
简介:
⽤Verilog实现⼀个简单的ALU,使其具有进⾏N位有符号数的加法、减法及⼤⼩⽐较运算的功能。本篇⽂章实现的ALU以N = 8为例,想要实现其他位宽的数据运算,可以通过修改N的值来实现。
代码实现:
/*----------------------------------------------------------------
Filename: alu.v
Function: 设计⼀个N位的ALU(可实现两个N位有符号整数加减⽐较运算)
Author: Zhang Kaizhou
thekillers
Date: 2019-10-31 20:40:42
-----------------------------------------------------------------*/
module alu(ena, clk, opcode, data1, data2, y);
//定义alu位宽
parameter N = 8; //输⼊范围[-128, 127]
//定义输⼊输出端⼝
alteration
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@(podge clk)
begin
if(ena)
begin
cax(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;
endca世故的意思
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
//设置电路初始状态
someone like you歌词翻译#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
//第⼆组测试
queenie什么意思#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]。
matchbox
例如N = 8,即⼀个8位⼆进制数能够表⽰的⽆符号整数的范围为[0, 2^8 - 1] = [0, 255]。