2024.11.04 수업날
< Program Counter >
PC의 최종 블록 다이어그램
Vivado 진행 순서
half_adder_N_bit
/////////////////////////////////////////////////// 2024.11.04
module half_adder_N_bit #(parameter N = 8)(
input inc,
input [N-1:0] load_data,
output [N-1:0] sum);
wire [N-1:0] carry_out;
half_adder_dataflow ha0(.a(inc), .b(load_data[0]), .s(sum[0]), .c(carry_out[0]));
genvar i; //genvar는 generate에서 만든 변수
generate
for(i=1; i<N; i=i+1) begin:hagen
half_adder_dataflow ha(.a(carry_out[i-1]), .b(load_data[i]), .s(sum[i]), .c(carry_out[i]));
end
endgenerate
// half_adder_dataflow ha1(.a(carry_out[0]), .b(load_data[1]), .s(sum[1]), .c(carry_out[1]));
// half_adder_dataflow ha2(.a(carry_out[1]), .b(load_data[2]), .s(sum[2]), .c(carry_out[2]));
// half_adder_dataflow ha3(.a(carry_out[2]), .b(load_data[3]), .s(sum[3]), .c(carry_out[3]));
// half_adder_dataflow ha4(.a(carry_out[3]), .b(load_data[4]), .s(sum[4]), .c(carry_out[4]));
endmodule
generate문을 쓰면 왼쪽에 N을 설정한 만큼 추가되는 것을 확인할 수 있다.
추가되는 것의 이름을 바꾸고 싶다면 begin 다음에 ':이름' 이런식으로 쓰면 된다.
Program Counter
/////////////////////////////////////////////////////////////
module Program_addr_counter(
input clk, reset_p,
input pc_inc, load_pc, pc_rd_en, // pc_inc 1씩 증가, pc_rd_en은 pc_out이 어떤 출력으로 될 것인지를 정함
input [7:0] pc_in,
output [7:0] pc_out);
wire [7:0] sum, cur_addr, next_addr;
assign next_addr = load_pc ? pc_in : sum;
half_adder_N_bit #(.N(8)) pc(
.inc(pc_inc),
.load_data(cur_addr),
.sum(sum));
register_Nbit_p # (.N(8)) pc_reg(
.clk(clk), .reset_p(reset_p),
.d(next_addr),
.wr_en(1), .rd_en(pc_rd_en),
.register_data(cur_addr),
.q(pc_out));
endmodule
pc 시뮬레이션 결과는 아래와 같다.
pc_inc 에 1을 줬을 때는 1이 더해져야하고,
load_pc 에 1을 줬을 때는 값이 그대로 load,
pc_rd_en에 1을 줬을 때는 값이 출력되어야 한다.
pc_inc 에 1을 줄때는 load_pc 에 0을 줘야 값 확인할 수 있다.
< Processor >
Vivado 진행 순서
Processor
///////////////////////////////////////////////// 2024.11.04
module Processor(
input clk, reset_p,
input [3:0] key_value,
input key_valid,
output [3:0] kout, // cpu가 key 입력을 받았는지 확인함
output [7:0] outreg_data);
wire [7:0] int_bus, mar_out, rom_out;
wire mar_inen, mdr_inen; // in enable
wire mdr_oen; // out enable
wire pc_inc, load_pc, pc_oen;
wire [7:0] ir_data;
wire ir_inen;
wire [3:0] bus_reg_data;
wire breg_inen;
wire acc_high_reset_p, acc_oen, acc_in_select;
wire [1:0] acc_high_select_in, acc_low_select;
wire op_add, op_sub, op_mul, op_div, op_and;
wire zero_flag, sign_flag;
wire tmpreg_inen, tmpreg_oen;
wire creg_inen, creg_oen;
wire dreg_inen, dreg_oen;
wire rreg_inen, rreg_oen;
wire outreg_inen;
wire keychreg_oen;
wire inreg_oen;
wire keyout_inen;
// Control_Block 모듈: CPU 제어 논리
// 입력: 클럭, 리셋, IR 데이터, 플래그
// 출력: 여러 컨트롤 신호 (MAR, MDR, PC, ALU 등) 활성화 및 설정 신호
Control_Block CB(
clk, reset_p,
ir_data,
zero_flag, sign_flag,
mar_inen, mdr_inen, mdr_oen, ir_inen, pc_inc, load_pc, pc_oen, breg_inen,
acc_high_reset_p, acc_oen, acc_in_select,
acc_high_select_in, acc_low_select,
op_add, op_sub, op_mul, op_div, op_and,
tmpreg_inen, tmpreg_oen, creg_inen, creg_oen,
dreg_inen, dreg_oen, rreg_inen, rreg_oen,
outreg_inen, keychreg_oen, inreg_oen, keyout_inen, rom_en);
// Program_addr_counter 모듈: Program Counter 제어
// PC 증가 또는 로드 수행, 내부 버스를 통해 값을 전달
Program_addr_counter PC(
.clk(clk), .reset_p(reset_p),
.pc_inc(pc_inc), .load_pc(load_pc), .pc_rd_en(pc_oen),
.pc_in(int_bus),
.pc_out(int_bus));
// MAR (Memory Address Register): 메모리 주소 저장
register_Nbit_p # (.N(8)) MAR(
.clk(clk), .reset_p(reset_p),
.d(int_bus), // 내부 버스에서 입력 받음
.wr_en(mar_inen), .rd_en(1),
.register_data(mar_out)); // 출력 데이터 (MAR의 주소 값)
// MDR (Memory Data Register): 메모리 데이터 저장
register_Nbit_p # (.N(8)) MDR(
.clk(clk), .reset_p(reset_p),
.d(rom_out), // ROM의 출력 데이터를 입력
.wr_en(mdr_inen), .rd_en(mdr_oen),
.q(int_bus)); // 내부 버스에 출력 연결
// IR (Instruction Register): 명령어 저장
register_Nbit_p # (.N(8)) IR(
.clk(clk), .reset_p(reset_p),
.d(int_bus), // 내부 버스에서 입력 받음
.wr_en(ir_inen), .rd_en(1),
.register_data(ir_data)); // 출력 데이터 (명령어)
// BREG: ALU 연산을 위해 데이터 보관 (4비트)
register_Nbit_p # (.N(4)) BREG( // ALU를 4 bit로 사용했기 때문
.clk(clk), .reset_p(reset_p),
.d(int_bus[7:4]), // 상위 4비트만 입력으로 사용
.wr_en(breg_inen), .rd_en(1),
.register_data(bus_reg_data)); // ALU로 전달할 데이터
// ALU 및 ACC: 산술 및 논리 연산 수행
Block_ALU_ACC alu_acc(
.clk(clk), .reset_p(reset_p), .acc_high_reset_p(acc_high_reset_p),
.rd_en(acc_oen), .acc_in_select(acc_in_select),
.acc_high_select_in(acc_high_select_in), .acc_low_select(acc_low_select),
.bus_data(int_bus[7:4]), // ALU 입력 데이터
.op_add(op_add), .op_sub(op_sub), .op_mul(op_mul), .op_div(op_div), .op_and(op_and), // 연산 제어
.bus_reg_data(bus_reg_data), // 레지스터 데이터
.zero_flag(zero_flag), .sign_flag(sign_flag), // 상태 플래그
.acc_data(int_bus)); // 내부 버스로 결과 출력
// TMPREG: 임시 레지스터
register_Nbit_p # (.N(4)) TMPREG(
.clk(clk), .reset_p(reset_p),
.d(int_bus[7:4]),
.wr_en(tmpreg_inen), .rd_en(tmpreg_oen),
.q(int_bus[7:4]));
// CREG, DREG, RREG: 추가 레지스터 (4비트)
register_Nbit_p # (.N(4)) CREG(
.clk(clk), .reset_p(reset_p),
.d(int_bus[7:4]),
.wr_en(creg_inen), .rd_en(creg_oen),
.q(int_bus[7:4]));
register_Nbit_p # (.N(4)) DREG(
.clk(clk), .reset_p(reset_p),
.d(int_bus[7:4]),
.wr_en(dreg_inen), .rd_en(dreg_oen),
.q(int_bus[7:4]));
register_Nbit_p # (.N(4)) RREG(
.clk(clk), .reset_p(reset_p),
.d(int_bus[7:4]),
.wr_en(rreg_inen), .rd_en(rreg_oen),
.q(int_bus[7:4]));
// OUTREG: CPU 출력용 레지스터
register_Nbit_p # (.N(8)) OUTREG(
.clk(clk), .reset_p(reset_p),
.d(int_bus),
.wr_en(outreg_inen),
.register_data(outreg_data));
// KEYCHREG: 키 입력 유효성을 확인하기 위한 레지스터
register_Nbit_p # (.N(4)) KEYCHREG(
.clk(clk), .reset_p(reset_p),
.d({key_valid, key_valid, key_valid, key_valid}),
.wr_en(1), .rd_en(keychreg_oen),
.q(int_bus[7:4]));
// INREG: 키 값을 저장하는 레지스터
register_Nbit_p # (.N(4)) INREG(
.clk(clk), .reset_p(reset_p),
.d(key_value),
.wr_en(1), .rd_en(inreg_oen),
.q(int_bus[7:4]));
// KEYOUTREG: 키 출력 확인 레지스터
register_Nbit_p # (.N(4)) KEYOUTREG(
.clk(clk), .reset_p(reset_p),
.d(int_bus[7:4]),
.wr_en(keyout_inen), .rd_en(1),
.register_data(kout));
endmodule
Processor에 인스턴스 하기 위해 Control Block 모듈을 추가한다.
Control_Block
///////////////////////////////////////// 2024.11.04
module Control_Block(
input clk, reset_p,
input [7:0] ir_data,
input zero_flag, sign_flag,
output mar_inen, mdr_inen, mdr_oen, ir_inen, pc_inc, load_pc, pc_oen, breg_inen,
output [1:0] acc_high_reset_p, acc_oen, acc_in_select,
output [1:0] acc_high_select_in, acc_low_select,
output op_add, op_sub, op_mul, op_div, op_and,
output tmpreg_inen, tmpreg_oen, creg_inen, creg_oen,
output dreg_inen, dreg_oen, rreg_inen, rreg_oen,
output outreg_inen, keychreg_oen, inreg_oen, keyout_inen, rom_en);
endmodule
cpu의 구조와 동작원리3(Program Counter, Processor) 끝!