본문 바로가기

Projects

FPGA 프로젝트 : Verilog를 이용한 CPU 제작 / ACC(Accumulator) (3)

1. ACC(Accumulator) 누산기란?


이번 시간에는 CPU 연산 처리 장치인 ALU로 부터 나온 데이터가 저장되는 ACC(Accumulator)를 Verilog로 구현한다. ACC(Accumulator) 누산기는 컴퓨터에서 가장 기본적인 산술 논리 장치(ALU) 중 하나로, 수행한 연산에 대한 데이터를 누적하는데 사용된다.

누산기는 일반적으로 레지스터(Register)와 함께 사용되며, 레지스터는 데이터를 저장하는 장치로, 누산기의 입력과 출력을 제어하고 데이터를 임시로 저장한다. 누산기는 입력된 데이터와 레지스터에 저장된 데이터를 덧셈 연산하여 결과를 출력한다.

 

2. ACC(Accumulator) 누산기의 구조

 


위 구조도를 보면 6개의 Input(파란색 선)과 2개(각 4비트)의 Output(빨간색 선)이 있다. 먼저 왼쪽 상단에 MUX를 통해 BUS에서 들어오는 데이터와 ALU로 부터 들어오는 데이터를 신호 선택선으로 HIGH 레지스터의 MUX에 전달한다. 또한 HIGH 레지스터의 MUX는 새로운 비트를 추가할 fill_value값과 LOW 레지스터의 최상위 비트를 받아 HIGH_Sel 신호에 의해 4비트가 결정된다. LOW 레지스터의 MUX도 마찬가지로 HIGH 레지스터의 4비트와 fill value를 받아 LOW레지스터의 4비트가 LOW_Sel신호에 의해 결정된다. 이렇게 결정된 HIGH와 LOW의 4비트(총 8비트)는 ACC에서 출력된다.

 

3. Verilog를 이용한 ACC(Accumulator) 누산기 구현 

 

`timescale 1ns / 1ps

module acc(

    input clk, reset_p, acc_high_reset_p, acc_in_sel, fill_value,
    input [1:0] acc_high_sel, acc_low_sel,
    input [3:0] aludata, bus_in,
    output [3:0] acc_high_data,
    output [3:0] acc_low_data
    
    );
    
    wire [3:0] acc_high_in;
    
    // 2x1 mux
    assign acc_high_in = acc_in_sel ? bus_in : aludata; // acc_i_en 에 따라서 , High 4bit에 덮어 씌울 값을 결정
    
    // 버스에서 데이터 받는거 : 상위 4비트 -> clear 해야됨 / 하위 4비트는 clear 할 필요 x 
    half_acc acc_high( // 상위 4비트     // reset_p는 or로 처리     
    .clk(clk), .reset_p(reset_p | acc_high_reset_p), .load_msb(fill_value), .load_lsb(acc_low_data[3]), //load_msb는 shift right를 위해 fill_value사용, 
                                                                                                        //load_lsb는 하위 4비트 중 MSB를 가져옴(다리 역할)
    .S(acc_high_sel), // S입력 동작 ->  00 : pass, 01 : shift right, 10 : shift left, 11 : load
    .data_in(acc_high_in),      //만약 S가 11일 경우에 위 mux에서 High 4bit에 덮어 씌울 결정된 값을 넣어줌
    .data(acc_high_data)        //output
    );
    
    half_acc acc_low( // 하위 4비트          
    .clk(clk), .reset_p(reset_p), .load_msb(acc_high_data[0]), .load_lsb(fill_value),  //load_msb는 상위 4비트의 LSB를 가져옴(다리 역할)
                                                                                        //load_lsb는 shift left를 위해 fill_value사용, 
    .S(acc_low_sel), // S입력 동작 ->  00 : pass, 01 : shift right, 10 : shift left, 11 : load
    .data_in(acc_high_data), // 만약 S가 11일 경우에 상위 4bit의 값을  하위 4bit에 덮어줌
    .data(acc_low_data)     //output
    );
   
endmodule


module half_acc(

    input clk, reset_p, load_msb, load_lsb,                   //상위4비트를 하위4비트로 load하면 병렬(parallel)  전송
    input [1:0] S, // S입력 동작 ->  00 : pass, 01 : shift right, 10 : shift left, 11 : load
    input [3:0] data_in,
    output [3:0] data
    );
    
    wire [3:0] D; // register 입력
            // S입력 :   11         10        01       00
    mux_4_1 mux3 (.D({data_in[3], data[2], load_msb, data[3]}), .S(S), .F(D[3]));
    mux_4_1 mux2 (.D({data_in[2], data[1], data[3], data[2]}), .S(S), .F(D[2]));
    mux_4_1 mux1 (.D({data_in[1], data[0], data[2], data[1]}), .S(S), .F(D[1]));
    mux_4_1 mux0 (.D({data_in[0], load_lsb, data[1], data[0]}), .S(S), .F(D[0]));
    
    // 한 clk에 좌,우,병렬 shfit가 되는 레지스터 4개 선언
    resister_N_bit_posedge #(.N(4)) reg_acc_4bit (
    .D(D), .clk(clk), .reset_p(reset_p), .wr_e_p(1'b1), .rd_e_p(1'b1), .Q(data) // rd_e_p가 1일때 출력, 0이면 임피던스 값
    );

endmodule

ACC를 만들기 위해서는 ACC에서 쓰일 8비트를 구현해야한다. 이 8비트에서는 쉬프트를 이용하기에 각 비트간 데이터가 움직이도록 해야하며, 초기화, 새 값을 덮어 씌우는 등의 기능을 구현해야한다.

 

먼저 8비트의 절반을 잘라 상위 4비트, 하위 4비트로 나눈다. 이 4비트 레지스터를 구현해보자.

 

4비트 레지스터를 아래에 half_acc로 구현한다. MUX를 이용해 4가지 케이스로 나눈다.

(00 : 아무 동작 안함 / 01 : Shift right / 10 : shift left / 11 : Load(새 값 덮어 씌우기))

이 케이스에 의해 각 비트는 MUX를 통해서 값이 결정된다. 위를 보면 신호 선택선에 의해 값이 새로 덮어 씌울지, lsb를 새로 넣어 왼쪽으로 움직일지, msb를 새로 넣어 오른쪽으로 움직일지, 그대로 멈출지를 결정한다.

이렇게 결정된 4비트는 4비트 레지스터에 등록된다.

 

이후 모듈 acc에서 앞서 만든 half_acc 두 개를 이용하여 상위 4bit, 하위 4bit를 만든다.

상위 4비트의 msb(8비트 중 맨 왼쪽)와 하위 4비트의 lsb(8비트 중 맨 오른쪽)에는 fill_value 변수를 넣어 쉬프트 이동이 있을 때를 대비해서 새 변수를 할당한다.

다음으로 다리 역할을 할  상위 4비트의 lsb(왼쪽 중앙)와 하위 4비트의 msb(오른쪽 중앙)에는 서로의 값을 할당하여 다리 역할을 하도록 한다.

data_in에는 신호 선택선 S값이 11이 들어올 경우에 새로 갱신할 값을 넣어준다. 상위 4비트에는 acc_in_sel을 사용하는 mux를 통해서 결정된 값을 할당하고, 하위 4비트에는 상위 4비트의 값을 그대로 저장한다.

 

신호 선택선 S에 의해 acc_high_data와 acc_low_data가 결정이 되면 output 값으로 전달이 된다.

 

다음 글에서는 위에서 만든 ACC(Accumulator)와 이전 글에서 만든 ALU와 연결하여 테스트를 할 것이다.