EE/Verilog HDL

[verilog HDL] 16-bit ALU(Arithmetic Logic Unit)

아이스얼그레이 2022. 2. 23. 16:40

논리회로설계 In Class assignment로 나온 16bit ALU 설계입니다.

 

최상위 module은 ALU이고 하위 module이 5개(+, -, *, /, 4 to 1 MUX)가 있습니다.
input은 16bit a, b, 2bit select signal이고 output은 16bit z입니다.

 

module의 hierarchy와 structure을 도식화해보면 다음과 같습니다.

16bit ALU의 hierarchy와 structure

 

위 그림을 보면 다음을 알 수 있습니다.

 

ⅰ) Add, Sub, Mul, Div module 각각에 input a, b가 들어간다.

 

ⅱ) MUX의 input으로 들어가는 arithmetic module의 output을 wire로 선언해야한다.

 

ⅲ) MUX의 output이 ALU의 output이 된다.

 

ⅳ) sel signal과 arithmetic module의 matching은 다음과 같다.

 

sel signal arithmetic module
2'b00 Adder
2'b01 Substractor
2'b10 Multiplier
2'b11 Divider

 

위를 verilog code로 바꿔보겠습니다.

 

1. ALU_16bit module

module ALU_16bit(
    input [15:0] a, b,
    input [1:0] sel,
    output [15:0] z
    );

    wire [15:0] output_add, output_sub, output_mul, output_div;

    Adder_16bit add0(.A(a), .B(b), .Z(output_add));
    Substractor_16bit sub0(.A(a), .B(b), .Z(output_sub));
    Multiplier_16bit mul0(.A(a), .B(b), .Z(output_mul));
    Divider_16bit div0(.A(a), .B(b), .Z(output_div));

    MUX_4_to_1 mux0(.i0(output_add), .i1(output_sub), .i2(output_mul), .i3(output_div), .sel(sel), .z(z));

endmodule

arithmetic module의 output을 MUX로 전달해주기 위해 4개의 16bit wire를 정의하였습니다. 각 instance의 input과 output을 잘 설정하는 것이 중요합니다. 오류를 최소한으로 하기위해 ordered connection by name 방법을 사용하였습니다.

 

2. MUX_4_to_1 module

module MUX_4_to_1(
    input [15:0] i0, // adder의 output -> sel 00
    input [15:0] i1, // substractor의 output -> sel 01
    input [15:0] i2, // multiplier의 output -> sel 10
    input [15:0] i3, // divider의 output -> sel 11
    input [1:0] sel,
    output [15:0] z
);

    assign z = sel[1] ? (sel[0] ? i3 : i2) : (sel[0] ? i1 : i0);

endmodule

MUX입니다. 원래 case문으로 작성했었는데, 갑자기 삼항연산자가 이해가 잘되어서 삼항연산자를 여러 개 써서 작성하였습니다. ⅳ) 을 만족하도록 MUX를 작성 하였습니다.

 

3. Adder, Substractor, Multiplier, Divider

module Adder_16bit(
    input [15:0] A,
    input [15:0] B,
    output [15:0] Z
);

    assign Z = A + B;

endmodule

module Substractor_16bit(
    input [15:0] A,
    input [15:0] B,
    output [15:0] Z
);

    assign Z = A - B;

endmodule

module Multiplier_16bit(
    input [15:0] A,
    input [15:0] B,
    output [15:0] Z
);

    assign Z = A * B;

endmodule

module Divider_16bit(
    input [15:0] A,
    input [15:0] B,
    output [15:0] Z
);

    assign Z = A / B;

endmodule

간단한 dataflow level design이므로 설명은 생략하겠습니다.

 

4. testbench

module ALU_16bit_tb(

    );

    reg [15:0] A, B;
    reg [1:0] SEL;
    wire [15:0] Z;

    ALU_16bit alu0(.a(A), .b(B), .sel(SEL), .z(Z));

    initial begin
        A = 16'b0000_0000_0000_0000;
        B = 16'b0000_0000_0000_0000;
        SEL = 2'b00;
    end

    always begin
        #5 SEL = SEL + 1;
        A = A + 20;
        B = B + 5;
    end

endmodule

testbench는 최대한 간단하게 작성해봤습니다. #20을 주기로 SEL이 00 01 10 11을 반복하도록 작성했고, input의 값은 결과를 알아보기 쉬운 적절한 값을 더하도록 설정했습니다.

 

ALU instance에서도 ordered connection by name 방법을 사용하였습니다.

 

simulation 결과는 다음과 같습니다.

ALU simulation 결과

 

사칙연산이 정상적으로 작동되는 것을 확인하였습니다.

 

RTL schematic은 다음과 같습니다.

 

ALU의 RTL schematic