verilog implements ALU adapted to RISC-V

This article is based on the verilog implementation of the ALU design part in "Computer Composition and Design Hardware/Software Interface RISC-V Edition Original Book 5th Edition" (David A. Patterson_John L. Hennis)

1. Hardware structure

The 64-bit ALU design adapted to the RISC-V architecture in the book is used to mainly complete logical operations such as AND, OR, NOR, basic arithmetic operations such as addition and subtraction, as well as the implementation of the less than or equal to set slt instruction and the conditional jump instruction bne instruction.

1.1-bit ALU structure

1) Non-most significant bit ALU

//------------------------------适应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
//-----------------------------------------------------------------------------------------------
2) Most significant bit ALU

The design of the overflow detection unit is as follows:

Overflow detection is used when performing addition and subtraction operations. There are only 4 situations in which overflow will occur:

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
//-----------------------------------------------------------------------------------------------

2.64-bit serial ALU structure

The structure in the figure above given in the book cannot achieve slt less than comparison setting when subtraction overflows, but the simulation results found that: when subtraction overflows, the corresponding result is the inversion of the Set bit of ALU63, so it only needs to be set in the Set bit of ALU63 and This can be achieved by passing the Overflow bit XOR to the less bit input of ALU0.

//----------------------------------------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
//-----------------------------------------------------------------------------------------------

3.ALU_Operation control signal

ALU_Operation={Ainvert,Bnegate,Operation[1:0]}

4. Final code implementation

`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
//-----------------------------------------------------------------------------------------------

2. Simulation test

The simulation test code is as follows: When performing specific simulation, you only need to replace the corresponding content in the initial block

`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

1. Arithmetic operations

The arithmetic operation verification of unsigned numbers and signed numbers is roughly the same. The only difference is the judgment of the overflow flag. The following only verifies signed numbers.

1) Addition ALU_Operation=4'b0010
a. Positive + positive

000586ab00459259H+000584abe69f24b4H
=1555443885642329+1553248727016628
=3108692612658957
=000b0b56e6e4e70dH

initial
begin
    ALU_DA=64'h000586ab00459259;
    ALU_DB=64'h000584abe69f24b4;
    ALU_Operation=4'b0010;
end
b. Positive + negative

000586ab00459259H+fffa7b541960db4cH
=1555443885642329+(-1553248727016628)
=2195158625701
=0001ff19a66da5H

initial
begin
    ALU_DA=64'h000586ab00459259;
    ALU_DB=64'hfffa7b541960db4c;
    ALU_Operation=4'b0010;
end
c. Negative + Negative

fffa7954ffba6da7H+fffa7b541960db4cH
=-1555443885642329+(-1553248727016628)
=-3108692612658957
=000b0b56e6e4e70dH

initial
begin
    ALU_DA=64'hfffa7954ffba6da7;
    ALU_DB=64'hfffa7b541960db4c;
    ALU_Operation=4'b0010;
end

2) Subtraction ALU_Operation=4'b0110
a. Positive-positive

05984621abef6f5eH-06985a2f2b2ee9e6H
=403149277082120030-475228919322044902
=-72079642239924872
=feffebf280c08578H

b. Negative-negative

fa67b9de541090a2H-f967a5d0d4d1161aH
=-403149277082120030-(-475228919322044902)
=72079642239924872
=0100140d7f3f7a88H

c.Positive-negative

05984621abef6f5eH-f967a5d0d4d1161aH
=403149277082120030-(-475228919322044902)
=878378196404164932
=c30a050d71e5944H

d. Negative-Positive

fa67b9de541090a2H-06985a2f2b2ee9e6H
=(-403149277082120030)-475228919322044902
=-878378196404164932
=f3cf5faf28e1a6bcH

3) Overflow test
a. Positive + positive

7ffffffffffffffH+0000000000000009H, the result will definitely be greater than 2^64-1, and overflow occurs at
Overflow position 1

b. Negative + Negative

8000000000000001H+ffffffffffffffff7H, the result will definitely be less than -2^64, overflow occurs at
Overflow position 1

c.Positive-negative

7ffffffffffffffH-fffffffffffffff7H, the result will definitely be greater than 2^64-1, overflow occurs at
Overflow position 1

d. Negative-Positive

8000000000000001H-0000000000000009H, the result will definitely be less than -2^64, overflow occurs at
Overflow position 1

2. Logical operations

initial
begin
    ALU_DA=64'h8452ba5cafe8cca8;
    ALU_DB=64'h2baef5fa56abafba;
    ALU_Operation=4'b0000;
end
1) With ALU_Operation=4'b0000

2) or ALU_Operation=4'b0001

3) Or non-ALU_Operation=4'b1100

3. Less than comparison setting ALU_Operation=4'b0111

1) Judgment when subtraction does not overflow

0452ba5cafe8cca8 H < 7baef5fa56abafba H,result = 64‘b 1

7452ba5cafe8cca8 H > 0baef5fa56abafba H,result = 64‘b 0

2) Judgment when subtraction overflows

7fffffffffffffff H > 8000000000000009 H,result = 64‘b 0

8000000000000009 H < 7fffffffffffffff H,result = 64‘b 1

At this point, the simulation test ends.

おすすめ

転載: blog.csdn.net/qq_62047219/article/details/132768411