Trung tâm đào tạo thiết kế vi mạch Semicon


  • ĐĂNG KÝ TÀI KHOẢN ĐỂ TRUY CẬP NHIỀU TÀI LIỆU HƠN!
  • Create an account
    *
    *
    *
    *
    *
    Fields marked with an asterisk (*) are required.
wafer.jpg

Thiết kế khối ALU 4 bit đơn giản và môi trường self test, random test sử dụng UVM

E-mail Print PDF

I. Mục tiêu

Bộ xử lý logic về toán học (ALU - Arithmetic and Logic Unit) là một mạch tổ hợp để xử lý các tác vụ về logic và toán học dựa trên hai số hạng. Các tác vụ cho ALU thực hiện được điều khiển bằng các ngõ nhập function-select.

 

Hình 1.1 Khối ALU 4 bit

Mục đích của bài thí nghiệm này là thiết kế một ALU đơn giản như sau:

- Độ dài các toán hạng là 4-bit.

- Các ngõ nhập function-select gồm có: M, S0 và S1.

- Các tác vụ ALU thực hiện được cho trong bảng bên dưới:

 

Hình 1.2 Xử lý các tác vụ về logic và toán học dựa trên input ngõ vào

 

II. Tóm tắt các bước tiến hành.

Trước tiên chúng ta tiến hành thiết kế cho các bộ cộng half adder ( 2 ngõ vào 1 bit , 2 ngõ ra 1 bit), full adder ( 3 ngõ vào 1 bit bao gồm thêm 1 biến nhớ c_in, 2 ngõ ra 1 bit). Hai bộ này giúp chúng ta tiến hành thực hiện phép tính cộng cho các số hạng.

Thiết kế khối “alu_single” để tính toán các kết quả 1 bit dữ liệu. Từ 4 khối “alu_single” ta có được khối 1 khối “alu” 4 bit dữ liệu.

Khối “logic_unit” thực hiện phép toán “AND”, “OR”, “XOR” và “NXOR”.

Khối “arithmetic_unit” thực hiện phép toán “+” các số hạng đầu vào.

Khối “mux_2to1” lựa chọn tín hiệu output từ khối “logic_unit” hoặc khối “arithmetic_unit” dựa vào ngõ vào “M”.

Kết quả output ngõ ra đi qua 1 FF để tín hiệu có thể output đồng bộ với cạnh lên của clock.

Trong bài này, Chúng ta còn thực hiện viết test bench self test. Môi trường tự dump kết quả pass hoặc fail dựa vào kết quả so sánh input ngõ ra và kết quả dự đoán.

Bên cạnh đó chúng ta còn xây dựng 1 môi trường uvm hoàn chỉnh để tiến hành random test. Môi trường UVM chỉ dành cho việc kiểm tra Verilog code với nhiều input và output. Tuy nhiên, Trong bài này chúng ta tiến hành build một môi trường hoàn chỉnh để từng bước làm quen với nó.

 

III. Lý thuyết hoạt động của mạch.

Mạch half adder và full adder được thiết kế tương tự như lab 1 (Bộ add 4 bit).

Đối với mạch half adder ta có 2 giá trị ngõ vào 1 bit và 2 giá trị ngõ ra. Half adder giúp chúng ta tính toán kết quả cộng 2 ngõ vào 1 bit và cho ra giá trị ngõ ra 1 bit và 1 bit nhớ.

 

Hình 3.1 Khối half adder.

In_1

In_2

Sum

C_out

0

0

0

0

0

1

1

0

1

0

1

0

1

1

0

1

 

Bảng 3.1 Bảng giá trị vào/ra cho khối half adder

Khối full adder dùng để tính tổng giá trị 3 ngõ vào 1 bit (thêm 1 biến c_in) ở đây ta sử dụng 2 khối half adder để xây đựng khối full adder.

 

Hình 3.2 Khối full adder.

 

Hình 3.3 Xây dựng khối full adder từ 2 khối half adder.

C_in

In_1

In_2

Sum

C_out

0

0

0

0

0

0

0

1

1

0

0

1

0

1

0

0

1

1

0

1

1

0

0

1

0

1

0

1

0

1

1

1

0

0

1

1

1

1

1

1

 

Bảng 3.2 bảng giá trị vào ra cho khối full adder.

Khối logic_unit được mô tả như bên dưới:

 

Hình 3.4 Khối logic_unit.

