Verilog 实现一个简单的ALU

mac2024-09-29  64

简介: 用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位,其中最高位为符号位。

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

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

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

由以上可知:

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

【重要】

位宽为N的二进制数能够表示的有符号整数的范围为[-2^(n - 1), 2^(n - 1) - 1]。 例如N = 8,即一个8位二进制数能够表示的有符号整数的范围为[-2^7, 2^7 - 1] = [-128, 127]。位宽为N的二进制数能够表示的无符号整数的范围为[0, 2^n - 1]。 例如N = 8,即一个8位二进制数能够表示的无符号整数的范围为[0, 2^8 - 1] = [0, 255]。
最新回复(0)