本文基于《计算机组成与设计硬件/软件接口 RISC-V版 原书第5版》 (戴维 A.帕特森_ 约翰 L.亨尼斯)中关于ALU设计部分的verilog实现
采用书中适应于RISC-V架构的64位ALU设计,主要完成与、或、或非等逻辑运算、加法减法等基本算术运算以及小于等于置位slt指令和条件跳转指令bne指令的实现。
//------------------------------适应RISC-V的1位ALU(非最高位ALU)---------------------------------
module ALU_1bit(
input a,
input b,
input less,
input Ainvert,
input Binvert,
input CarryIn,
input [1:0] Operation,
output reg Result,
output CarryOut
);
wire a_n,b_n;
assign a_n=(Ainvert==0)?a:~a;
assign b_n=(Binvert==0)?b:~b;
assign CarryOut=(a_n&b_n)|(a_n&CarryIn)|(b_n&CarryIn);
always@(*)
begin
case (Operation)
2'b00:Result=a_n & b_n;
2'b01:Result=a_n | b_n;
2'b10:Result=a_n^b_n^CarryIn;
2'b11:Result=less;
endcase
end
endmodule
//-----------------------------------------------------------------------------------------------
其中溢出检测单元的设计如下:
溢出检测在进行加法和减法运算时被使用,一共只有4种情况会发生溢出:
Overflow=a^Set&((~a^b)^Binvert)
//--------------------------------适应RISC-V的1位ALU(最高位ALU)---------------------------------
module ALU_Hbit(
input a,
input b,
input less,
input Ainvert,
input Binvert,
input CarryIn,
input [1:0] Operation,
output reg Result,
output Set,
output Overflow
);
wire a_n,b_n;
assign a_n=(Ainvert==0)?a:~a;
assign b_n=(Binvert==0)?b:~b;
assign Set=a_n^b_n^CarryIn;
always@(*)
begin
case (Operation)
2'b00:Result=a_n & b_n;
2'b01:Result=a_n | b_n;
2'b10:Result=Set;
2'b11:Result=less;
default:Result=0;
endcase
end
//Overflow 溢出检测逻辑
assign Overflow=a^Set&((~a^b)^Binvert);
endmodule
//-----------------------------------------------------------------------------------------------
书上给出的上图结构在减法溢出时无法实现slt小于比较置位,但仿真结果发现:当减法溢出时,ALU63的Set位取反即为对应结果,故只需要在ALU63的Set位和Overflow位异或之后传递到ALU0的less位输入即可实现。
//----------------------------------------64位串行ALU--------------------------------------------
module ALU_RISC_V(
input [63:0] ALU_DA,
input [63:0] ALU_DB,
input [3:0] ALU_Operation,
output Zero,
output Overflow,
output [63:0] Result
);
genvar i;
wire CarryOut[62:0],less0,Set;
assign less0=Overflow^Set;
ALU_1bit alu0(
.a(ALU_DA[0]),
.b(ALU_DB[0]),
.less(less0),
.Ainvert(ALU_Operation[3]),
.Binvert(ALU_Operation[2]),
.CarryIn(ALU_Operation[2]),
.Operation(ALU_Operation[1:0]),
.Result(Result[0]),
.CarryOut(CarryOut[0])
);
generate
for(i=1;i<63;i=i+1)
begin:ALU_62bit
ALU_1bit alu(
.a(ALU_DA[i]),
.b(ALU_DB[i]),
.less(1'b0),
.Ainvert(ALU_Operation[3]),
.Binvert(ALU_Operation[2]),
.CarryIn(CarryOut[i-1]),
.Operation(ALU_Operation[1:0]),
.Result(Result[i]),
.CarryOut(CarryOut[i])
);
end
endgenerate
ALU_Hbit alu63(
.a(ALU_DA[63]),
.b(ALU_DB[63]),
.less(1'b0),
.Ainvert(ALU_Operation[3]),
.Binvert(ALU_Operation[2]),
.CarryIn(CarryOut[62]),
.Operation(ALU_Operation[1:0]),
.Result(Result[63]),
.Set(Set),
.Overflow(Overflow)
);
assign Zero=~|Result;
endmodule
//-----------------------------------------------------------------------------------------------
ALU_Operation={Ainvert,Bnegate,Operation[1:0]}
`timescale 1ns / 1ps
//
// Company: NJUEE
// Engineer: xixi
//
// Create Date: 2023/09/08 20:22:22
// Design Name:
// Module Name: ALU_RISC_V
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//ALU_Operation :{Ainvert,Bnegate,Operation[1:0]}
//0000 与
//0001 或
//0010 加
//0110 减
//0111 小于比较置位
//1100 或非
//----------------------------------------64位串行ALU--------------------------------------------
module ALU_RISC_V(
input [63:0] ALU_DA,
input [63:0] ALU_DB,
input [3:0] ALU_Operation,
output Zero,
output Overflow,
output [63:0] Result
);
genvar i;
wire CarryOut[62:0],less0,Set;
assign less0=Overflow^Set;
ALU_1bit alu0(
.a(ALU_DA[0]),
.b(ALU_DB[0]),
.less(less0),
.Ainvert(ALU_Operation[3]),
.Binvert(ALU_Operation[2]),
.CarryIn(ALU_Operation[2]),
.Operation(ALU_Operation[1:0]),
.Result(Result[0]),
.CarryOut(CarryOut[0])
);
generate
for(i=1;i<63;i=i+1)
begin:ALU_62bit
ALU_1bit alu(
.a(ALU_DA[i]),
.b(ALU_DB[i]),
.less(1'b0),
.Ainvert(ALU_Operation[3]),
.Binvert(ALU_Operation[2]),
.CarryIn(CarryOut[i-1]),
.Operation(ALU_Operation[1:0]),
.Result(Result[i]),
.CarryOut(CarryOut[i])
);
end
endgenerate
ALU_Hbit alu63(
.a(ALU_DA[63]),
.b(ALU_DB[63]),
.less(1'b0),
.Ainvert(ALU_Operation[3]),
.Binvert(ALU_Operation[2]),
.CarryIn(CarryOut[62]),
.Operation(ALU_Operation[1:0]),
.Result(Result[63]),
.Set(Set),
.Overflow(Overflow)
);
assign Zero=~|Result;
endmodule
//-----------------------------------------------------------------------------------------------
//------------------------------适应RISC-V的1位ALU(非最高位ALU)---------------------------------
module ALU_1bit(
input a,
input b,
input less,
input Ainvert,
input Binvert,
input CarryIn,
input [1:0] Operation,
output reg Result,
output CarryOut
);
wire a_n,b_n;
assign a_n=(Ainvert==0)?a:~a;
assign b_n=(Binvert==0)?b:~b;
assign CarryOut=(a_n&b_n)|(a_n&CarryIn)|(b_n&CarryIn);
always@(*)
begin
case (Operation)
2'b00:Result=a_n & b_n;
2'b01:Result=a_n | b_n;
2'b10:Result=a_n^b_n^CarryIn;
2'b11:Result=less;
endcase
end
endmodule
//-----------------------------------------------------------------------------------------------
//--------------------------------适应RISC-V的1位ALU(最高位ALU)---------------------------------
module ALU_Hbit(
input a,
input b,
input less,
input Ainvert,
input Binvert,
input CarryIn,
input [1:0] Operation,
output reg Result,
output Set,
output Overflow
);
wire a_n,b_n;
assign a_n=(Ainvert==0)?a:~a;
assign b_n=(Binvert==0)?b:~b;
assign Set=a_n^b_n^CarryIn;
always@(*)
begin
case (Operation)
2'b00:Result=a_n & b_n;
2'b01:Result=a_n | b_n;
2'b10:Result=Set;
2'b11:Result=less;
default:Result=0;
endcase
end
//Overflow 溢出检测逻辑
assign Overflow=a^Set&((~a^b)^Binvert);
endmodule
//-----------------------------------------------------------------------------------------------
仿真测试代码如下:进行具体仿真时只需替换initial块中对应内容
`timescale 1ns / 1ps
//
// Company: NJUEE
// Engineer: xixi
//
// Create Date: 2023/09/08 20:43:54
// Design Name:
// Module Name: tb_ALU_RISC_V
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
//ALU_Operation :{Ainvert,Bnegate,Operation[1:0]}
//0000 与
//0001 或
//0010 加
//0110 减
//0111 小于比较置位
//1100 或非
module tb_ALU_RISC_V(
);
reg[63:0] ALU_DA;
reg[63:0] ALU_DB;
reg[3:0] ALU_Operation;
wire Zero;
wire Overflow;
wire [63:0] Result;
initial
begin
ALU_DA=64'h8000000000000009;
ALU_DB=64'h7fffffffffffffff;
ALU_Operation=4'b0111;
end
ALU_RISC_V alu(
.ALU_DA(ALU_DA),
.ALU_DB(ALU_DB),
.ALU_Operation(ALU_Operation),
.Zero(Zero),
.Overflow(Overflow),
.Result(Result)
);
endmodule
无符号数和有符号数的算术运算验证大致相同,区别仅有溢出标志位的判断,以下均只验证有符号数
000586ab00459259H+000584abe69f24b4H
=1555443885642329+1553248727016628
=3108692612658957
=000b0b56e6e4e70dH
initial
begin
ALU_DA=64'h000586ab00459259;
ALU_DB=64'h000584abe69f24b4;
ALU_Operation=4'b0010;
end
000586ab00459259H+fffa7b541960db4cH
=1555443885642329+(-1553248727016628)
=2195158625701
=0001ff19a66da5H
initial
begin
ALU_DA=64'h000586ab00459259;
ALU_DB=64'hfffa7b541960db4c;
ALU_Operation=4'b0010;
end
fffa7954ffba6da7H+fffa7b541960db4cH
=-1555443885642329+(-1553248727016628)
=-3108692612658957
=000b0b56e6e4e70dH
initial
begin
ALU_DA=64'hfffa7954ffba6da7;
ALU_DB=64'hfffa7b541960db4c;
ALU_Operation=4'b0010;
end
05984621abef6f5eH-06985a2f2b2ee9e6H
=403149277082120030-475228919322044902
=-72079642239924872
=feffebf280c08578H
fa67b9de541090a2H-f967a5d0d4d1161aH
=-403149277082120030-(-475228919322044902)
=72079642239924872
=0100140d7f3f7a88H
05984621abef6f5eH-f967a5d0d4d1161aH
=403149277082120030-(-475228919322044902)
=878378196404164932
=c30a050d71e5944H
fa67b9de541090a2H-06985a2f2b2ee9e6H
=(-403149277082120030)-475228919322044902
=-878378196404164932
=f3cf5faf28e1a6bcH
7fffffffffffffffH+0000000000000009H,结果一定会大于2^64-1,发生溢出
Overflow位置1
8000000000000001H+fffffffffffffff7H,结果一定会小于-2^64,发生溢出
Overflow位置1
7fffffffffffffffH-fffffffffffffff7H,结果一定会大于2^64-1,发生溢出
Overflow位置1
8000000000000001H-0000000000000009H,结果一定会小于-2^64,发生溢出
Overflow位置1
initial
begin
ALU_DA=64'h8452ba5cafe8cca8;
ALU_DB=64'h2baef5fa56abafba;
ALU_Operation=4'b0000;
end
0452ba5cafe8cca8 H < 7baef5fa56abafba H,result = 64‘b 1
7452ba5cafe8cca8 H > 0baef5fa56abafba H,result = 64‘b 0
7fffffffffffffff H > 8000000000000009 H,result = 64‘b 0
8000000000000009 H < 7fffffffffffffff H,result = 64‘b 1
至此,仿真测试结束。