S1

S0

In_0

In_1

H

0

0

A

B

A&B

0

1

A

B

A|B

1

0

A

B

A^B

1

1

A

B

~(A^B)

 

Bảng 3.3 Hoạt động của bộ “logic_unit”.

Với khối này giá trị H không phụ thuộc vào giá trị M ngõ vào. Giá trị M ngõ vào có chức năng lựa chọn giá trị ngõ ra từ khối “logic_unit” hay từ khối “arithmetic_unit”.

S1

S0

In_0

In_1

Carry_in

G

0

0

A

B

C0

A&C0

0

1

A

B

C0

A+B+C0

1

0

A

B

C0

A+B’+C0

1

1

A

B

C0

A’+B+C0

 

Bảng 3.4 Hoạt động của khối “arithmetic_unit”.

Kết quả của bộ ALU 4 bit sẽ đi qua 1 FF để tín hiệu ngõ ra chạy cùng với tín hiệu clock.

 

Hình 3.5 Sơ đồ tổng quát của bộ alu 4 bit.

 

IV. Verilog code và test bench, môi trường uvm.

Thật ra code cho khối này rất ngắn và đơn giản nhưng mình luôn lựa chọn cách viết phức tạp nhất để bản thân làm quen với những cấu trúc phức tạp và tăng khả năng readable của bản thân (Sau này gặp các code dễ hơn sẽ đọc nhanh hơn).

 

Verilog code:

//Module: ALU 4 bit data

module alu (clk, rst_n, in_1, in_2, carry_in, S0, S1, M, carry_out, out);

   parameter WIDTH = 4;

   input S0;

   input S1;

   input M;

   input clk;

   input rst_n;

   input [WIDTH-1:0] in_1;

   input [WIDTH-1:0] in_2;

   input carry_in;

   output carry_out;

   output [WIDTH-1:0] out;

   wire [WIDTH-2:0] carry_tmp;

   reg [WIDTH-1:0] out;

   reg  carry_out;

   wire [WIDTH-1:0] out_tmp;

   wire  carry_out_tmp;

 

// Gọi module 4 bộ alu_single 1 bit để có được 1 bộ alu 4 bit.

   alu_single alu_single_0 (.in_1(in_1[0]), .in_2(in_2[0]), .carry_in(carry_in),

                            .S0(S0), .S1(S1), .M(M), .carry_out(carry_tmp[0]), .out(out_tmp[0]));

   generate

   genvar index;

   for (index = 1; index < WIDTH - 1 ; index = index + 1) begin: re_peat

       alu_single alu_single_1 (.in_1(in_1[index]), .in_2(in_2[index]), .carry_in(carry_tmp[index-1]),

                            .S0(S0), .S1(S1), .M(M), .carry_out(carry_tmp[index]), .out(out_tmp[index]));

   end

   endgenerate

   alu_single alu_single_2 (.in_1(in_1[WIDTH - 1]), .in_2(in_2[WIDTH - 1]), .carry_in(carry_tmp[WIDTH - 2]),

                            .S0(S0), .S1(S1), .M(M), .carry_out(carry_out_tmp), .out(out_tmp[WIDTH - 1]));

 

// Output sẽ đi qua 1 FF để ngỏ ra được đồng bộ với clock.

always @(posedge clk or negedge rst_n) begin

   if (!rst_n) begin

      out <= 4'b0000;

      carry_out <=  1'b0;

   end else begin

      out <= out_tmp;

       carry_out <= carry_out_tmp;

   end

end

endmodule

 

//  Thiết kế alu_single 1 bit từ các khối mux_2to1, logic_unit, arithmethic_unit.

