본문 바로가기

Projects

FPGA 프로젝트 : Verilog를 이용한 CPU 제작 / ACC(Accumulator)와 ALU의 연결 (4)

 

1. Verilog에서의 ALU와 ACC의 연결 코드 


최종적으로 Processor 모듈을 만들 때, 코드를 간단하게 작성하기 위해 지난 글에서 작성한 ALU와 ACC를 연결한 모듈을 만들어야한다. 코드는 다음과 같다.

`timescale 1ns / 1ps

module block_alu_acc(

    input clk, reset_p, acc_high_reset_p, acc_in_sel, acc_o_en,
    input op_add, op_sub, op_and, op_mul, op_div,
    input [1:0] acc_low_sel, acc_high_select_in,
    input [3:0] bus_in, bus_reg_in,
    output sign_flag, zero_flag, // carry flag, cout은 내부에서 계산할때만 쓰여서 추가안함
    output [7:0] acc_data // bus로 출력함
    );
    
    wire carry_flag, cout;
    wire [1:0] acc_high_sel;
    wire [3:0] aludata, acc_high_data, acc_low_data;
    
                      // '00'이면 유지, '11'이면 load    // 곱셈 : acc_low_data가 1이면 더함  // 나눗셈 : 뺄셈되면 1씀 & 연산값이 양수일때 cout이 1 
                      
    assign acc_high_sel[1] = (op_mul | op_div) ? (op_mul&acc_low_data[0]) | (op_div&cout) : acc_high_select_in[1]; 
    assign acc_high_sel[0] = (op_mul | op_div) ? (op_mul&acc_low_data[0]) | (op_div&cout) : acc_high_select_in[0]; 
    
    acc block_acc (                                // fill_value 대신 carry_flag 으로 채움
        clk, reset_p, acc_high_reset_p, acc_in_sel, carry_flag, // 1bit input
        acc_high_sel, acc_low_sel,                              // 2bit input
        aludata, bus_in,                                        // 4bit input
        acc_high_data, acc_low_data                             // 4bit output                
    );
    
    assign acc_data = acc_o_en ? {acc_high_data, acc_low_data} : 8'bz; 
    
    alu block_alu (
        clk, reset_p, 
        op_add, op_sub, op_and, op_mul, op_div, acc_low_data[0],
        acc_high_data,
        bus_reg_in,
        aludata,
        zero_flag, sign_flag, carry_flag, cout 
    );
    
endmodule

먼저 이 코드의 핵심은 

 

    assign acc_high_sel[1] = (op_mul | op_div) ? (op_mul&acc_low_data[0]) | (op_div&cout) : acc_high_select_in[1]; 
    assign acc_high_sel[0] = (op_mul | op_div) ? (op_mul&acc_low_data[0]) | (op_div&cout) : acc_high_select_in[0]; 

 

이 코드이다. 제어를 담당하는 control block으로 부터 연산 수행의 flag를 담당하는 op_xxx코드가 있다. 이 코드는 연산을 수행할 경우 1로 set이 된다. 위 assign문을 이용한 코드가 작성된 이유는 "곱셈과 나눗셈의 처리"를 묻기 위함이다. 2진수의 곱셈과 나눗셈의 특성상, 계속해서 연산을 덧셈과 뺄셈을 통해서 곱셈과 나눗셈을 진행해야한다. 곱셈 연산이 수행될때는 최하위 비트가 1인지 파악하여 그 여부에 따라 덧셈 연산을 진행해야하고, 나눗셈의 경우 양수인 경우를 계속해서 확인을 해야한다(궁금하다면 2진수의 곱셈과 나눗셈 방법을 참고). 따라서 연산이 수행이 되는 조건에 따라 high의 처리 결과가 결정이 되는 것이다. 하지만 연산 수행이 되지 않을 경우에는 그대로 모듈에서 받은 acc_high_select_in 두 비트를 그대로 전달해준다.

 

이렇게 acc_high_sel 두 비트가 결정이 되면 앞선 글에서 작성했던 acc누산기 알고리즘에 의해 high값의 연산 수행 4가지(00 : pass, 01 : shift right, 10 : shift left, 11 : load ) 중 1가지가 선택이 된다. 이렇게 하위 acc모듈로 부터 거쳐 나온 acc_high_data, acc_low_data 총 8비트의 값을 acc_o_en 값(BUS로 내보낼지 말지 결정하는 flag)에 따라acc_o_en이  1인 경우 BUS로 출력을, 0인 경우에는 임피던스를 출력한다.(임피던스로 출력하는 이유는 acc에서 데이터를 out시키지 않아도 되면 bus에 임피던스를 주어 끊어진 상태를 만들어야 한다. 그렇지 않으면 다른 모듈이나 레지스터에 이상한 값이 전달될 수 있기 때문이다. 쉽게 말해서 BUS는 공유선이기에 사용하지 않으면 연결을 끊어주어야 한다.)

 

따라서 최종적으로 이 ACC와 ALU가 연결된 모듈에서 나오는 최종 output 값acc data 8비트(연산 결과 데이터), sign_flag(숫자의 부호를 판단하는 flag), zero_flag(수가 0인지 아닌지 판단하는 flag)이다.