program counter = 0부터 시작
PC가 실행되면 BUS로 들어감
MAR 0번지 DATA를 가져가다 ROM에 저장
후에 IR에 들어감
MDR에 데이터나 명령이 들어갈 수 있음
IR에 명령이 들어가면 control block에 들어감
control block은 디코딩을 함
ex)더하기 3 + 4면 ACC에 3이 ALU를 거쳐 다시 ACC에 들어감. 다음은 ACC를 무시하고 4가 BREG에 들어감. 더한 값은 ALU를 거쳐 ACC에 저장. 또 + 4가 진행되면 7이 저장되어있는 상태에서 BREG에 4가 들어가고 ALU를 통해 ACC에 11이 저장된다.
register에 clk이 들어갈 때마다 1씩 증가 >> counter 동작
Half-adder 8개 만들기
`timescale 1ns / 1ps
module hadder_8_bit(
input A,
input [7:0] data_in,
output [7:0] data_out
);
wire carry_out [7:0];
genvar i;
generate
half_adder ha0(.A(A), .B(data_in[0]), .S(data_out[0]), .C(carry_out[0])); //첫번째 hadder만 그대로 받아야하니까 만들어놓음
for (i = 1; i < 8; i = i + 1)begin :hagen //콜론하고 이름 = genvar로 만든 모델이름
half_adder ha(.A(carry_out[i-1]), .B(data_in[i]), .S(data_out[i]), .C(carry_out[i]));
end
endgenerate
endmodule
pc코드
`timescale 1ns / 1ps
module program_addr_counter(
input clk,
input reset_p,
input pc_inc,
input load_pc,
input pc_o_en,
input [7:0] pc_in,
output [7:0] pc_out
);
wire [7:0] data_out, p_addr, p_addr_out;
hadder_N_bit #(.N(8)) ha8bit(.A(pc_inc), .data_in(p_addr_out), .data_out(data_out)); //p_addr mux의 출력을 주고있음
assign p_addr = (load_pc) ? pc_in : data_out; //mux는 이렇게 쓰는게 제일 간단함
// genvar i;
// generate
// for(i=0;i<8;i=i+1)begin
// mux_2_1 mux2to1_0(.D({pc_in[i], data_out[i]}), .S(load_pc), .F(p_addr[i]));
// end
// endgenerate
register_N_bit_posedge #(.N(8)) sum_reg(
.D(p_addr),
.clk(clk),
.reset_p(reset_p),
.wr_e_p(1'b1), .rd_e_p(pc_o_en),
.Q(p_addr_out), //이건 hadder에 넣고 hadder의 data_out은 mux에 넣고
.tri_state_Q(pc_out)); //pc_o_en에 0을 주면 임피던스, 1을 주면 값 출력
endmodule
counter 코드
`timescale 1ns / 1ps
module hadder_8_bit(
input A,
input [7:0] data_in,
output [7:0] data_out
);
wire carry_out [7:0];
genvar i;
generate
half_adder ha0(.A(A), .B(data_in[0]), .S(data_out[0]), .C(carry_out[0])); //첫번째 hadder만 그대로 받아야하니까 만들어놓음
for (i = 1; i < 8; i = i + 1)begin :hagen //콜론하고 이름 = genvar로 만든 모델이름
half_adder ha(.A(carry_out[i-1]), .B(data_in[i]), .S(data_out[i]), .C(carry_out[i]));
end
endgenerate
endmodule
module hadder_N_bit #(parameter N = 8)(
input A,
input [N-1:0] data_in,
output [N-1:0] data_out
);
wire [N-1:0] carry_out;
//carry_out을 배열로 만들어 놓으면 파라미터로 가능
genvar i;
generate
half_adder ha0(.A(A), .B(data_in[0]), .S(data_out[0]), .C(carry_out[0])); //첫번째 hadder만 그대로 받아야하니까 만들어놓음
for (i=1; i<N; i=i+1)begin
half_adder ha(.A(carry_out[i-1]), .B(data_in[i]), .S(data_out[i]), .C(carry_out[i]));
end
endgenerate
endmodule
테스터 벤치 코드
`timescale 1ns / 1ps
module tb_program_addr_counter();
reg clk, reset_p, pc_inc, load_pc, pc_o_en;
reg [7:0] pc_in;
wire [7:0] pc_out;
program_addr_counter DUT(
.clk(clk),
.reset_p(reset_p),
.pc_inc(pc_inc),
.load_pc(load_pc),
.pc_o_en(pc_o_en),
.pc_in(pc_in),
.pc_out(pc_out)
);
initial begin
clk = 0; reset_p = 1; pc_inc = 0; load_pc = 0; pc_o_en = 1;
pc_in = 8'b00010011;
end
always #50 clk = ~clk;
initial begin
#100;
reset_p = 0; #100;
pc_inc = 1; #500;
load_pc = 1; #100;
load_pc = 0; #500;
pc_o_en = 0; #100;
pc_o_en = 1; #100;
pc_o_en = 0; #100;
reset_p = 1; #100;
reset_p = 0; #100;
$finish;
end
endmodule
시뮬레이션 결과
pc_inc = 1일 때 clk의 상승에지에서 pc_out의 값은 ++
loda_pc의 값이 1일 때, clk의 상승에지에서 pc_out은 pc_in의 값을 불러온다.
pc_in이 0일 때, pc_out은 임피던스
reset_p가 1일 때 0으로 초기화 = pc_out의 첫 0이 나온 이유는 첫 clk의 상승에지에서 reset_p가 1이기 때문에 0이 된 상태.
zero_flag = 1이면 연산결과가 참, 0이면 거짓
sigh_flag 연산결과가 양이면 1, 음이면 0
carry_flag 올림수가 발생하면 1, 그대로면 0
가감산기 코드
module fadd_subNbit #(parameter N = 4)(
input [N-1:0] A,
input [N-1:0] B,
input Cin,
output [N-1:0] S,
output Cout
);
wire [N:0] carry_out;
//carry_out을 배열로 만들어 놓으면 파라미터로 가능
assign carry_out[0] = Cin;
assign Cout = carry_out[N];
genvar i;
generate
for (i=0; i<N; i=i+1)begin
fadder fa(.A(A[i]), .B(B[i]^Cin), .Cin(carry_out[i]), .S(S[i]), .Cout(carry_out[i+1])); //^Cin 으로 빼기가 가능해짐.
end
endgenerate
endmodule
가감산기 테스터벤치 코드
`timescale 1ns / 1ps
module tb_fadd_subNbit();
parameter N = 4;
reg [N-1:0] A, B;
reg Cin;
wire [N-1:0]S;
wire Cout;
fadd_subNbit #(.N(N)) DUT(.A(A), .B(B), .Cin(Cin), .S(S), .Cout(Cout));
initial begin
A = 4'b1010;
B = 4'b0100;
Cin = 0;
#100;
Cin = 1;
#100; $finish;
end
endmodule
alu 코드
`timescale 1ns / 1ps
module alu(
input clk, reset_p, op_add, op_sub, op_and, op_mul, op_div, alu_lsb,
input [3:0] acc_high,
input [3:0] bus_reg_data,
output [3:0] alu_out,
output zero_flag, sign_flag, carry_flag, cout
);
wire [3:0] sum;
wire zero_sum;
fadd_subNbit #(.N(4))fadd_sub4bit(.A(acc_high), .B(bus_reg_data), .Cin(op_sub|op_div), .S(sum), .Cout(cout));
assign alu_out = op_and ? (acc_high & bus_reg_data) : sum;
//op_and가 1일 때라는 뜻,
//acc_high & bus_reg_data이게 나옴. 외에는 sum
//2x1 mux, 조건연산자는 mux가 만들어진다.
register sign_f(.d(!(cout)&op_sub), .clk(clk), .reset_p(reset_p), .in_en(op_sub), .q(sign_flag));
//결과가 -일 때 carry는 0. 음수가 발생하면 flag
register carry_f(.d((op_add|op_div|(op_mul&alu_lsb))&cout), .clk(clk), .reset_p(reset_p), .in_en(1'b1), .q(carry_flag));
//alu_lsb는 곱셈할 때
assign zero_sum = ~(|sum); //zero_sum은 sum이 0일 때 1. sum = 0일 때 or연산이 0이어야 하기때문에 식을 저렇게 함
register zero_f(.d(zero_sum), .clk(clk), .reset_p(reset_p), .in_en(op_sub), .q(zero_flag));
//연산의 결과가 0일때 zero flag 발생
endmodule
alu 테스터벤치 코드
`timescale 1ns / 1ps
module tb_alu();
reg clk, reset_p, op_add, op_sub, op_and, op_mul, op_div, alu_lsb;
reg [3:0] acc_high, bus_reg_data;
wire [3:0] alu_out;
wire zero_flag, sign_flag, carry_flag, cout;
alu DUT(
clk, reset_p, op_add, op_sub, op_and, op_mul, op_div, alu_lsb,
acc_high,
bus_reg_data,
alu_out,
zero_flag, sign_flag, carry_flag, cout
);
initial begin
acc_high = 4'b0101;
bus_reg_data = 4'b0010;
op_add = 0;
op_sub = 0;
op_mul = 0;
op_div = 0;
clk = 0;
reset_p = 1;
op_and = 0;
end
always #50 clk = ~clk;
// initial begin
// #100;
// reset_p = 0;#100;
// op_add = 1; #100;
// op_add = 0; op_sub = 1; #100;
// op_sub = 0; op_and = 1; #100;
// op_and = 0; #100;
// $finish;
// end
initial begin
#100;
reset_p = 0; #100;
acc_high = 4'b1101; bus_reg_data = 4'b0111; op_add = 1; #100;
op_add = 0; acc_high = 4'b0101; bus_reg_data = 4'b1010; op_sub = 1; #100;
bus_reg_data = 4'b0101; #100;
op_sub = 0; #100;
$finish;
end
endmodule
alu 테스터벤치 결과
0100
+ 1
---------
0101 = 5
'Verilog > Verilog 실습' 카테고리의 다른 글
Verilog 다목적 시계 (0) | 2023.05.16 |
---|---|
Verilog HC-SR04 초음파센서 제어 (0) | 2023.05.16 |
Verilog [CPU만들기] ACC (2) | 2023.05.16 |
Verilog ADC로 전압값을 BCD로 변환 (0) | 2023.05.04 |
Verilog basys3으로 DHT11 제어하기 (0) | 2023.05.03 |