module alu_single (in_1, in_2, carry_in, S0, S1, M, carry_out, out);

   input S0;

   input S1;

   input M;

   input in_1;

   input in_2;

   input carry_in;

   output carry_out;

   output out;

   wire G;

   wire H;

   wire carry_out;

   wire out;

   wire carry_out_sm;

   logic_unit logic_unit_0 (.S0(S0), .S1(S1), .in_1(in_1), .in_2(in_2), .H(H));

   arithmetic_unit arithmetic_unit_0 (.S0(S0), .S1(S1), .in_1(in_1), .in_2(in_2),

                                      .carry_in(carry_in), .carry_out(carry_out_sm), .G(G));

   mux_2to1 mux_2to1_0 (.G(G), .H(H), .M(M), .out(out));

   mux_2to1 mux_2to1_1 (.G(carry_out_sm), .H(1'b0), .M(M), .out(carry_out));

endmodule

 

// Thiết kế khối mux_2to1

module mux_2to1 (G, H, M, out);

   input G, H, M;

   output out;

   wire out;

   assign out = (M == 1'b0)? H: G;

endmodule

 

//  Thiết kế khối logic_unit

module logic_unit (S0, S1, in_1, in_2, H);

   input S0, S1, in_1, in_2;

   output H;

   wire H;

   assign H = ({S1, S0} == 2'b00) ? in_1&in_2:

              ({S1, S0} == 2'b01) ? in_1|in_2:

              ({S1, S0} == 2'b10) ? in_1^in_2:

              ({S1, S0} == 2'b11) ? ~(in_1^in_2): 1'b0;

endmodule

 

// Thiết kế khối arithmetic_unit

module arithmetic_unit ( S0, S1, in_1, in_2, carry_in, carry_out, G);

   input S0, S1, in_1, in_2, carry_in;

   output carry_out, G;

   wire carry_out, G;

   wire out_case01, out_case10, out_case11, carry_out_case01, carry_out_case10, carry_out_case11;

full_adder full_adder_01  (.in_1(in_1), .in_2(in_2), .c_in(carry_in), .out(out_case01), .c_out(carry_out_case01));

full_adder full_adder_10  (.in_1(in_1), .in_2(~in_2), .c_in(carry_in), .out(out_case10), .c_out(carry_out_case10));

full_adder full_adder_11  (.in_1(~in_1), .in_2(in_2), .c_in(carry_in), .out(out_case11), .c_out(carry_out_case11));

   assign {carry_out, G} = ({S1, S0} == 2'b00) ? in_1+carry_in:

                       ({S1, S0} == 2'b01) ? {carry_out_case01, out_case01}:

                       ({S1, S0} == 2'b10) ? {carry_out_case10, out_case10}:

                       ({S1, S0} == 2'b11) ? {carry_out_case11, out_case11}: 2'b00;

Endmodule

 

// Khối full adder

module full_adder (in_1, in_2, c_in, out, c_out);

 

// Define input/output

input in_1;

input in_2;

input c_in;

output out;

output c_out;

wire sum_tmp, c_tmp_0, c_tmp_1;

 

// Add 2 inputs

half_adder half_adder_00 (.in_1(in_1), .in_2(in_2),

                         .out(sum_tmp), .c_out(c_tmp_0));

// Add sum of 2 input with carry 1

half_adder half_adder_01 (.in_1(sum_tmp), .in_2(c_in),

                         .out(out), .c_out(c_tmp_1));

// Calculate carry out

assign c_out = c_tmp_1 | c_tmp_0;

endmodule

// Khối half adder

module half_adder (in_1, in_2, out, c_out);

// defien input/output

input in_1;

input in_2;

output out;

output c_out;

// Calculate sum of 2 inputs

assign out = in_1^in_2;

// Calculate carry out

assign c_out = in_1&in_2;

endmodule

 

Để cho việc dễ dàng re-use ở đây mình sử dụng vòng lập :

generate

  

endgenerate

Vòng lập này hoàn toàn có thể tổng hợp (Synthesis) được.

Nói về vòng lập generate thì việc này được sử dụng nhiều khi muốn một tác vụ được lập lại nhiều lần. Với code C sẽ sử dụng vòng lặp for trong Verilog cấu trúc generate cũng tương tự như for trong C.

 

Test bench

//Module: ALU 4 bit data testbench

`timescale 1ns/1ns

//`include "alu.v"

module alu_tb ();

   parameter WIDTH = 4;

   reg S0;

   reg S1;

   reg M;

   reg [WIDTH-1:0] in_1;

   reg [WIDTH-1:0] in_2;

   reg carry_in;

   reg clk;

   reg rst_n;

   wire carry_out;

   wire [WIDTH-1:0] out;

   integer i;

 

alu alu_00 (.clk(clk), .rst_n(rst_n), .in_1(in_1), .in_2(in_2), .carry_in(carry_in), .S0(S0), .S1(S1), .M(M), .carry_out(carry_out), .out(out));

 

//initial begin

//   $monitor ("M_S1_S0 = %b%b%b, in_1 = %d, in_2 = %d, carry_in = %d, out = %d, carry_out = %d", M, S1, S0, in_1, in_2, carry_in, out, carry_out);

//end

 

initial begin

   clk = 0;

   forever #10 clk = ~clk;

end

 

initial begin

   #1;

   rst_n = 0;

   for ( i = 0 ; i < 3; i = i+1) begin

      S0 = $urandom;

      S1 = $urandom;

      M = $urandom;

      in_1 = $urandom;

      in_2 = $urandom;

      carry_in = $urandom;

      #20;

   end

   rst_n = 1;

   repeat (1000) begin

      S0 = $urandom;

      S1 = $urandom;

      M = $urandom;

      in_1 = $urandom;

      in_2 = $urandom;

      carry_in = $urandom;

      #20;

   end

//$display ("M_S1_S0 = %b%b%b, in_1 = %d, in_2 = %d, carry_in = %d", M, S1, S0, in_1, in_2, carry_in);

//$display ("M_S1_S0 = %b%b%b, in_1 = %d, in_2 = %d, carry_in = %d, out = %d", M, S1, S0, in_1, in_2, carry_in, out);

//$finish;

end

 

// If after 55 cycle, Simulation will pass.

initial begin

  repeat (25) begin

      @ (posedge clk);

   end

      $display ("[%t]--------------- SIMULATION PASS ---------------", $time);

      $finish;

end

 

initial begin

reg [3:0] out_tmp;

reg [3:0] out_cmp;

reg  c_tmp;

reg  c_cmp;

reg [3:0] out_1;

 

  repeat (20) begin

      @ (posedge clk) begin

         $display ("M_S1_S0 = %b%b%b, in_1 = %d, in_2 = %d, carry_in = %d, out = %d, out_tmp = %d, c = %d, c_tmp = %d", M, S1, S0, in_1, in_2, carry_in, out, out_tmp, carry_out, c_tmp);

         if ((out != out_cmp)||(carry_out != c_tmp)) begin

            $display ("[%t]--------------- SIMULATION FAIL ---------------", $time);

            $finish;

         end

         if (rst_n == 1'b0) begin

            out_tmp = 4'b0000;

            c_cmp = 1'b0;

         end else begin

         case ({M, S1, S0})

            3'b000: {c_cmp,out_tmp} = {1'b0,in_1&in_2};

            3'b001: {c_cmp,out_tmp} = {1'b0,in_1|in_2};

            3'b010: {c_cmp,out_tmp} = {1'b0,in_1^in_2};

            3'b011: {c_cmp,out_tmp} = {1'b0,~(in_1^in_2)};

           3'b100: {c_cmp,out_tmp} = in_1+carry_in;

            3'b101: begin

                      out_1 = in_1;

                      {c_cmp, out_tmp}  = out_1+in_2+carry_in;

                    end

            3'b110: begin

                      out_1 = ~in_2;

                      {c_cmp, out_tmp}  = out_1+in_1+carry_in;

                           $display("c_cmp = %d, out_1 = %d, in_1 = %d, in_2 = %d", c_cmp, out_1, in_1, in_2);

                    end

            3'b111: begin

                      out_1 = ~in_1;

                      {c_cmp, out_tmp}  = out_1+in_2+carry_in;

                    end

            default: {c_cmp,out_tmp} = 5'b00000;

         endcase

         end

         out_cmp = out_tmp;

         c_tmp = c_cmp;

      end

   end

end

//initial begin

//   $vcdplusfile("alu.vpd");

//   $vcdpluson();

//end

  initial begin

    $dumpfile("dump.vcd");

    $dumpvars(0, alu_tb);

end 

endmodule

Nguồn: trongtranrvc.blogspot

Bạn Có Đam Mê Với Vi Mạch hay Nhúng      -     Bạn Muốn Trau Dồi Thêm Kĩ Năng

Mong Muốn Có Thêm Cơ Hội Trong Công Việc

    Và Trở Thành Một Người Có Giá Trị Hơn

Bạn Chưa Biết Phương Thức Nào Nhanh Chóng Để Đạt Được Chúng

Hãy Để Chúng Tôi Hỗ Trợ Cho Bạn. SEMICON  

 

Hotline: 0972.800.931 - 0938.838.404 (Mr Long)

 

Last Updated ( Wednesday, 24 July 2019 20:22 )  

Related Articles

Chat Zalo