Please wait ...
-
-
-
RV32I_R_Type
RV32I_R_Type
✅ DataPath.sv
`timescale 1ns / 1ps
module DataPath (
input logic clk,
input logic reset,
input logic [31:0] instrCode,
input logic regFileWe,
input logic [ 3:0] aluControl,
output logic [31:0] instrMemAddr
);
logic [31:0] aluResult;
logic [31:0] RFData1, RFData2;
logic [31:0] PCSrcData, PCOutData;
assign instrMemAddr = PCOutData;
RegisterFile U_RegFile (
.clk (clk),
.we (regFileWe),
.RA1 (instrCode[19:15]),
.RA2 (instrCode[24:20]),
.WA (instrCode[11: 7]),
.WD (aluResult),
.RD1 (RFData1),
.RD2 (RFData2)
);
alu U_ALU (
.aluControl(aluControl),
.a (RFData1),
.b (RFData2),
.result (aluResult)
);
register U_PC (
.clk (clk),
.reset (reset),
.en (1'b1),
.d (PCSrcData),
.q (PCOutData)
);
adder U_PC_Adder(
.a (32'd4),
.b (PCOutData),
.y (PCSrcData)
);
endmodule
module alu (
input logic [ 3:0] aluControl,
input logic [31:0] a,
input logic [31:0] b,
output logic [31:0] result
);
always_comb begin
result = 32'bx;
case (aluControl)
4'b0000: result = a + b; // add
4'b0001: result = a - b; // sub
4'b0010: result = a & b; // and
4'b0011: result = a | b; // or
4'b0100: result = a << b; // sll
4'b0101: result = a >> b; // srl
4'b0110: result = $signed(a) >>> b; // sra
4'b0111: result = ($signed(a) < $signed(b)) ? 1 : 0; // slt
4'b1000: result = (a < b) ? 1 : 0; // sltu
4'b1001: result = a ^ b; // xor
endcase
end
endmodule
module RegisterFile (
input logic clk,
input logic we,
input logic [ 4:0] RA1,
input logic [ 4:0] RA2,
input logic [ 4:0] WA,
input logic [31:0] WD,
output logic [31:0] RD1,
output logic [31:0] RD2
);
logic [31:0] mem [0:2**5-1];
always_ff @(posedge clk) begin
if(we) begin
mem[WA] <= WD;
end
end
assign RD1 = (RA1 != 0) ? mem[RA1] : 32'b0;
assign RD2 = (RA2 != 0) ? mem[RA2] : 32'b0;
endmodule
module register (
input logic clk,
input logic reset,
input logic en,
input logic [31:0] d,
output logic [31:0] q
);
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
q <= 0;
end
else begin
if(en) begin
q <= d;
end
end
end
endmodule
module adder (
input logic [31:0] a,
input logic [31:0] b,
output logic [31:0] y
);
assign y = a + b;
endmodule
Test를 위한 regFile 수정
module RegisterFile (
input logic clk,
input logic we,
input logic [ 4:0] RA1,
input logic [ 4:0] RA2,
input logic [ 4:0] WA,
input logic [31:0] WD,
output logic [31:0] RD1,
output logic [31:0] RD2
);
logic [31:0] mem [0:2**5-1];
initial begin // for Simulation Test
for (int i = 0; i < 32; i++) begin
mem[i] = 10 + i;
end
end
always_ff @(posedge clk) begin
if(we) begin
mem[WA] <= WD;
end
end
assign RD1 = (RA1 != 0) ? mem[RA1] : 32'b0;
assign RD2 = (RA2 != 0) ? mem[RA2] : 32'b0;
endmodule
✅ ControlUnit.sv
Single-Cycle은 combinational logic으로 구현.
wire로 선언한 이유?
=> logic으로는 {instrCode[30], instrCode[14:12]}이게 안됌.
=> 사용하려면 assign으로 연결
logic [6:0] opcode;
logic [3:0] operator;
assign opcode = instrCode[6:0];
assign operator = {instrCode[30], instrCode[14:12]};
`timescale 1ns / 1ps
module ControlUnit (
input logic [31:0] instrCode,
output logic regFileWe,
output logic [ 3:0] aluControl
);
wire [6:0] opcode = instrCode[6:0];
wire [3:0] operator = {instrCode[30], instrCode[14:12]}; // function
always_comb begin
regFileWe = 1'b0;
case (opcode)
7'b0110011: regFileWe = 1'b1; // R-Type
endcase
end
always_comb begin
aluControl = 2'bx;
case (opcode)
7'b0110011: begin // R-Type
aluControl = 2'bx;
case (operator)
4'b0000: aluControl = 4'b0000; // ADD
4'b1000: aluControl = 4'b0001; // SUB
4'b0111: aluControl = 4'b0010; // AND
4'b0110: aluControl = 4'b0011; // OR
4'b0001: aluControl = 4'b0100; // SLL
4'b0101: aluControl = 4'b0101; // SRL
4'b1101: aluControl = 4'b0110; // SRA
4'b0010: aluControl = 4'b0111; // SLT
4'b0011: aluControl = 4'b1000; // SLTU
4'b0100: aluControl = 4'b1001; // XOR
endcase
end
endcase
end
endmodule
✅ ROM.sv
4의 배수로 나눈 값이랑 같다.
`timescale 1ns / 1ps
module ROM (
input logic [31:0] addr,
output logic [31:0] data
);
logic [31:0] rom[0:61];
assign data = rom[addr[31:2]];
endmodule
어셈블리어에 대한 머신 코드이다.
`timescale 1ns / 1ps
module ROM (
input logic [31:0] addr,
output logic [31:0] data
);
logic [31:0] rom[0:61];
initial begin // for Simulation Test
// rom[x] = 32'b funct7 _ rs2 _ rs1 _ funct3 _ rd _ op
// 어셈블리어에 대한 머신 코드이다.
rom[0] = 32'b0000000_00001_00010_000_01000_0110011; // add x8, x2, x1
rom[1] = 32'b0100000_00010_00001_000_01001_0110011; // sub x9, x1, x2
rom[2] = 32'b0000000_00100_00011_111_01010_0110011; // and x10, x3, x4
rom[3] = 32'b0000000_00011_00100_110_01011_0110011; // or x11, x4, x3
rom[4] = 32'b0000000_00101_00001_001_01100_0110011; // sll x12, x1, x5
rom[5] = 32'b0000000_00101_00100_101_01101_0110011; // srl x13, x4, x5
rom[6] = 32'b0100000_00101_00100_101_01110_0110011; // sra x14, x4, x5
rom[7] = 32'b0000000_00010_00100_010_01111_0110011; // slt x15, x4, x2
rom[8] = 32'b0000000_00000_00011_011_10000_0110011; // sltu x16, x3, x0
rom[9] = 32'b0000000_00100_00011_100_10001_0110011; // xor x17, x3, x4
end
assign data = rom[addr[31:2]];
endmodule
✅ MCU.sv
`timescale 1ns / 1ps
module MCU(
input logic clk,
input logic reset
);
logic [31:0] instrMemAddr, instrCode;
CPU_RV32I U_CPU_RV32I (
.clk (clk),
.reset (reset),
.instrCode (instrCode),
.instrMemAddr (instrMemAddr)
);
ROM U_ROM(
.addr (instrMemAddr),
.data (instrCode)
);
endmodule
✅ TestBench
`timescale 1ns / 1ps
module tb_RV32I();
logic clk;
logic reset;
MCU U_DUT (.*);
always#5 clk = ~clk;
initial begin
clk = 0;
reset = 1;
#20;
reset = 0;
#60;
$finish();
end
endmodule
✅ 자동 검증 TestBench
`timescale 1ns / 1ps
`include "../../sources_1/new/opcode.vh"
`include "../../sources_1/new/mem_path.vh"
module tb_RV32I();
logic clk;
logic reset;
MCU U_MCU (
.clk (clk),
.reset(reset)
);
always#5 clk = ~clk;
task init;
int i;
for (int i = 0; i < 62; i++) begin
`INSTR_PATH.rom[i] = 32'h00000000;
end
for (int i = 0; i < 32; i++) begin
`RF_PATH.mem[i] = 32'h00000000;
end
endtask
task reset_cpu;
repeat(3) begin
@(posedge clk);
reset = 1;
end
@(posedge clk);
reset = 0;
endtask
logic [31:0] cycle;
logic done;
logic [31:0] current_test_id = 0;
logic [255:0] current_test_type;
logic [31:0] current_output;
logic [31:0] current_result;
logic all_tests_passed = 0;
wire [31:0] timeout_cycle = 25;
initial begin
while (all_tests_passed === 0) begin
@(posedge clk);
if (cycle === timeout_cycle) begin
$display("[Failed] Timeout at [%d] test %s, expected_result = %h, got = %h", current_test_id, current_test_type, current_result, current_output);
$finish();
end
end
end
always_ff @(posedge clk) begin
if (done === 0) cycle <= cycle + 1;
else cycle <= 0;
end
task check_result (input logic [4:0] addr, input [31:0] expect_value, input [255:0] test_type);
done = 0;
current_test_id = current_test_id + 1;
current_test_type = test_type;
current_result = expect_value;
while (`RF_PATH.mem[addr] !== expect_value) begin
current_output = `RF_PATH.mem[addr];
@(posedge clk);
end
cycle = 0;
done = 1;
$display("[%d] Test %s passed!", current_test_id, test_type);
endtask
logic [ 4:0] RS0, RS1, RS2, RS3, RS4, RS5;
logic [31:0] RD0, RD1, RD2, RD3, RD4, RD5;
initial begin
clk = 0;
reset = 1;
#10;
reset = 0;
#10;
// R-Type TEST
if(1) begin
init();
RS0 = 0; RD0 = 32'h0000_0000;
RS1 = 1; RD1 = 32'h0000_0001;
RS2 = 2; RD2 = 32'h7FFF_FFFF;
RS3 = 3; RD3 = 32'hFFFF_FFFF;
RS4 = 4; RD4 = 32'h8000_0000;
RS5 = 5; RD5 = 32'h0000_001F;
`RF_PATH.mem[RS1] = RD1; //x1 data
`RF_PATH.mem[RS2] = RD2; //x2 data
`RF_PATH.mem[RS3] = RD3; //x3 data
`RF_PATH.mem[RS4] = RD4; //x4 data
`RF_PATH.mem[RS5] = RD5; //x5 data
// Format: {funct7, rs2, rs1, funct3, rd, opcode}
`INSTR_PATH.rom[0] = {`FNC7_0, RS1, RS2, `FNC_ADD_SUB, 5'd8, `OPC_ARI_RTYPE}; // add x8, x2, x1
`INSTR_PATH.rom[1] = {`FNC7_1, RS2, RS1, `FNC_ADD_SUB, 5'd9, `OPC_ARI_RTYPE}; // sub x9, x1, x2
`INSTR_PATH.rom[2] = {`FNC7_0, RS4, RS3, `FNC_AND, 5'd10, `OPC_ARI_RTYPE}; // and x10, x3, x4
`INSTR_PATH.rom[3] = {`FNC7_0, RS3, RS4, `FNC_OR, 5'd11, `OPC_ARI_RTYPE}; // or x11, x4, x3
`INSTR_PATH.rom[4] = {`FNC7_0, RS5, RS1, `FNC_SLL, 5'd12, `OPC_ARI_RTYPE}; // sll x12, x1, x5
`INSTR_PATH.rom[5] = {`FNC7_0, RS5, RS4, `FNC_SRL_SRA, 5'd13, `OPC_ARI_RTYPE}; // srl x13, x4, x5
`INSTR_PATH.rom[6] = {`FNC7_1, RS5, RS4, `FNC_SRL_SRA, 5'd14, `OPC_ARI_RTYPE}; // sra x14, x4, x5
`INSTR_PATH.rom[7] = {`FNC7_0, RS2, RS4, `FNC_SLT, 5'd15, `OPC_ARI_RTYPE}; // slt x15, x4, x2
`INSTR_PATH.rom[8] = {`FNC7_0, RS0, RS3, `FNC_SLTU, 5'd16, `OPC_ARI_RTYPE}; // sltu x16, x3, x0
`INSTR_PATH.rom[9] = {`FNC7_0, RS4, RS3, `FNC_XOR, 5'd17, `OPC_ARI_RTYPE}; // xor x17, x3, x4
reset_cpu();
#10; check_result(8, 32'h8000_0000, "R-Type ADD");
#10; check_result(9, 32'h8000_0002, "R-Type SUB");
#10; check_result(10, 32'h8000_0000, "R-Type AND");
#10; check_result(11, 32'hFFFF_FFFF, "R-Type OR");
#10; check_result(12, 32'h8000_0000, "R-Type SLL");
#10; check_result(13, 32'h0000_0001, "R-Type SRL");
#10; check_result(14, 32'hFFFF_FFFF, "R-Type SRA");
#10; check_result(15, 32'h0000_0001, "R-Type SLT");
#10; check_result(16, 32'h0000_0000, "R-Type SLTU");
#10; check_result(17, 32'h7FFF_FFFF, "R-Type XOR");
end
// I-Type TEST
if(0) begin
init();
reset_cpu();
end
all_tests_passed = 1'b1;
repeat(10) @(posedge clk);
$display("All tests passed!");
$finish();
end
endmodule
경로 매크로 설정
// 레지스터 파일(Register File)
`define RF_PATH U_MCU.U_CPU_RV32I.U_DataPath.U_RegFile
// 명령어 메모리(Instruction Memory)
`define INSTR_PATH U_MCU.U_ROM
명령어 및 함수 코드 매크로
// List of RISC-V opcodes and funct codes.
// Use `include "opcode.vh" to use these in the decoder
`ifndef OPCODE
`define OPCODE
// Arithmetic instructions
`define OPC_ARI_RTYPE 7'b0110011
// ***** 5-bit Opcodes *****
`define OPC_ARI_RTYPE_5 5'b01100
// Arithmetic R-type and I-type functions codes
`define FNC_ADD_SUB 3'b000
`define FNC_SLL 3'b001
`define FNC_SLT 3'b010
`define FNC_SLTU 3'b011
`define FNC_XOR 3'b100
`define FNC_OR 3'b110
`define FNC_AND 3'b111
`define FNC_SRL_SRA 3'b101
`define FNC7_0 7'b0000000 // ADD, SRL
`define FNC7_1 7'b0100000 // SUB, SRA
`endif //OPCODE
테스트 초기화 / 리셋
레지스터 파일(RF)과 명령어 메모리(ROM)를 모두 0으로 초기화
CPU reset
task init;
int i;
for (int i = 0; i < 62; i++) begin
`INSTR_PATH.rom[i] = 32'h00000000;
end
for (int i = 0; i < 32; i++) begin
`RF_PATH.mem[i] = 32'h00000000;
end
endtask
task reset_cpu;
repeat(3) begin
@(posedge clk);
reset = 1;
end
@(posedge clk);
reset = 0;
endtask
테스트 결과 검증 및 타임아웃 관리
각 테스트 결과를 자동 검증, 일정 Cycle내에 결과가 나오지 않으면 에러 메시지 출력 후 종료
실패 시 어떤 테스트에서 어떤 값이 잘못되었는지 상세 정보 출력
wire [31:0] timeout_cycle = 25;
initial begin
while (all_tests_passed === 0) begin
@(posedge clk);
if (cycle === timeout_cycle) begin
$display("[Failed] Timeout at [%d] test %s, expected_result = %h, got = %h", current_test_id, current_test_type, current_result, current_output);
$finish();
end
end
end
always_ff @(posedge clk) begin
if (done === 0) cycle <= cycle + 1;
else cycle <= 0;
end
task check_result (input logic [4:0] addr, input [31:0] expect_value, input [255:0] test_type);
done = 0;
current_test_id = current_test_id + 1;
current_test_type = test_type;
current_result = expect_value;
while (`RF_PATH.mem[addr] !== expect_value) begin
current_output = `RF_PATH.mem[addr];
@(posedge clk);
end
cycle = 0;
done = 1;
$display("[%d] Test %s passed!", current_test_id, test_type);
endtask
R-Type 명령어 테스트
// R-Type TEST
if(1) begin
init();
RS0 = 0; RD0 = 32'h0000_0000;
RS1 = 1; RD1 = 32'h0000_0001;
RS2 = 2; RD2 = 32'h7FFF_FFFF;
RS3 = 3; RD3 = 32'hFFFF_FFFF;
RS4 = 4; RD4 = 32'h8000_0000;
RS5 = 5; RD5 = 32'h0000_001F;
`RF_PATH.mem[RS1] = RD1; //x1 data
`RF_PATH.mem[RS2] = RD2; //x2 data
`RF_PATH.mem[RS3] = RD3; //x3 data
`RF_PATH.mem[RS4] = RD4; //x4 data
`RF_PATH.mem[RS5] = RD5; //x5 data
// Format: {funct7, rs2, rs1, funct3, rd, opcode}
`INSTR_PATH.rom[0] = {`FNC7_0, RS1, RS2, `FNC_ADD_SUB, 5'd8, `OPC_ARI_RTYPE}; // add x8, x2, x1
`INSTR_PATH.rom[1] = {`FNC7_1, RS2, RS1, `FNC_ADD_SUB, 5'd9, `OPC_ARI_RTYPE}; // sub x9, x1, x2
`INSTR_PATH.rom[2] = {`FNC7_0, RS4, RS3, `FNC_AND, 5'd10, `OPC_ARI_RTYPE}; // and x10, x3, x4
`INSTR_PATH.rom[3] = {`FNC7_0, RS3, RS4, `FNC_OR, 5'd11, `OPC_ARI_RTYPE}; // or x11, x4, x3
`INSTR_PATH.rom[4] = {`FNC7_0, RS5, RS1, `FNC_SLL, 5'd12, `OPC_ARI_RTYPE}; // sll x12, x1, x5
`INSTR_PATH.rom[5] = {`FNC7_0, RS5, RS4, `FNC_SRL_SRA, 5'd13, `OPC_ARI_RTYPE}; // srl x13, x4, x5
`INSTR_PATH.rom[6] = {`FNC7_1, RS5, RS4, `FNC_SRL_SRA, 5'd14, `OPC_ARI_RTYPE}; // sra x14, x4, x5
`INSTR_PATH.rom[7] = {`FNC7_0, RS2, RS4, `FNC_SLT, 5'd15, `OPC_ARI_RTYPE}; // slt x15, x4, x2
`INSTR_PATH.rom[8] = {`FNC7_0, RS0, RS3, `FNC_SLTU, 5'd16, `OPC_ARI_RTYPE}; // sltu x16, x3, x0
`INSTR_PATH.rom[9] = {`FNC7_0, RS4, RS3, `FNC_XOR, 5'd17, `OPC_ARI_RTYPE}; // xor x17, x3, x4
reset_cpu();
#10; check_result(8, 32'h8000_0000, "R-Type ADD");
#10; check_result(9, 32'h8000_0002, "R-Type SUB");
#10; check_result(10, 32'h8000_0000, "R-Type AND");
#10; check_result(11, 32'hFFFF_FFFF, "R-Type OR");
#10; check_result(12, 32'h8000_0000, "R-Type SLL");
#10; check_result(13, 32'h0000_0001, "R-Type SRL");
#10; check_result(14, 32'hFFFF_FFFF, "R-Type SRA");
#10; check_result(15, 32'h0000_0001, "R-Type SLT");
#10; check_result(16, 32'h0000_0000, "R-Type SLTU");
#10; check_result(17, 32'h7FFF_FFFF, "R-Type XOR");
end
✅ 결과
[Failed]
[Passed]
[Simulation_Result]
-
PortFolio
📑 목차
📑 목차
필수 분석 3요소
직무분석
직무 분석을 위한 정보 출처
분석 후 정리
직무 분석의 흐름
기업 분석 (Company Analysis)
기업 분석의 구조화
기업 분석을 위한 정보 출처
산업 분석 (Industry Analysis)
산업 분석의 핵심 요소
분석 후 정리
입사지원서
작성 전 점검사항
피해야 할 입사지원서의 특징
당사 양식 (회사 지정 양식)
자유 양식 (이력서, CV 등)
기본 구성 항목 및 핵심
성장과정
📝 핵심 작성 포인트
❌ 피해야 할 내용
성격의 장단점
📝 핵심 작성 포인트
❌ 주의사항
직무 경험
📝 핵심 작성 포인트
지원동기 및 입사 후 포부
📝 작성 흐름
경험을 논리적으로 풀어내는 스토리텔링 기법
대표 기법: STAR
기타 기법
✅ 제출 전 최종 점검사항
📝 작성 점검사항
👀 가독성을 높이는 방법
📝 면접 질문 대비 체크리스트
💺 자세와 태도
🗣️ 말하기 습관
🎯 직무 관련
🔄 이직 사유 답변
📌 기타
필수 분석 3요소
직무 분석: 내가 할 일은 무엇인가?
기업 분석: 내가 일할 곳은 어떤 곳인가?
산업 분석: 내가 속할 분야의 현재와 미래는 어떠한가?
직무분석
직무 분석 방법
선택 직무에 대한 구체적 역할과 필요 역량 확인
내가 잘할 수 있을까?
내가 좋아하는 일을 수행하는 직무인가?
**지원 직무가 회사에 기여할 수 있는 성과는 무엇인가?**
직무 수행을 위해 본인이 준비한 역량은 무엇인가?
직무 수행을 위해 본인이 가장 부족한 역량은 무엇인가?
부족한 역량을 보완을 위해 어떤 노력을 할 것인가?
구체적으로 하는 일 -> 필요한 KSA -> 자신이 보유한 KSA -> 그것을 근거한 사례 ->
직무 분석을 위한 정보 출처
고용24: 취업 지원 및 직업 정보
NCS (국가직무능력표준): 직무기술서 및 상세 역할 검색
기업 홈페이지: 직무 소개 및 인재상
동영상 채널 (YouTube): 현직자 인터뷰 및 직무 브이로그
취업포털 사이트: 채용공고의 직무 설명(JD), 현직자 관련 정보
직무 관련 커뮤니티: 현업 실무자들의 생생한 이야기
분석 후 정리
핵심 역량 파악: 분석을 통해 파악한 핵심 역량을 포트폴리오에 녹여내야 한다.
성공 가능성 예측: 직무에 대한 이해를 바탕으로 자신의 성공 가능성을 가늠한다.
보완 계획 수립: 부족한 점을 파악하고, 앞으로의 역량 개발 계획을 세운다.
직무 적합성 어필: 핵심 역량에 집중하여 자신이 얼마나 준비된 인재인지 보여준다.
직무 분석의 흐름
하는 일 → 필요 역량(KSA) → 보유 역량(KSA) → 경험적 근거(사례) → 미보유 역량 → 보완 계획
기업 분석 (Company Analysis)
Point! “알게 되었습니다”라는 수동적인 태도보다, “이러한 점을 파악하고 이에 맞춰 OOO을 준비했습니다” 와 같이 능동적인 자세를 보여주는 것이 중요.
기업 분석의 구조화
기본 정보
비전, 미션, 전략: 회사가 나아갈 방향을 이해. (‘왜’ 이 비전을 수립했는지, ‘어떻게’ 실천하고 있는지 사례를 파악하는 것이 중요.)
회사 개요, 창업 이념, 경영 화두: 회사의 근본적인 가치를 파악.
인재상 및 핵심 가치
인재상 확인: 기업이 어떤 사람을 원하는지 파악.
나만의 정의: 해당 인재상에 대한 자신만의 정의를 내리고, 왜 필요한지 이해. (예: “OOO이 이 기업의 강점이기에, 이를 발전시킬 수 있는 OOO 역량을 갖춘 인재가 필요하구나.”)
사업 현황
수익 구조: 회사가 어떻게 돈을 버는지 분석. (주력 제품, 서비스 등)
재무 상태: 최근 매출과 영업이익의 추이를 확인.
미래 과제 및 이슈
강점과 약점(SWOT): 회사의 현재 위치와 잠재력을 분석.
최신 이슈: 최근 기업이 마주한 과제나 기회를 파악.
신년사 활용:
올해의 키워드: 신년사에서 강조하는 키워드를 활용하여 자신의 포부를 연결.
과거 신년사 비교 (최근 3년): 회사의 목표가 어떻게 변화해왔는지 흐름을 파악.
경쟁사 신년사 비교: 업계의 전반적인 동향과 키워드를 파악.
기업 분석을 위한 정보 출처
기업 홈페이지
회사 소개: 연혁, 경영 이념, 인재상, 비전, 미션 등
제품 및 서비스: 브랜드 소개 및 상세 정보
홍보 센터/뉴스룸: 최근 이슈, 보도자료, 사내 소식지 등
최근 보도자료
사업 동향: 신규 사업, 주력 사업의 진행 상황
업계 현황: 업계 내 기업의 위치와 이슈
사업 목표: 신년사, 인터뷰 등을 통해 드러난 목표 확인
DART (전자공시시스템)
사업 보고서: 사업의 규모, 전략, 재무 현황 등 가장 신뢰도 높은 정보
재무제표 분석: 매출액, 영업이익, 당기순이익 등의 변화를 파악. (Point! “매출이 올랐다”에서 그치지 말고, 왜, 어떻게 올랐는지 원인을 분석해야 함.)
산업 분석 (Industry Analysis)
Point! 내가 왜 ‘이 산업’을 선택했는지에 대한 명확한 기준과 이유를 제시해야 함.
산업 분석의 핵심 요소
산업 선택 기준: 내가 이 산업을 선택한 이유는 무엇인가?
경쟁 우위 요소: 해당 산업에서 경쟁 우위를 확보하기 위해 필요한 것은 무엇인가?
최신 이슈와 트렌드: 최근 산업 동향(예: 반도체 동향)은 어떠하며, 지원 기업은 이에 어떻게 대응하고 있는가?
산업의 필요성: 해당 산업이 사회나 경제에 왜 필요한지 이해해야 한다.
분석 후 정리
역량 매칭: 나의 역량을 기업의 인재상, 비전, 그리고 산업의 필요성과 연결.
개발 방향 제시: 현재 부족한 역량을 산업의 미래와 연관 지어 어떻게 개발할지 방향을 제시.
포부 정립: 기업의 비전과 함께 성장하며 산업에 기여할 수 있는 자신의 포부를 구체적으로 정리.
입사지원서
간결함과 핵심: 모든 내용은 핵심 위주로 간결하게 작성합니다. 불필요한 미사여구나 설명은 피하기.
구체적인 경험: 성인이 된 이후의 경험을 바탕으로 작성하여 직무 역량과의 연관성을 보여줌.
균형 있는 분량: 각 항목의 글자 수를 550~600자 내외로 균형감 있게 맞추는 것이 좋다.
프로젝트 기술서: 경력이나 프로젝트를 상세히 기술할 경우, 가장 중요한 내용만 담아 10~15 페이지 이내로 정리.
작성 전 점검사항
핵심 분석: 직무, 기업, 산업에 대한 필수 분석을 마쳤는가?
강점 정리: 나의 어떤 강점과 경험을 내세울 것인지 명확히 정리되었는가?
직무 적합성: 나의 경험과 역량이 지원 직무와 높은 관련성을 가지는가?
매력 어필: 나를 차별화할 수 있는 매력 포인트를 어떻게 어필할지 준비되었는가?
피해야 할 입사지원서의 특징
어필 포인트 부재: 지원자만의 뚜렷한 장점이나 매력이 보이지 않음.
단조로운 구성: 특색 없는 문장과 구성으로 지루한 느낌.
신뢰성 부족: 객관적으로 검증하기 어려운 경력이나 역량만 나열.
차별성 없음: 어느 회사에 지원해도 무방할 정도로 일반적인 내용으로 채움.
예측 불가능성: 지원자의 성향이나 성격을 전혀 파악할 수 없다.
부실한 내용: 분량은 채웠지만, 내용이 허술하고 깊이가 없다.
당사 양식 (회사 지정 양식)
특징: 회사가 지정한 고정된 양식으로, 질문 항목이나 틀을 수정할 수 없다.
작성법: 주어진 항목에 맞춰 내용을 충실하게 작성하는 것이 중요. 모든 지원자가 동일한 기준으로 평가.
자유 양식 (이력서, CV 등)
특징: 정해진 틀 없이 지원자가 자유롭게 구성하는 양식.
작성법: 자신에게 가장 유리한 항목으로만 구성하고, 공란(빈칸)은 절대 만들지 않는다.
기본 구성 항목 및 핵심
성장과정: 가치관과 신념이 형성된 과정을 성인의 경험으로 증명
성격의 장단점: 직무와 관련된 강점, 그리고 단점을 극복하려는 노력
직무 경험: 직무와 직접적으로 연관된 경험과 이를 통해 배운 역량
지원동기 및 입사 후 포부: 나는 왜 이 회사, 이 직무에 적합한 인재인가?
성장과정
“어릴 적 이야기”가 아닌 “성인으로서 가치관을 키워온 과정”을 보여주는 것이 핵심.
📝 핵심 작성 포인트
신념/기준 제시: 지원자가 중요하게 생각하며 성장시켜온 신념이나 기준을 제시.
구체적 사례: 그 신념을 장기간 실천해 온 성인 시절의 사례를 들어 증명한다.
역량 연결: 희망 직무에 필요한 성향이나 조직 융화 관련 강점을 키워온 경험을 연결한다.
❌ 피해야 할 내용
“선천적으로~”, “어린 시절 저는~” 과 같이 과거에만 머무는 서술
“성실합니다. 그래서 지각, 결석을 한 적이 없습니다.” 와 같이 당연한 이야기
성격의 장단점
장점은 직무와의 연관성을, 단점은 솔직함과 개선 의지를 보여주는 항목.
📝 핵심 작성 포인트
직무 연관성: 직무와 직접적으로 연관되는 강점을 구체적인 경험과 함께 제시.
개선 노력: 단점은 솔직하게 인정하고, 이를 보완하기 위한 노력을 반드시 함께 작성.
황금 비율: 장점과 단점의 분량 비율은 7:3 정도가 이상적.
❌ 주의사항
“지나치게 꼼꼼해서 시간이 오래 걸립니다.” 와 같이 장점 같은 단점은 피해야 한다.
장점과 단점은 명확히 분리해서 서술하는 것이 좋다.
직무 경험
지원 직무에 대한 이해도와 실무 역량을 직접적으로 어필하는 항목.
📝 핵심 작성 포인트
직접 경험: 인턴, 계약직, 프로젝트 등 직무와 관련된 직접적인 실무 경험을 중심으로 작성.
역할과 성과: 프로젝트에서 자신이 맡았던 구체적인 역할, 이를 통해 향상시킨 실무 역량, 그리고 배운 점을 명확히 기술.
지원동기 및 입사 후 포부
‘회사-직무-나’의 연결고리를 찾아, 나의 성장 계획을 보여주는 항목.
📝 작성 흐름
산업 분석: 현재 산업의 특성 및 이슈를 언급.
기업 분석: 그 속에서 회사가 나아가는 방향을 연결.
나의 적합성: 해당 방향을 위해 내가 기여할 수 있는 부분(역량)을 강조하며 지원 직무의 필요성을 어필.
미래 계획: 입사 후 구체적인 업무 수행 계획과 커리어 성장 계획을 제시.
예시: “최근 OO 산업은 ~라는 동향을 보입니다. 귀사는 이에 대응해 ~방향으로 나아가고 있으며, 이러한 목표 달성을 위해선 OO 역량이 필수적입니다. 저는 OOO 경험을 통해 해당 역량을 길렀기에, 귀사에서 OOO를 수행하며 함께 성장하고자 지원합니다.”
경험을 논리적으로 풀어내는 스토리텔링 기법
두괄식 구성: 결론(강점 키워드)을 문장 맨 앞에 제시하여 전달력을 높인다.
본론: 아래와 같은 기법을 활용하여 경험을 구체적으로 작성.
대표 기법: STAR
S (Situation): 언제, 어떤 계기로 경험을 시작했는가? (상황)
T (Task): 주어진 과제나 목표는 무엇이었는가? (과업)
A (Action): 목표 달성을 위해 내가 취한 구체적인 행동과 노력은 무엇이었는가? (행동)
R (Result): 그 결과는 어떠했으며, 무엇을 배우고 느꼈는가? (결과)
기타 기법
CAR: Context (상황), Action (행동), Result (결과)
IPARC: Idea (아이디어), Plan (계획), Action (행동), Result (결과), Change (변화)
✅ 제출 전 최종 점검사항
진부한 표현이나 당연한 말을 사용하지 않았는가?
줄임말, 은어, 신조어를 사용하지 않았는가?
오탈자나 문법 오류는 없는가?
📝 작성 점검사항
같은 경험을 중복 사용하지 않고, 각 항목을 다르게 구성했는가?
회사명을 정확히 기재했는가?
페이지 번호와 회사 로고를 삽입했는가?
내가 직접 읽었을 때 “읽고 싶은 입사지원서”라고 느껴지는가? (최소 3번 이상 확인)
👀 가독성을 높이는 방법
문장은 길지 않게, 핵심 위주로 작성한다.
저는, 제가, 저의로 문장을 시작하지 않는다.
단락과 문장 간 간격을 적절히 사용해 눈에 잘 들어오게 구성한다.
📝 면접 질문 대비 체크리스트
💺 자세와 태도
의자에 기대지 않기 → 편해짐 방지, 허리와 어깨 펴기
다리는 의자 너비까지만 벌리기
질문을 한 사람을 보며 답변
7초 미만의 아이컨택 유지
🗣️ 말하기 습관
말끝 흐리지 않기 (화법 중요)
추측·예측 발언은 주관이 없어 보이므로 주의
1분 자기소개 준비
서론: “OO 지원자 OOO입니다.”
본론: 엔지니어로서의 역량, 대표 사례, 달성 경험 제시
결론: 지원 직무와의 연결 및 포부
🎯 직무 관련
직무 이해도: 정답이 있음 (이론, 원리, 기초 지식)
직무 준비도: 정답 없음 (준비 과정과 경험 중심)
직무 적합도: 정답 없음 (조직과의 어울림, 가치관)
🔄 이직 사유 답변
단순히 “이직 이유”에만 집중하지 말고, 미래 비전과 연결
전문 지식 필요 → 교육 수강 → 산업 동향·회사 비전과 적합하여 지원
주의: 사람과의 관계 문제로 인한 이직은 부정적 평가
→ 조직은 다양한 부류의 사람들로 구성됨
📌 기타
우선순위를 재정립할 수 있는 역량을 키웠음을 강조
말하는 연습 필수
None
· 2025-08-13
-
Day5
DAY5
✅ Dedicated Processor RegFile
R1 = 0;
R2 = 0;
while(R1 <= 10){
R2 = R2 + R1;
R1 = R1 + 1;
OutPort = R2;
}
✅ 동작방식
✅ RegFile Asm
✅ 코드
DataPath.sv
`timescale 1ns / 1ps
module DataPath(
input logic clk,
input logic reset,
input logic RFSrcMuxSel,
input logic [2:0] RAddr1,
input logic [2:0] RAddr2,
input logic [2:0] WAddr,
input logic we,
output logic R1Le10,
input logic OutPortEn,
output logic [7:0] OutPort
);
logic [7:0] AdderResult, RFSrcMuxOut;
logic [7:0] RData1, RData2;
mux_2X1 U_RFSrcMux (
.sel (RFSrcMuxSel),
.x0 (AdderResult),
.x1 (1),
.y (RFSrcMuxOut)
);
RegFile U_RegFile (
.clk (clk),
.RAddr1 (RAddr1),
.RAddr2 (RAddr2),
.WAddr (WAddr),
.we (we),
.WData (RFSrcMuxOut),
.RData1 (RData1),
.RData2 (RData2)
);
comparator U_R1Le10 (
.a (RData1),
.b (8'd10),
.lt (R1Le10)
);
adder U_Adder (
.a (RData1),
.b (RData2),
.sum (AdderResult)
);
register U_OutPort (
.clk (clk),
.reset (reset),
.en (OutPortEn),
.d (RData1),
.q (OutPort)
);
endmodule
module RegFile (
input logic clk,
input logic [2:0] RAddr1,
input logic [2:0] RAddr2,
input logic [2:0] WAddr,
input logic we,
input logic [7:0] WData,
output logic [7:0] RData1,
output logic [7:0] RData2
);
logic [7:0] mem [0:2**3-1]; // 8bit 8개 (Addr 개수)
always_ff @(posedge clk) begin
if(we) begin
mem[WAddr] <= WData;
end
end
assign RData1 = (RAddr1 == 0) ? 8'b0 : mem[RAddr1];
assign RData2 = (RAddr2 == 0) ? 8'b0 : mem[RAddr2];
endmodule
module register (
input logic clk,
input logic reset,
input logic en,
input logic [7:0] d,
output logic [7:0] q
);
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
q <= 0;
end
else begin
if(en) begin
q <= d;
end
end
end
endmodule
module mux_2X1 (
input logic sel,
input logic [7:0] x0,
input logic [7:0] x1,
output logic [7:0] y
);
always_comb begin
y = 8'b0;
case (sel)
1'b0: y = x0;
1'b1: y = x1;
endcase
end
endmodule
module adder (
input logic [7:0] a,
input logic [7:0] b,
output logic [7:0] sum
);
assign sum = a + b;
endmodule
module comparator (
input logic [7:0] a,
input logic [7:0] b,
output logic lt
);
assign lt = a <= b;
endmodule
ControlUnit
-
DedicatedProcessor ALUOP
DedicatedProcessor ALUOP
✅ 과제
⚒️ 코드 ⚒️
⚒️[DedicatedProcessor ALUOP.sv]
✅ Schematic
✅ 시뮬레이션
✅ 분석
반복별 레지스터 값
1회: R1=3, R2=2, R3=3, R4=5 → Yes
2회: R1=7, R2=6, R3=9, R4=15 → Yes
3회: R1=15, R2=14, R3=21, R4=35 → Yes
4회: R1=31, R2=30, R3=45, R4=75 → Yes
5회: R1=63, R2=62, R3=93, R4=155 → Yes
6회: R1=127, R2=126, R3=189, R4=59 → No ⇒ halt
➡️ 첫 번째 반복
시작 값: (R1, R2, R3, R4) = (1, 0, 0, 0)
**계산 순서**
R2 = R1 + R1 (1 + 1 = 2) ➞ (1, **2**, 0, 0)
R3 = R2 + R1 (2 + 1 = 3) ➞ (1, 2, **3**, 0)
R4 = R3 - R1 (3 - 1 = 2) ➞ (1, 2, 3, **2**)
R1 = R1 | R2 (1 | 2 = 3) ➞ (**3**, 2, 3, 2)
R4 = R4 & R3 (2 & 3 = 2) ➞ (3, 2, 3, **2**)
R4 = R2 + R3 (2 + 3 = 5) ➞ (3, 2, 3, **5**)
조건 확인: R4 > R2 (5 > 2) ➞ ✅ Yes, 계속 진행
➡️ 두 번째 반복
시작 값: (R1, R2, R3, R4) = (3, 2, 3, 5)
**계산 순서**
R2 = R1 + R1 (3 + 3 = 6) ➞ (3, **6**, 3, 5)
R3 = R2 + R1 (6 + 3 = 9) ➞ (3, 6, **9**, 5)
R4 = R3 - R1 (9 - 3 = 6) ➞ (3, 6, 9, **6**)
R1 = R1 | R2 (3 | 6 = 7) ➞ (**7**, 6, 9, 6)
R4 = R4 & R3 (6 & 9 = 0) ➞ (7, 6, 9, **0**)
R4 = R2 + R3 (6 + 9 = 15) ➞ (7, 6, 9, **15**)
조건 확인: R4 > R2 (15 > 6) ➞ ✅ Yes, 계속 진행
➡️ 세 번째 반복
시작 값: (R1, R2, R3, R4) = (7, 6, 9, 15)
**계산 순서**
R2 = R1 + R1 (7 + 7 = 14) ➞ (7, **14**, 9, 15)
R3 = R2 + R1 (14 + 7 = 21) ➞ (7, 14, **21**, 15)
R4 = R3 - R1 (21 - 7 = 14) ➞ (7, 14, 21, **14**)
R1 = R1 | R2 (7 | 14 = 15) ➞ (**15**, 14, 21, 14)
R4 = R4 & R3 (14 & 21 = 4) ➞ (15, 14, 21, **4**)
R4 = R2 + R3 (14 + 21 = 35) ➞ (15, 14, 21, **35**)
조건 확인: R4 > R2 (35 > 14) ➞ ✅ Yes, 계속 진행
➡️ 네 번째 반복
시작 값: (R1, R2, R3, R4) = (15, 14, 21, 35)
**계산 순서**
R2 = R1 + R1 (15 + 15 = 30) ➞ (15, **30**, 21, 35)
R3 = R2 + R1 (30 + 15 = 45) ➞ (15, 30, **45**, 35)
R4 = R3 - R1 (45 - 15 = 30) ➞ (15, 30, 45, **30**)
R1 = R1 | R2 (15 | 30 = 31) ➞ (**31**, 30, 45, 30)
R4 = R4 & R3 (30 & 45 = 12) ➞ (31, 30, 45, **12**)
R4 = R2 + R3 (30 + 45 = 75) ➞ (31, 30, 45, **75**)
조건 확인: R4 > R2 (75 > 30) ➞ ✅ Yes, 계속 진행
➡️ 다섯 번째 반복
시작 값: (R1, R2, R3, R4) = (31, 30, 45, 75)
**계산 순서**
R2 = R1 + R1 (31 + 31 = 62) ➞ (31, **62**, 45, 75)
R3 = R2 + R1 (62 + 31 = 93) ➞ (31, 62, **93**, 75)
R4 = R3 - R1 (93 - 31 = 62) ➞ (31, 62, 93, **62**)
R1 = R1 | R2 (31 | 62 = 63) ➞ (**63**, 62, 93, 62)
R4 = R4 & R3 (62 & 93 = 28) ➞ (63, 62, 93, **28**)
R4 = R2 + R3 (62 + 93 = 155) ➞ (63, 62, 93, **155**)
조건 확인: R4 > R2 (155 > 62) ➞ ✅ Yes, 계속 진행
➡️ 여섯 번째 반복 (마지막)
시작 값: (R1, R2, R3, R4) = (63, 62, 93, 155)
**계산 순서**
R2 = R1 + R1 (63 + 63 = 126) ➞ (63, **126**, 93, 155)
R3 = R2 + R1 (126 + 63 = 189) ➞ (63, 126, **189**, 155)
R4 = R3 - R1 (189 - 63 = 126) ➞ (63, 126, 189, **126**)
R1 = R1 | R2 (63 | 126 = 127) ➞ (**127**, 126, 189, 126)
R4 = R4 & R3 (126 & 189 = 120) ➞ (127, 126, 189, **120**)
R4 = R2 + R3 (126 + 189 = 315)
8-bit Wrapping (오버플로우): 8비트 레지스터는 255까지만 표현 가능하므로, 315는 256을 뺀 나머지 값인 59가 된다. (315 - 256 = 59)
R4 최종 값 ➞ (127, 126, 189, **59**)
조건 확인: R4 > R2 (59 > 126) ➞ ❌ No, 중단 (Halt)
-
DedicatedProcessor ALUOP
DedicatedProcessor ALUOP
✅ DedicatedProcessor_ALUOP.sv
`timescale 1ns / 1ps
module DedicatedProcessor_ALUOP(
input logic clk,
input logic reset,
output logic [7:0] OutPort
);
logic RFSrcMuxSel;
logic [2:0] RAddr1;
logic [2:0] RAddr2;
logic [2:0] WAddr;
logic [1:0] AluOpMuxSel;
logic we;
logic Lt;
logic OutPortEn;
DataPath U_DataPath (
.clk (clk),
.reset (reset),
.RFSrcMuxSel(RFSrcMuxSel),
.RAddr1 (RAddr1),
.RAddr2 (RAddr2),
.WAddr (WAddr),
.AluOpMuxSel(AluOpMuxSel),
.we (we),
.Lt (Lt),
.OutPortEn (OutPortEn),
.OutPort (OutPort)
);
ControlUnit U_ControlUnit (
.clk (clk),
.reset (reset),
.RFSrcMuxSel(RFSrcMuxSel),
.RAddr1 (RAddr1),
.RAddr2 (RAddr2),
.WAddr (WAddr),
.AluOpMuxSel(AluOpMuxSel),
.we (we),
.Lt (Lt),
.OutPortEn (OutPortEn)
);
endmodule
✅ DataPath.sv
`timescale 1ns / 1ps
module DataPath (
input logic clk,
input logic reset,
input logic RFSrcMuxSel,
input logic [2:0] RAddr1,
input logic [2:0] RAddr2,
input logic [2:0] WAddr,
input logic [1:0] AluOpMuxSel,
input logic we,
output logic Lt,
input logic OutPortEn,
output logic [7:0] OutPort
);
logic [7:0] AdderResult, RFSrcMuxOut;
logic [7:0] RData1, RData2;
mux_2x1 U_RFSrcMux (
.sel(RFSrcMuxSel),
.x0 (AdderResult),
.x1 (1),
.y (RFSrcMuxOut)
);
RegFile U_RegFile (
.clk (clk),
.RAddr1(RAddr1),
.RAddr2(RAddr2),
.WAddr (WAddr),
.we (we),
.WData (RFSrcMuxOut),
.RData1(RData1),
.RData2(RData2)
);
comparator U_comparator (
.a (RData1),
.b (RData2),
.lt (Lt)
);
alu_op U_ALU_OP (
.x0 (RData1),
.x1 (RData2),
.AluOpMuxSel(AluOpMuxSel),
.y (AdderResult)
);
register U_OutPort (
.clk (clk),
.reset(reset),
.en (OutPortEn),
.d (RData1),
.q (OutPort)
);
endmodule
✅ alu_op 추가
module alu_op (
input logic [7:0] x0,
input logic [7:0] x1,
input logic [1:0] AluOpMuxSel,
output logic [7:0] y
);
always_comb begin
y = 8'b00;
case (AluOpMuxSel)
2'b00: begin
y = x0 + x1;
end
2'b01: begin
y = x0 - x1;
end
2'b10: begin
y = x0 & x1;
end
2'b11: begin
y = x0 | x1;
end
endcase
end
endmodule
✅ ControlUnit
`timescale 1ns / 1ps
module ControlUnit (
input logic clk,
input logic reset,
output logic RFSrcMuxSel,
output logic [2:0] RAddr1,
output logic [2:0] RAddr2,
output logic [2:0] WAddr,
output logic [1:0] AluOpMuxSel,
output logic we,
input logic Lt,
output logic OutPortEn
);
typedef enum {
S0,
S1,
S2,
S3,
S4,
S5,
S6,
S7,
S8,
S9,
S10,
S11,
S12,
S13
} state_e;
state_e state, next_state;
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
state <= S0;
end
else begin
state <= next_state;
end
end
always_comb begin
next_state = state;
RFSrcMuxSel = 0;
RAddr1 = 0;
RAddr2 = 0;
WAddr = 0;
AluOpMuxSel = 0;
we = 0;
OutPortEn = 0;
case (state)
S0:begin // R1 = 1
RFSrcMuxSel = 1;
RAddr1 = 0;
RAddr2 = 0;
WAddr = 1;
AluOpMuxSel = 0;
we = 1;
OutPortEn = 0;
next_state = S1;
end
S1:begin // R2 = 0
RFSrcMuxSel = 0;
RAddr1 = 0;
RAddr2 = 0;
WAddr = 3'h2;
AluOpMuxSel = 0;
we = 1;
OutPortEn = 0;
next_state = S2;
end
S2:begin // R3 = 0
RFSrcMuxSel = 0;
RAddr1 = 0;
RAddr2 = 0;
WAddr = 3'h3;
AluOpMuxSel = 0;
we = 1;
OutPortEn = 0;
next_state = S3;
end
S3:begin // R4 = 0
RFSrcMuxSel = 0;
RAddr1 = 0;
RAddr2 = 0;
WAddr = 3'h4;
AluOpMuxSel = 0;
we = 1;
OutPortEn = 0;
next_state = S4;
end
S4:begin // R2 = R1 + R1
RFSrcMuxSel = 0;
RAddr1 = 1;
RAddr2 = 1;
WAddr = 3'h2;
AluOpMuxSel = 0;
we = 1;
OutPortEn = 0;
next_state = S5;
end
S5:begin // R3 = R2 + R1
RFSrcMuxSel = 0;
RAddr1 = 3'h2;
RAddr2 = 1;
WAddr = 3'h3;
AluOpMuxSel = 0;
we = 1;
OutPortEn = 0;
next_state = S6;
end
S6:begin // R4 = R3 - R1
RFSrcMuxSel = 0;
RAddr1 = 3'h3;
RAddr2 = 1;
WAddr = 3'h4;
AluOpMuxSel = 1;
we = 1;
OutPortEn = 0;
next_state = S7;
end
S7:begin // R1 = R1 | R2
RFSrcMuxSel = 0;
RAddr1 = 3'h1;
RAddr2 = 3'h2;
WAddr = 3'h1;
AluOpMuxSel = 2'h3;
we = 1;
OutPortEn = 0;
next_state = S8;
end
S8:begin // R4 < R2
RFSrcMuxSel = 0;
RAddr1 = 3'h4;
RAddr2 = 3'h2;
WAddr = 0;
AluOpMuxSel = 0;
we = 0;
OutPortEn = 0;
if(Lt) next_state = S6;
else next_state = S9;
end
S9:begin // R4 = R4 & R3
RFSrcMuxSel = 0;
RAddr1 = 3'h4;
RAddr2 = 3'h3;
WAddr = 3'h4;
AluOpMuxSel = 2'h2;
we = 1;
OutPortEn = 0;
next_state = S10;
end
S10:begin // R4 = R2 + R3
RFSrcMuxSel = 0;
RAddr1 = 3'h2;
RAddr2 = 3'h3;
WAddr = 3'h4;
AluOpMuxSel = 2'h0;
we = 1;
OutPortEn = 0;
next_state = S11;
end
S11:begin // R4 > R2
RFSrcMuxSel = 0;
RAddr1 = 3'h4;
RAddr2 = 3'h2;
WAddr = 0;
AluOpMuxSel = 0;
we = 0;
OutPortEn = 0;
if(Lt) next_state = S12;
else next_state = S4;
end
S12:begin // OutPut
RFSrcMuxSel = 0;
RAddr1 = 3'h4;
RAddr2 = 0;
WAddr = 0;
AluOpMuxSel = 0;
we = 0;
OutPortEn = 1;
next_state = S13;
end
S13:begin // halt
RFSrcMuxSel = 0;
RAddr1 = 0;
RAddr2 = 0;
WAddr = 0;
AluOpMuxSel = 0;
we = 0;
OutPortEn = 0;
next_state = S13;
end
endcase
end
endmodule
-
-
DedicatedProcessor Adder
DedicatedProcessor Adder
✅ 과제
⚒️ 코드 ⚒️
⚒️[DedicatedProcessor ALUOP.sv]
✅ Schematic
✅ 시뮬레이션
✅ 분석
반복별 레지스터 값
1회: R1=3, R2=2, R3=3, R4=5 → Yes
2회: R1=7, R2=6, R3=9, R4=15 → Yes
3회: R1=15, R2=14, R3=21, R4=35 → Yes
4회: R1=31, R2=30, R3=45, R4=75 → Yes
5회: R1=63, R2=62, R3=93, R4=155 → Yes
6회: R1=127, R2=126, R3=189, R4=59 → No ⇒ halt
➡️ 첫 번째 반복
시작 값: (R1, R2, R3, R4) = (1, 0, 0, 0)
**계산 순서**
R2 = R1 + R1 (1 + 1 = 2) ➞ (1, **2**, 0, 0)
R3 = R2 + R1 (2 + 1 = 3) ➞ (1, 2, **3**, 0)
R4 = R3 - R1 (3 - 1 = 2) ➞ (1, 2, 3, **2**)
R1 = R1 | R2 (1 | 2 = 3) ➞ (**3**, 2, 3, 2)
R4 = R4 & R3 (2 & 3 = 2) ➞ (3, 2, 3, **2**)
R4 = R2 + R3 (2 + 3 = 5) ➞ (3, 2, 3, **5**)
조건 확인: R4 > R2 (5 > 2) ➞ ✅ Yes, 계속 진행
➡️ 두 번째 반복
시작 값: (R1, R2, R3, R4) = (3, 2, 3, 5)
**계산 순서**
R2 = R1 + R1 (3 + 3 = 6) ➞ (3, **6**, 3, 5)
R3 = R2 + R1 (6 + 3 = 9) ➞ (3, 6, **9**, 5)
R4 = R3 - R1 (9 - 3 = 6) ➞ (3, 6, 9, **6**)
R1 = R1 | R2 (3 | 6 = 7) ➞ (**7**, 6, 9, 6)
R4 = R4 & R3 (6 & 9 = 0) ➞ (7, 6, 9, **0**)
R4 = R2 + R3 (6 + 9 = 15) ➞ (7, 6, 9, **15**)
조건 확인: R4 > R2 (15 > 6) ➞ ✅ Yes, 계속 진행
➡️ 세 번째 반복
시작 값: (R1, R2, R3, R4) = (7, 6, 9, 15)
**계산 순서**
R2 = R1 + R1 (7 + 7 = 14) ➞ (7, **14**, 9, 15)
R3 = R2 + R1 (14 + 7 = 21) ➞ (7, 14, **21**, 15)
R4 = R3 - R1 (21 - 7 = 14) ➞ (7, 14, 21, **14**)
R1 = R1 | R2 (7 | 14 = 15) ➞ (**15**, 14, 21, 14)
R4 = R4 & R3 (14 & 21 = 4) ➞ (15, 14, 21, **4**)
R4 = R2 + R3 (14 + 21 = 35) ➞ (15, 14, 21, **35**)
조건 확인: R4 > R2 (35 > 14) ➞ ✅ Yes, 계속 진행
➡️ 네 번째 반복
시작 값: (R1, R2, R3, R4) = (15, 14, 21, 35)
**계산 순서**
R2 = R1 + R1 (15 + 15 = 30) ➞ (15, **30**, 21, 35)
R3 = R2 + R1 (30 + 15 = 45) ➞ (15, 30, **45**, 35)
R4 = R3 - R1 (45 - 15 = 30) ➞ (15, 30, 45, **30**)
R1 = R1 | R2 (15 | 30 = 31) ➞ (**31**, 30, 45, 30)
R4 = R4 & R3 (30 & 45 = 12) ➞ (31, 30, 45, **12**)
R4 = R2 + R3 (30 + 45 = 75) ➞ (31, 30, 45, **75**)
조건 확인: R4 > R2 (75 > 30) ➞ ✅ Yes, 계속 진행
➡️ 다섯 번째 반복
시작 값: (R1, R2, R3, R4) = (31, 30, 45, 75)
**계산 순서**
R2 = R1 + R1 (31 + 31 = 62) ➞ (31, **62**, 45, 75)
R3 = R2 + R1 (62 + 31 = 93) ➞ (31, 62, **93**, 75)
R4 = R3 - R1 (93 - 31 = 62) ➞ (31, 62, 93, **62**)
R1 = R1 | R2 (31 | 62 = 63) ➞ (**63**, 62, 93, 62)
R4 = R4 & R3 (62 & 93 = 28) ➞ (63, 62, 93, **28**)
R4 = R2 + R3 (62 + 93 = 155) ➞ (63, 62, 93, **155**)
조건 확인: R4 > R2 (155 > 62) ➞ ✅ Yes, 계속 진행
➡️ 여섯 번째 반복 (마지막)
시작 값: (R1, R2, R3, R4) = (63, 62, 93, 155)
**계산 순서**
R2 = R1 + R1 (63 + 63 = 126) ➞ (63, **126**, 93, 155)
R3 = R2 + R1 (126 + 63 = 189) ➞ (63, 126, **189**, 155)
R4 = R3 - R1 (189 - 63 = 126) ➞ (63, 126, 189, **126**)
R1 = R1 | R2 (63 | 126 = 127) ➞ (**127**, 126, 189, 126)
R4 = R4 & R3 (126 & 189 = 120) ➞ (127, 126, 189, **120**)
R4 = R2 + R3 (126 + 189 = 315)
8-bit Wrapping (오버플로우): 8비트 레지스터는 255까지만 표현 가능하므로, 315는 256을 뺀 나머지 값인 59가 된다. (315 - 256 = 59)
R4 최종 값 ➞ (127, 126, 189, **59**)
조건 확인: R4 > R2 (59 > 126) ➞ ❌ No, 중단 (Halt)
-
DedicatedProcessor Counter
DedicatedProcessor Counter
✅ 과제
⚒️ 코드 ⚒️
⚒️[DedicatedProcessor ALUOP.sv]
✅ Schematic
✅ 시뮬레이션
✅ 분석
반복별 레지스터 값
1회: R1=3, R2=2, R3=3, R4=5 → Yes
2회: R1=7, R2=6, R3=9, R4=15 → Yes
3회: R1=15, R2=14, R3=21, R4=35 → Yes
4회: R1=31, R2=30, R3=45, R4=75 → Yes
5회: R1=63, R2=62, R3=93, R4=155 → Yes
6회: R1=127, R2=126, R3=189, R4=59 → No ⇒ halt
➡️ 첫 번째 반복
시작 값: (R1, R2, R3, R4) = (1, 0, 0, 0)
**계산 순서**
R2 = R1 + R1 (1 + 1 = 2) ➞ (1, **2**, 0, 0)
R3 = R2 + R1 (2 + 1 = 3) ➞ (1, 2, **3**, 0)
R4 = R3 - R1 (3 - 1 = 2) ➞ (1, 2, 3, **2**)
R1 = R1 | R2 (1 | 2 = 3) ➞ (**3**, 2, 3, 2)
R4 = R4 & R3 (2 & 3 = 2) ➞ (3, 2, 3, **2**)
R4 = R2 + R3 (2 + 3 = 5) ➞ (3, 2, 3, **5**)
조건 확인: R4 > R2 (5 > 2) ➞ ✅ Yes, 계속 진행
➡️ 두 번째 반복
시작 값: (R1, R2, R3, R4) = (3, 2, 3, 5)
**계산 순서**
R2 = R1 + R1 (3 + 3 = 6) ➞ (3, **6**, 3, 5)
R3 = R2 + R1 (6 + 3 = 9) ➞ (3, 6, **9**, 5)
R4 = R3 - R1 (9 - 3 = 6) ➞ (3, 6, 9, **6**)
R1 = R1 | R2 (3 | 6 = 7) ➞ (**7**, 6, 9, 6)
R4 = R4 & R3 (6 & 9 = 0) ➞ (7, 6, 9, **0**)
R4 = R2 + R3 (6 + 9 = 15) ➞ (7, 6, 9, **15**)
조건 확인: R4 > R2 (15 > 6) ➞ ✅ Yes, 계속 진행
➡️ 세 번째 반복
시작 값: (R1, R2, R3, R4) = (7, 6, 9, 15)
**계산 순서**
R2 = R1 + R1 (7 + 7 = 14) ➞ (7, **14**, 9, 15)
R3 = R2 + R1 (14 + 7 = 21) ➞ (7, 14, **21**, 15)
R4 = R3 - R1 (21 - 7 = 14) ➞ (7, 14, 21, **14**)
R1 = R1 | R2 (7 | 14 = 15) ➞ (**15**, 14, 21, 14)
R4 = R4 & R3 (14 & 21 = 4) ➞ (15, 14, 21, **4**)
R4 = R2 + R3 (14 + 21 = 35) ➞ (15, 14, 21, **35**)
조건 확인: R4 > R2 (35 > 14) ➞ ✅ Yes, 계속 진행
➡️ 네 번째 반복
시작 값: (R1, R2, R3, R4) = (15, 14, 21, 35)
**계산 순서**
R2 = R1 + R1 (15 + 15 = 30) ➞ (15, **30**, 21, 35)
R3 = R2 + R1 (30 + 15 = 45) ➞ (15, 30, **45**, 35)
R4 = R3 - R1 (45 - 15 = 30) ➞ (15, 30, 45, **30**)
R1 = R1 | R2 (15 | 30 = 31) ➞ (**31**, 30, 45, 30)
R4 = R4 & R3 (30 & 45 = 12) ➞ (31, 30, 45, **12**)
R4 = R2 + R3 (30 + 45 = 75) ➞ (31, 30, 45, **75**)
조건 확인: R4 > R2 (75 > 30) ➞ ✅ Yes, 계속 진행
➡️ 다섯 번째 반복
시작 값: (R1, R2, R3, R4) = (31, 30, 45, 75)
**계산 순서**
R2 = R1 + R1 (31 + 31 = 62) ➞ (31, **62**, 45, 75)
R3 = R2 + R1 (62 + 31 = 93) ➞ (31, 62, **93**, 75)
R4 = R3 - R1 (93 - 31 = 62) ➞ (31, 62, 93, **62**)
R1 = R1 | R2 (31 | 62 = 63) ➞ (**63**, 62, 93, 62)
R4 = R4 & R3 (62 & 93 = 28) ➞ (63, 62, 93, **28**)
R4 = R2 + R3 (62 + 93 = 155) ➞ (63, 62, 93, **155**)
조건 확인: R4 > R2 (155 > 62) ➞ ✅ Yes, 계속 진행
➡️ 여섯 번째 반복 (마지막)
시작 값: (R1, R2, R3, R4) = (63, 62, 93, 155)
**계산 순서**
R2 = R1 + R1 (63 + 63 = 126) ➞ (63, **126**, 93, 155)
R3 = R2 + R1 (126 + 63 = 189) ➞ (63, 126, **189**, 155)
R4 = R3 - R1 (189 - 63 = 126) ➞ (63, 126, 189, **126**)
R1 = R1 | R2 (63 | 126 = 127) ➞ (**127**, 126, 189, 126)
R4 = R4 & R3 (126 & 189 = 120) ➞ (127, 126, 189, **120**)
R4 = R2 + R3 (126 + 189 = 315)
8-bit Wrapping (오버플로우): 8비트 레지스터는 255까지만 표현 가능하므로, 315는 256을 뺀 나머지 값인 59가 된다. (315 - 256 = 59)
R4 최종 값 ➞ (127, 126, 189, **59**)
조건 확인: R4 > R2 (59 > 126) ➞ ❌ No, 중단 (Halt)
-
DedicatedProcessor Adder
DedicatedProcessor Adder
✅ top.sv
`timescale 1ns / 1ps
module top(
input logic clk,
input logic reset,
output logic [3:0] fndCom,
output logic [7:0] fndFont
);
logic [ 7:0] OutPort;
logic clk_10hz;
clk_divider U_CLK_DIV (
.clk (clk),
.reset (reset),
.clk_10hz (clk_10hz)
);
DedicatedProcessor_Adder U_DedicatedProcessor_Adder (
.clk (clk_10hz),
.reset (reset),
.OutPort (OutPort)
);
fndController U_fndController (
.clk (clk),
.reset (reset),
.number (OutPort),
.fndCom (fndCom),
.fndFont (fndFont)
);
endmodule
module clk_divider (
input logic clk,
input logic reset,
output logic clk_10hz
);
logic [$clog2(10_000_000)-1:0] div_counter;
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
div_counter <= 0;
clk_10hz <= 0;
end
else begin
if(div_counter == 10_000_000 - 1)begin
div_counter <= 0;
clk_10hz <= 1;
end
else begin
div_counter <= div_counter + 1;
clk_10hz <= 0;
end
end
end
endmodule
✅ DedicatedProcessor_Adder.sv
`timescale 1ns / 1ps
module DedicatedProcessor_Adder(
input logic clk,
input logic reset,
output logic [ 7:0] OutPort
);
logic SumSrcMuxSel;
logic ISrcMuxSel;
logic AdderSrcMuxSel;
logic SumEn;
logic IEn;
logic ILe10;
logic OutPortEn;
DataPath U_DataPath (
.clk (clk),
.reset (reset),
.SumSrcMuxSel (SumSrcMuxSel),
.ISrcMuxSel (ISrcMuxSel),
.AdderSrcMuxSel (AdderSrcMuxSel),
.SumEn (SumEn),
.IEn (IEn),
.ILe10 (ILe10),
.OutPortEn (OutPortEn),
.OutPort (OutPort)
);
ControlUnit U_ControlUnit (
.clk (clk),
.reset (reset),
.ILe10 (ILe10),
.SumSrcMuxSel (SumSrcMuxSel),
.ISrcMuxSel (ISrcMuxSel),
.AdderSrcMuxSel (AdderSrcMuxSel),
.SumEn (SumEn),
.IEn (IEn),
.OutPortEn (OutPortEn)
);
endmodule
✅ DataPath.sv
`timescale 1ns / 1ps
module DataPath(
input logic clk,
input logic reset,
input logic SumSrcMuxSel,
input logic ISrcMuxSel,
input logic AdderSrcMuxSel,
input logic SumEn,
input logic IEn,
output logic ILe10,
input logic OutPortEn,
output logic [7:0] OutPort
);
logic [7:0] SumSrcMuxOut, ISrcMuxOut;
logic [7:0] SumRegOut, IRegOut;
logic [7:0] AdderResult, AdderSrcMuxOut;
mux_2X1 U_SumSrcMux (
.sel (SumSrcMuxSel),
.x0 (0),
.x1 (AdderResult),
.y (SumSrcMuxOut)
);
mux_2X1 U_ISrcMux (
.sel (ISrcMuxSel),
.x0 (0),
.x1 (AdderResult),
.y (ISrcMuxOut)
);
register U_SUM_REG (
.clk (clk),
.reset (reset),
.en (SumEn),
.d (SumSrcMuxOut),
.q (SumRegOut)
);
register U_I_Reg (
.clk (clk),
.reset (reset),
.en (IEn),
.d (ISrcMuxOut),
.q (IRegOut)
);
comparator U_ILe10 (
.a (IRegOut),
.b (8'd10),
.lt (ILe10)
);
mux_2X1 U_AdderSrcMux (
.sel (AdderSrcMuxSel),
.x0 (SumRegOut),
.x1 (1),
.y (AdderSrcMuxOut)
);
adder U_Adder (
.a (AdderSrcMuxOut),
.b (IRegOut),
.sum (AdderResult)
);
register U_OutPort (
.clk (clk),
.reset (reset),
.en (OutPortEn),
.d (SumRegOut),
.q (OutPort)
);
endmodule
✅ ControlUnit.sv
`timescale 1ns / 1ps
module ControlUnit(
input logic clk,
input logic reset,
input logic ILe10,
output logic SumSrcMuxSel,
output logic ISrcMuxSel,
output logic AdderSrcMuxSel,
output logic SumEn,
output logic IEn,
output logic OutPortEn
);
typedef enum {
S0,
S1,
S2,
S3,
S4,
S5
} state_e;
state_e state, next_state;
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
state <= S0;
end
else begin
state <= next_state;
end
end
always_comb begin
next_state = state;
SumSrcMuxSel = 0;
ISrcMuxSel = 0;
SumEn = 0;
IEn = 0;
AdderSrcMuxSel = 0;
OutPortEn = 0;
case (state)
S0:begin
SumSrcMuxSel = 0;
ISrcMuxSel = 0;
SumEn = 1;
IEn = 1;
AdderSrcMuxSel = 0;
OutPortEn = 0;
next_state = S1;
end
S1:begin
SumSrcMuxSel = 0;
ISrcMuxSel = 0;
SumEn = 0;
IEn = 0;
AdderSrcMuxSel = 0;
OutPortEn = 0;
if(ILe10) next_state = S2;
else next_state = S5;
end
S2:begin
SumSrcMuxSel = 1;
ISrcMuxSel = 1;
SumEn = 1;
IEn = 0;
AdderSrcMuxSel = 0;
OutPortEn = 0;
next_state = S3;
end
S3:begin
SumSrcMuxSel = 1;
ISrcMuxSel = 1;
SumEn = 0;
IEn = 1;
AdderSrcMuxSel = 1;
OutPortEn = 0;
next_state = S4;
end
S4:begin
SumSrcMuxSel = 1;
ISrcMuxSel = 1;
SumEn = 0;
IEn = 0;
AdderSrcMuxSel = 0;
OutPortEn = 1;
next_state = S1;
end
S5:begin
SumSrcMuxSel = 1;
ISrcMuxSel = 1;
SumEn = 0;
IEn = 0;
AdderSrcMuxSel = 0;
OutPortEn = 0;
next_state = S5;
end
endcase
end
endmodule
-
DedicatedProcessor Counter
DedicatedProcessor Counter
✅ DedicatedProcessor Counter
`timescale 1ns / 1ps
module DedicatedProcessor_Counter(
input logic clk,
input logic reset,
output logic [7:0] OutBuffer
);
logic ASrcMuxsel, AEn, OutBufEn, ALt10;
logic [$clog2(100_000_000 / 10)-1:0] div_counter;
logic clk_10hz;
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
div_counter <= 0;
end
else begin
if(div_counter == 10_000_000 - 1) begin
div_counter <= 0;
clk_10hz <= 1'b1;
end
else begin
div_counter <= div_counter + 1;
clk_10hz <= 0;
end
end
end
DataPath U_DataPath (
.clk (clk_10hz),
.*
);
ControlUnit U_ControlUnit (
.clk (clk_10hz),
.*
);
endmodule
module DataPath(
input logic clk,
input logic reset,
input logic ASrcMuxsel,
input logic AEn,
output logic ALt10,
input logic OutBufEn,
output logic [7:0] OutBuffer
);
logic [7:0] AdderResult, ASrcMuxOut, ARegOut;
mux_2X1 U_ASrcMux (
.sel (ASrcMuxsel),
.x0 (8'h0),
.x1 (AdderResult),
.y (ASrcMuxOut)
);
register U_Register (
.clk (clk),
.reset (reset),
.en (AEn),
.d (ASrcMuxOut),
.q (ARegOut)
);
register U_OutReg (
.clk (clk),
.reset (reset),
.en (OutBufEn),
.d (ARegOut),
.q (OutBuffer)
);
comparator U_Comparator(
.a (ARegOut),
.b (8'd10),
.lt (ALt10)
);
adder U_Adder (
.a (ARegOut),
.b (8'd1),
.sum (AdderResult)
);
/*
OutBuf U_OutBuf (
.en (OutBufEn),
.x (ARegOut),
.y (OutBuffer)
);
*/
endmodule
module register (
input logic clk,
input logic reset,
input logic en,
input logic [7:0] d,
output logic [7:0] q
);
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
q <= 0;
end
else begin
if(en) begin
q <= d;
end
end
end
endmodule
module mux_2X1 (
input logic sel,
input logic [7:0] x0,
input logic [7:0] x1,
output logic [7:0] y
);
always_comb begin
y = 8'b0;
case (sel)
1'b0: y = x0;
1'b1: y = x1;
endcase
end
endmodule
module adder (
input logic [7:0] a,
input logic [7:0] b,
output logic [7:0] sum
);
assign sum = a + b;
endmodule
module comparator (
input logic [7:0] a,
input logic [7:0] b,
output logic lt
);
assign lt = a < b;
endmodule
module OutBuf (
input logic en,
input logic [7:0] x,
output logic [7:0] y
);
assign y = en ? x : 8'bx;
endmodule
module ControlUnit(
input logic clk,
input logic reset,
input logic ALt10,
output logic ASrcMuxsel,
output logic AEn,
output logic OutBufEn
);
typedef enum {
S0,
S1,
S2,
S3,
S4
} state_e;
state_e state, next_state;
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
state <= S0;
end
else begin
state <= next_state;
end
end
always_comb begin
next_state = state;
ASrcMuxsel = 0;
AEn = 0;
OutBufEn = 0;
case (state)
S0:begin
ASrcMuxsel = 0;
AEn = 1;
OutBufEn = 0;
next_state = S1;
end
S1:begin
ASrcMuxsel = 1;
AEn = 0;
OutBufEn = 0;
if(ALt10) next_state = S2;
else next_state = S4;
end
S2:begin
ASrcMuxsel = 1;
AEn = 0;
OutBufEn = 1;
next_state = S3;
end
S3:begin
ASrcMuxsel = 1;
AEn = 1;
OutBufEn = 0;
next_state = S1;
end
S4:begin
ASrcMuxsel = 1;
AEn = 0;
OutBufEn = 0;
next_state = S4;
end
endcase
end
endmodule
-
Day3
DAY3
✅ UART (Universal Asynchronous Receiver/Transmitter)
1. 비동기 통신의 정의
동기(Synchronous)
송수신 장치가 동일한 클록 신호를 공유
데이터와 클록이 함께 전송됨
예: SPI, I2C
비동기(Asynchronous)
송수신 장치가 클록 신호를 공유하지 않음
각자 내부 타이머로 비트 타이밍을 맞춤
예: UART
2. UART가 비동기인 이유
클록 라인이 없음
UART는 TX와 RX 두 선만 사용
클록 신호 없이 데이터만 전송
Start/Stop 비트로 동기화
데이터 프레임 시작: Start bit(0)
데이터 프레임 종료: Stop bit(1)
수신 측은 Start bit 감지 후 내부 타이머로 비트 샘플링
Baud Rate로 시간 동기화
속도, bps, 주파수, 시간
정해놓은 시간마다 데이터를 주고 받음
송신 측과 수신 측이 동일한 baud rate로 약속
클록이 없으므로, 오차 범위 내에서만 정상 수신 가능
3. 동작 원리
Idle 상태
라인은 기본적으로 HIGH(1) 상태
Start Bit
통신 시작 시 1비트 길이의 LOW(0) 신호 전송
Data Bits
LSB부터 순차적으로 전송 (일반적으로 8비트)
Parity Bit (옵션)
데이터 전송 중 오류 검출용 (Even, Odd)
데이터의 1의 개수가 짝수, 홀수에 맞춰서 동작
안 쓰는 이유는❓
Stop Bit
1비트 길이의 HIGH(1) 신호로 전송 종료 표시
수신 측
스타트 비트를 감지 후 정해진 baud rate에 맞춰 비트 샘플링
Frame
1~5번까지의 과정을 1프레임
✅ SPI (Universal Asynchronous Receiver/Transmitter)
✅ 비교 (UART vs SPI vs I2C)
구분
UART
SPI
I2C
동기방식
비동기
동기
동기
관계 수
1:1
1:N
N:N
선 개수
2개 (TX, RX)
4개 (MISO, MOSI, SCK, CS)
2개 (SCL, SDA)
속도
중간 (bps~Mbps)
매우 빠름 (수십 Mbps)
중간 (100k~3.4Mbps)
장점
간단, 저전력
빠름, 풀듀플렉스
다중 장치 연결 용이
-
UART
DAY2
✅ 버튼 구조
버튼을 누를 때, 노이즈나 진동에 의해 짧은 시간 내에 ON/OFF가 반복됨
이 현상을 바운스(Bounce) 라고 하며, 디바운싱(Debounce) 처리가 필요
✅ Shift Register를 이용한 디바운싱
💡 Shift Register 역할
버튼 입력(in_data)을 8클럭 동안 시프트 저장
sh_reg 값이 전부 1이면, 버튼이 안정적으로 눌림 상태라고 판단
✅ shift_register 모듈 코드
module shift_register (
input logic clk,
input logic reset,
input logic in_data,
output logic [7:0] out_data
);
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
out_data <= 0;
end
else begin
out_data <= {in_data, out_data[7:1]}; // right shift
//out_data <= {out_data[6:0], in_data}; // left shift
end
end
endmodule
✅ 엣지 검출기 (Edge Detector)
🔍 개요
디바운싱된 버튼 입력(debounce)의 변화를 감지하여
상승 엣지(rising_edge)
하강 엣지(falling_edge)
또는 둘 다(both_edge)를 검출하는 회로
✅ 동작 원리
edge_reg[1] ← 이전 상태
edge_reg[0] ← 현재 상태
변화 조건
- 상승 엣지: 이전 0 → 현재 1
- 하강 엣지: 이전 1 → 현재 0
- 둘 다: 둘 중 하나라도 발생 시
assign debounce = &sh_reg;
//assign out_button = debounce;
logic [1:0] edge_reg;
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
edge_reg <= 0;
end
else begin
edge_reg[0] <= debounce;
edge_reg[1] <= edge_reg[0];
end
end
assign rising_edge = edge_reg[0] & ~edge_reg[1];
assign falling_edge = ~edge_reg[0] & edge_reg[1];
assign both_edge = rising_edge | falling_edge;
✅ 전체 구조 (Button Detector)
`timescale 1ns / 1ps
module button_detector(
input logic clk,
input logic reset,
input logic in_button,
output logic rising_edge,
output logic falling_edge,
output logic both_edge
);
logic clk_1khz;
logic debounce;
logic [7:0] sh_reg;
logic [$clog2(100000)-1:0] div_counter;
always_ff @(posedge clk or posedge reset) begin
if(reset)begin
div_counter <= 0;
clk_1khz <= 0;
end
else begin
if(div_counter == 100000 - 1)begin
clk_1khz <= 1;
div_counter <= 0;
end
else begin
div_counter <= div_counter + 1;
clk_1khz <= 0;
end
end
end
shift_register u_shift_register(
.clk (clk_1khz),
.reset (reset),
.in_data (in_button),
.out_data (sh_reg)
);
assign debounce = &sh_reg;
//assign out_button = debounce;
logic [1:0] edge_reg;
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
edge_reg <= 0;
end
else begin
edge_reg[0] <= debounce;
edge_reg[1] <= edge_reg[0];
end
end
assign rising_edge = edge_reg[0] & ~edge_reg[1];
assign falling_edge = ~edge_reg[0] & edge_reg[1];
assign both_edge = rising_edge | falling_edge;
endmodule
module shift_register (
input logic clk,
input logic reset,
input logic in_data,
output logic [7:0] out_data
);
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
out_data <= 0;
end
else begin
out_data <= {in_data, out_data[7:1]}; // right shift
//out_data <= {out_data[6:0], in_data}; // left shift
end
end
endmodule
✅ 검증 (Test Bench)
클래스 정의 (transaction)
rand bit button : 랜덤 생성 1비트 버튼 값
function bit run_random() : 현재 button 값을 반환
class transaction;
rand bit button;
function bit run_random();
return button;
endfunction
endclass
초기화
clk = 0, reset = 1
10ns 후 reset = 0
in_button = 0으로 초기화, 20ns 대기
버튼 누름 (Push)
in_button = 1로 변경
60회 반복:
tr.randomize()로 버튼 값 랜덤 생성
in_button에 랜덤 값 적용
1ns 대기
in_button = 1로 고정, 150ns 대기
// push button
in_button = 1;
for(int i= 0; i < 60; i++)begin
tr.randomize();
in_button = tr.run_random();
#1;
end
in_button = 1;
#150;
버튼 놓음 (Release)
in_button = 0으로 변경
30회 반복:
랜덤 버튼 값 생성 및 적용
1ns 대기
in_button = 0로 고정, 100ns 대기
in_button = 0;
for(int i= 0; i < 30; i++)begin
tr.randomize();
in_button = tr.run_random();
#1;
end
in_button = 0;
#100;
$finish;
✅ 주요 특징
버튼 입력 바운스(Bounce) 효과를 랜덤 패턴으로 구현
상승/하강/양쪽 에지 검출 기능 검증
클래스 기반 랜덤 입력 생성으로 테스트 확장성 확보
-
Day2
DAY2
✅ 조합논리회로 vs 순차논리회로
항목
조합논리회로
순차논리회로
동작 기준
현재 입력에만 의존
현재 입력 + 과거 상태(레지스터 등)
클록 사용 여부
클록 사용 안 함
클록 사용 (동기식 설계)
메모리 기능
없음
있음 (상태 저장 가능)
예시
AND, OR, MUX 등
FSM, 레지스터, 카운터, 메모리 등
💡 조합 논리는 빠르지만 타이밍 제어가 어렵고 글리치(glitch) 발생 가능성 있음.
💡 순차 논리는 동기식으로 안정적이고 제어가 쉬움.
✅ Latch 와 Flip-Flop
Latch
클록 신호 없이 동작
입력 신호에 민감하게 반응
메모리 기능 있음
Flip-Flop
클록 엣지(상승/하강)에 반응
엣지 트리거 방식으로 동작
더 안정적인 메모리 소자
✅ SR Latch
Q와 /Q는 항상 반대여야 함.
상태 설명:
S
R
Q(next)
설명
0
0
유지
이전 상태 유지
0
1
0
Reset 상태
1
0
1
Set 상태
1
1
불안정
금지 상태 (발진 가능)
✅ D Latch
입력을 단일화하여 S= D, R = D’ 형태로 구성
Gate 신호가 enable 역할
클록에 민감 (레벨 트리거 방식)
✅ Gated D Latch & D Flip-Flop
Gated D Latch: Gate 신호가 high일 때만 입력 허용
D Flip-Flop (Master-Slave 구조)
Master: 클록 Low일 때 입력 저장
Slave: 클록 High일 때 출력 전달
상승엣지 또는 하강엣지에서만 출력 변화 (엣지 트리거)
✅ 메타스테이블(Metastable)
클록 엣지 시점에 입력(D)이 변하면 출력이 일정 시간 동안 불안정 상태에 빠질 수 있음
이를 메타스테이블 현상이라 함
중요 Timing Spec
항목
설명
Setup Time
클록 엣지 이전에 D 입력이 안정적으로 유지되어야 하는 최소 시간
Hold Time
클록 엣지 이후에도 D 입력이 유지되어야 하는 최소 시간
✅ Synchronizer
비동기 입력을 동기화하는 구조
D Flip-Flop 2개 이상 직렬 연결
첫 번째 F/F: 신호 수신
두 번째 F/F: 안정된 출력 생성
메타스테이블 방지를 위한 대표적 설계 기법
✅ 전파 지연 시간 (Propagation Delay)
클록 → 출력까지 걸리는 시간
조합 회로의 깊이에 비례
예: 곱셈 연산이 많은 FFT 회로는 레지스터 삽입 필요
📌 데이터시트에서는 clock-to-Q delay, t_pd, t_co 등으로 명시됨
✅ 글리치(Glitch)
조합 논리에서 입력이 동시에 변하지 않으면, 전파 지연 차이로 인해 일시적인 오류 출력 발생 가능
클록 엣지 직전 글리치 발생 시 시스템 오동작 가능성 있음
→ 복잡한 조합 논리는 피하고, 순차 회로로 나누어 설계하는 것이 안전함
✅ 파이프라이닝 기법
연산 중간에 레지스터 삽입으로 클록 주기를 분할
복잡한 연산을 여러 클록 사이클에 나누어 처리 가능
조합 논리 길이를 줄여 글리치 방지 및 클록 여유 확보
✅ AMBA APB 예시
AMBA APB 프로토콜도 메타스테이블과 클록 도메인 이슈를 고려하여 설계됨
동기화 구조 반영 필요
✅ 보완 및 추가 설명
타이밍 분석은 FPGA/ASIC 설계의 핵심
Setup/Hold violation은 기능적 문제 유발
CDC (Clock Domain Crossing) 설계에서는 synchronizer 필수
글리치를 줄이기 위한 방법
입력 신호 동기화
레지스터 삽입 (타이밍 여유 확보)
순차 논리 설계에서의 핵심 원칙
항상 클록 경계 기준으로 상태 변화 설계
조합 논리는 최소화
타이밍 분석은 FPGA/ASIC 설계의 핵심 요소
Setup / Hold 타이밍 위반이 발생하면 회로 동작이 비정상적으로 될 수 있음
타이밍 제약 조건을 만족하도록 설계하고, STA(Static Timing Analysis) 필수 수행
CDC (Clock Domain Crossing) 설계
서로 다른 클록 도메인을 오갈 때 메타스테이블 위험
해결 방법:
2단 이상 D Flip-Flop 직렬 연결 (Synchronizer)
Handshake 또는 FIFO 구조 사용
글리치(Glitch) 줄이기 위한 방법
입력 신호는 반드시 클록 도메인에 동기화
조합 논리 길이가 길 경우 중간에 레지스터 삽입하여 안정화
하나의 클록 사이클 내에 연산이 끝나도록 설계
순차 논리 설계 핵심 원칙
모든 상태 변화는 클록 엣지 기준으로 결정되어야 함
조합 논리는 최소화하여 타이밍 복잡도를 줄이고, 유지/확장 가능한 설계 지향
-
Button Detector
DAY2
✅ 버튼 구조
버튼을 누를 때, 노이즈나 진동에 의해 짧은 시간 내에 ON/OFF가 반복됨
이 현상을 바운스(Bounce) 라고 하며, 디바운싱(Debounce) 처리가 필요
✅ Shift Register를 이용한 디바운싱
💡 Shift Register 역할
버튼 입력(in_data)을 8클럭 동안 시프트 저장
sh_reg 값이 전부 1이면, 버튼이 안정적으로 눌림 상태라고 판단
✅ shift_register 모듈 코드
module shift_register (
input logic clk,
input logic reset,
input logic in_data,
output logic [7:0] out_data
);
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
out_data <= 0;
end
else begin
out_data <= {in_data, out_data[7:1]}; // right shift
//out_data <= {out_data[6:0], in_data}; // left shift
end
end
endmodule
✅ 엣지 검출기 (Edge Detector)
🔍 개요
디바운싱된 버튼 입력(debounce)의 변화를 감지하여
상승 엣지(rising_edge)
하강 엣지(falling_edge)
또는 둘 다(both_edge)를 검출하는 회로
✅ 동작 원리
edge_reg[1] ← 이전 상태
edge_reg[0] ← 현재 상태
변화 조건
- 상승 엣지: 이전 0 → 현재 1
- 하강 엣지: 이전 1 → 현재 0
- 둘 다: 둘 중 하나라도 발생 시
assign debounce = &sh_reg;
//assign out_button = debounce;
logic [1:0] edge_reg;
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
edge_reg <= 0;
end
else begin
edge_reg[0] <= debounce;
edge_reg[1] <= edge_reg[0];
end
end
assign rising_edge = edge_reg[0] & ~edge_reg[1];
assign falling_edge = ~edge_reg[0] & edge_reg[1];
assign both_edge = rising_edge | falling_edge;
✅ 전체 구조 (Button Detector)
`timescale 1ns / 1ps
module button_detector(
input logic clk,
input logic reset,
input logic in_button,
output logic rising_edge,
output logic falling_edge,
output logic both_edge
);
logic clk_1khz;
logic debounce;
logic [7:0] sh_reg;
logic [$clog2(100000)-1:0] div_counter;
always_ff @(posedge clk or posedge reset) begin
if(reset)begin
div_counter <= 0;
clk_1khz <= 0;
end
else begin
if(div_counter == 100000 - 1)begin
clk_1khz <= 1;
div_counter <= 0;
end
else begin
div_counter <= div_counter + 1;
clk_1khz <= 0;
end
end
end
shift_register u_shift_register(
.clk (clk_1khz),
.reset (reset),
.in_data (in_button),
.out_data (sh_reg)
);
assign debounce = &sh_reg;
//assign out_button = debounce;
logic [1:0] edge_reg;
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
edge_reg <= 0;
end
else begin
edge_reg[0] <= debounce;
edge_reg[1] <= edge_reg[0];
end
end
assign rising_edge = edge_reg[0] & ~edge_reg[1];
assign falling_edge = ~edge_reg[0] & edge_reg[1];
assign both_edge = rising_edge | falling_edge;
endmodule
module shift_register (
input logic clk,
input logic reset,
input logic in_data,
output logic [7:0] out_data
);
always_ff @(posedge clk or posedge reset) begin
if(reset) begin
out_data <= 0;
end
else begin
out_data <= {in_data, out_data[7:1]}; // right shift
//out_data <= {out_data[6:0], in_data}; // left shift
end
end
endmodule
✅ 검증 (Test Bench)
클래스 정의 (transaction)
rand bit button : 랜덤 생성 1비트 버튼 값
function bit run_random() : 현재 button 값을 반환
class transaction;
rand bit button;
function bit run_random();
return button;
endfunction
endclass
초기화
clk = 0, reset = 1
10ns 후 reset = 0
in_button = 0으로 초기화, 20ns 대기
버튼 누름 (Push)
in_button = 1로 변경
60회 반복:
tr.randomize()로 버튼 값 랜덤 생성
in_button에 랜덤 값 적용
1ns 대기
in_button = 1로 고정, 150ns 대기
// push button
in_button = 1;
for(int i= 0; i < 60; i++)begin
tr.randomize();
in_button = tr.run_random();
#1;
end
in_button = 1;
#150;
버튼 놓음 (Release)
in_button = 0으로 변경
30회 반복:
랜덤 버튼 값 생성 및 적용
1ns 대기
in_button = 0로 고정, 100ns 대기
in_button = 0;
for(int i= 0; i < 30; i++)begin
tr.randomize();
in_button = tr.run_random();
#1;
end
in_button = 0;
#100;
$finish;
✅ 주요 특징
버튼 입력 바운스(Bounce) 효과를 랜덤 패턴으로 구현
상승/하강/양쪽 에지 검출 기능 검증
클래스 기반 랜덤 입력 생성으로 테스트 확장성 확보
-
-
-
-
Day6: Convolutional Neural Network
이미지 분류
이미지 분류는 컴퓨터가 사람처럼 시각적으로 사물을 인식하고 분류하는 Computer Vision 분야의 핵심 작업에 해당한다.
CNN(합성곱 신경망)은 기존 신경망보다 정교한 분석이 가능하며, 깊은 층을 통해 이미지의 특징을 고도화된 필터로 추출한다.
분류 유형
이진 분류(Binary): 두 개의 클래스(예: 정상/비정상) 중 하나로 분류한다.
다중 클래스(Multiclass): 세 개 이상의 클래스 중 하나로 분류한다(예: 고양이/개/토끼).
다중 라벨(Multilabel): 한 이미지가 여러 라벨을 동시에 가질 수 있다.
계층적 분류(Hierarchical): 클래스가 계층 구조로 조직되어 상위-하위 개념을 구분한다.
핵심 단계
데이터 수집: 충분한 양의 이미지와 라벨을 확보한다.
특징 추출: 이미지에서 의미 있는 특징(엣지, 색상, 질감 등)을 추출한다.
분류: 추출된 특징을 바탕으로 이미지를 올바른 클래스에 할당한다.
전이학습(Transfer Learning):
사전학습된 모델의 가중치를 재사용해 적은 데이터로도 높은 성능을 낼 수 있다.
CNN 구성요소
구성요소
역할 및 설명
입력층(Input Layer)
원본 이미지의 픽셀 데이터를 입력받는다. 이미지의 크기(예: 224x224x3)가 입력 크기를 결정한다.
합성곱층(Convolutional Layer)
여러 개의 필터(커널)를 이미지에 슬라이딩하며 지역적 특징(엣지, 패턴 등)을 추출한다. 각 필터는 특성 맵을 만든다.
활성화 함수(Activation Function)
주로 ReLU를 사용한다. 음수 값을 0으로 바꿔주고, 비선형성을 부여해 복잡한 패턴 학습이 가능하게 한다.
풀링층(Pooling Layer)
특성 맵의 공간적 크기를 줄여 계산량을 감소시키고 과적합을 방지한다. Max pooling(최댓값 추출)이 대표적이다.
완전 연결층(Fully Connected Layer)
추출된 특징을 1차원 벡터로 변환(flatten)한 후, 모든 뉴런이 서로 연결되어 최종 분류를 진행한다.
출력층(Output Layer)
클래스별 확률값을 출력한다. 다중 클래스 분류에서는 Softmax 함수로 확률값을 정규화한다.
드롭아웃(Dropout, 선택적)
일부 뉴런을 무작위로 비활성화해 과적합을 방지하는 정규화 기법이다.
합성곱(Convolution) 연산
입력 이미지에 작은 필터(예: 3x3)를 슬라이딩하며 곱셈·합산을 반복해 특징 맵을 생성한다.
필터의 개수만큼 여러 특징 맵이 만들어지며, 각 필터는 엣지, 질감 등 특정 패턴에 반응한다.
필터의 이동 간격은 stride, 경계 처리를 위한 패딩(padding) 등도 주요 파라미터에 해당한다.
풀링(Pooling) 연산
MaxPooling(최댓값), AveragePooling(평균값) 등이 있으며, 공간 정보를 요약해 연산량을 줄이고, 위치 변화에 강인한 특징을 학습한다.
GlobalAveragePooling은 전체 맵의 평균값만 남겨 FC층 전에 차원을 크게 줄일 수 있다.
Flatten & FC Layer
합성곱·풀링을 반복한 후, 결과를 1차원 벡터로 변환(flatten)하여 완전 연결층에 입력한다.
FC층은 전통적인 신경망처럼 모든 뉴런이 서로 연결되어 최종 분류를 담당한다.
이미지 학습과정
데이터 준비 및 전처리
이미지 수집 및 라벨링:
충분한 양의 이미지를 수집하고, 각 이미지에 라벨(정답)을 부여한다.
데이터 증강(Data Augmentation):
회전, 뒤집기, 밝기 조정, 확대/축소 등으로 데이터 다양성을 확보하고 과적합을 방지한다.
정규화 및 리사이즈:
픽셀 값을 0~1 범위로 정규화하고, 모델 입력 크기에 맞게 리사이즈한다.
ImageDataGenerator
Keras 등에서 제공하는 ImageDataGenerator를 활용하면, 실시간으로 데이터 증강 및 전처리를 자동화할 수 있다.
flow_from_directory: 디렉토리 구조별로 이미지를 불러오고 자동 라벨링한다.
flow_from_dataframe: DataFrame에서 경로와 라벨을 읽어 배치 단위로 불러온다.
특징 추출 및 모델 학습
합성곱/풀링/활성화:
CNN의 여러 층을 거치며 이미지로부터 점점 더 추상적인 특징을 자동으로 추출한다.
완전 연결층:
추출된 특징을 바탕으로 최종적으로 클래스별 확률을 산출한다.
평가 및 검증
검증 데이터셋 활용:
학습에 사용하지 않은 별도의 데이터로 모델 성능을 평가한다.
성능 개선:
필요시 하이퍼파라미터를 조정하거나 데이터 증강, 레이어 추가 등으로 성능을 개선한다.
테스트 및 배포
실제 환경에서 미지의 이미지를 분류하여 모델의 실전 성능을 검증한다.
CNN 아키텍처
아키텍처
주요 특징 및 구조
LeNet-5
1998년에 제안되었으며, 2개의 합성곱+풀링층과 3개의 완전 연결층으로 구성된다. 소형 이미지(28x28, MNIST 등) 분류에 적합하다.
AlexNet
2012년 ILSVRC에서 우승하였으며, 5개의 합성곱층+3개의 완전 연결층, ReLU 활성화 함수 도입, 대규모 이미지(224x224) 분류에 사용된다.
VGG-16
13개의 합성곱층+3개의 완전 연결층, 모든 합성곱 커널 크기를 3x3으로 통일하여 깊은 구조(16층)로 일관된 구조를 가진다.
ResNet
2015년 ILSVRC에서 우승하였으며, 50~152개 층의 초심층 구조와 잔차 연결(residual connection)로 학습 효율을 극대화한다.
Inception
다양한 크기의 필터를 병렬로 적용(Inception 모듈), 1x1 합성곱으로 연산량을 감소시키고 GlobalAveragePooling을 사용한다.
MobileNet
모바일/임베디드 환경에 최적화된 경량화 구조로 실시간 분류가 가능하다.
전이학습(Transfer Learning) 활용
최신 실무에서는 사전학습된 CNN 모델을 가져와 출력층만 교체하거나 일부 층만 미세조정(Fine-tuning)하여 적은 데이터로도 좋은 성능을 얻는다.
공통 구조
입력 → [합성곱 → 활성화 → 풀링] × N → (필요시 드롭아웃) → 완전 연결층 → 출력(Softmax) 순으로 진행한다.
특징
특징 추출부(Feature Extractor):
여러 합성곱/풀링층이 반복되어 이미지의 저수준(엣지)부터 고수준(객체)까지 특징을 추출한다.
분류부(Classifier):
완전 연결층에서 추출된 특징을 바탕으로 클래스별 확률을 산출한다.
정리
이미지 분류는 이미지를 클래스별로 자동 분류하는 작업이며, CNN은 이를 위한 대표적 딥러닝 모델이다.
CNN은 입력층, 합성곱층, 활성화함수, 풀링층, 완전 연결층, 출력층 등으로 구성되며, 각 층이 계층적으로 쌓여 특징을 추출하고 분류를 수행한다.
학습과정은 데이터 준비, 전처리, 모델 학습, 평가, 테스트 순으로 진행한다.
대표적인 CNN 아키텍처로는 LeNet, AlexNet, VGG, ResNet, Inception, MobileNet 등이 있으며, 각각의 구조와 특징이 다르다.
실습
학습 목표
CNN의 기본 개념과 이미지 분류에서의 역할을 이해한다.
CNN의 주요 구성요소(입력층, 합성곱층, 활성화 함수, 풀링층, 완전 연결층 등)를 설명할 수 있다.
이미지 학습과정(데이터 준비, 전처리, 모델 학습, 평가, 테스트)을 이해한다.
학습곡선을 해석하고 오버피팅 문제를 인식하며, 개선 방법을 습득한다.
딥러닝 모델의 하이퍼파라미터 튜닝과 전이학습 활용법을 이해한다.
CNN Layer 구현
CNN 모델 디자인
from tensorflow.keras import models, layers
model = models.Sequential()
# (32, 32, 3) => (30, 30, 32)
model.add(layers.Conv2D(filters=32, kernel_size=(3, 3), activation='relu', input_shape=(32, 32, 3)))
# (30, 30, 32) => (15, 15, 32)
model.add(layers.MaxPool2D(pool_size=(2, 2)))
# (15, 15, 32) => (13, 13, 64)
model.add(layers.Conv2D(filters=64, kernel_size=(3, 3), activation='relu'))
# (13, 13, 64) => (6, 6, 64)
model.add(layers.MaxPool2D(pool_size=(2, 2)))
# (6, 6, 64) => (4, 4, 64)
model.add(layers.Conv2D(filters=64, kernel_size=(3, 3), activation='relu'))
# 3D를 1D로 변환
model.add(layers.Flatten())
# Classification : Fully Connected Layer 추가
model.add(layers.Dense(units=64, activation='relu'))
model.add(layers.Dense(units=10, activation='softmax'))
# 모델의 학습 정보 설정
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
# 모델 학습
history = model.fit(x=train_x, y=train_y, epochs=20, batch_size=256, verbose=2, validation_split=0.2)
Accuracy
Loss
학습곡선 해석 및 오버피팅 개선 방안
1. 그래프 해석
Training Accuracy/Loss
학습 정확도는 꾸준히 상승하여 0.9(90%)에 근접한다.
학습 손실(loss)은 꾸준히 감소해 0.4 이하로 떨어진다.
Validation Accuracy/Loss
검증 정확도는 0.8(80%) 부근에서 더 이상 오르지 않고, 에포크가 진행될수록 상승이 멈추거나 약간 하락/변동한다.
검증 손실은 0.7~0.8 선에서 변동하며, 오히려 에포크가 늘수록 올라가기도 한다.
2. 원인 분석
오버피팅(overfitting) 현상.
오버피팅이란?
모델이 학습 데이터에는 매우 잘 맞지만, 새로운 데이터(검증/테스트)에는 일반화가 잘 안 되는 상태.
구체적 신호
학습 손실은 계속 감소(=학습 데이터에 점점 더 잘 맞춤)
검증 손실은 어느 순간부터 더 이상 감소하지 않고, 오히려 증가하거나 불안정하게 변동
학습 정확도와 검증 정확도의 차이가 점점 커짐
3. 왜 이런 현상이 생기나?
모델이 너무 복잡하거나 파라미터가 많을 때
학습 데이터에 비해 검증 데이터의 분포가 다를 때
데이터가 충분히 다양하지 않거나, 데이터 증강이 부족할 때
드롭아웃, 정규화 등 일반화 기법이 부족할 때
에포크 수가 너무 많아 불필요하게 오래 학습할 때
4. 이런 경우 어떻게 해야 하나?
Early Stopping(조기 종료) 사용:
검증 손실이 더 이상 감소하지 않으면 학습을 멈춘다.
드롭아웃(Dropout)·정규화(BatchNorm) 추가:
모델이 일부 뉴런에 의존하지 않도록 하고, 학습을 안정화한다.
데이터 증강(Data Augmentation):
학습 데이터를 회전, 이동, 노이즈 추가 등으로 다양하게 만든다.
모델 단순화:
층 수나 파라미터 수를 줄여 복잡도를 낮춘다.
학습률(learning rate) 조정:
너무 높으면 불안정, 너무 낮으면 과적합으로 이어질 수 있다.
더 많은 데이터 확보:
가능하다면 데이터셋을 키운다.
5. 참고: 정상적인 학습곡선은?
학습·검증 손실이 모두 점진적으로 감소
학습·검증 정확도가 모두 점진적으로 증가
두 곡선 간의 차이가 크지 않음
(차이가 크면 오버피팅, 둘 다 낮으면 언더피팅)
결론
현재 학습곡선은 모델이 학습 데이터에는 과하게 맞추고, 새로운 데이터에는 일반화하지 못하는 전형적인 오버피팅 상태다.
CNN 모델 개선
드롭아웃(Dropout)·정규화(BatchNorm) 추가:
학습률(learning rate) 조정:
from tensorflow.keras import models, layers
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(BatchNormalization())
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(Dropout(0.5))
model.add(layers.Conv2D(128, (3, 3), activation='relu'))
model.add(BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(Dropout(0.5))
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(layers.Dense(10, activation='softmax'))
model.compile(optimizer=Adam(learning_rate=0.0002), loss='categorical_crossentropy', metrics=['accuracy'])
history = model.fit(x=train_x, y=train_y, epochs=50, batch_size=128, validation_split=0.2, verbose=2)
Accuracy
Loss
결론
이번 학습을 통해 합성곱 신경망(CNN)의 구조와 원리를 이해하고, 실제 이미지 분류 문제에 적용해봄으로써 딥러닝 기반 컴퓨터 비전의 핵심 개념을 익혔다.
CNN의 다양한 구성요소와 대표 아키텍처의 특징, 데이터 전처리와 정규화, 오버피팅 방지 기법 등 실전적인 내용을 학습함으로써,
이미지 분류 모델의 성능을 효과적으로 향상시키는 방법을 습득할 수 있었다.
향후에는 전이학습, 데이터 증강, 하이퍼파라미터 튜닝 등 고급 기법을 적극적으로 활용하여,
더 높은 성능과 실전 적용 능력을 갖춘 딥러닝 모델을 설계·활용할 수 있을 것이다.
-
Day5: Neural Network Model
Activate function
Learning Analysis
Optimization Techniques
LAB
Mnist 실습
1. 차이점
항목
신경망 구조
신경망❌구조
모델 구조
4개 Dense 계층(512→256→128→10), Dropout 3회
1개 Dense 계층(10)
활성화 함수
relu(은닉층), softmax(출력층)
softmax(출력층)
Dropout 사용
있음(0.3 비율, 3회)
없음
Optimizer
Adam(learning_rate=0.0003)
SGD(기본값)
Epoch 수
35
30
Batch Size
128
64
모델 복잡도
높음
매우 단순(로지스틱 회귀와 유사)
2. 모델 구조 및 복잡도
신경망❌구조: 은닉층 없이 입력(784차원)에서 바로 10개 유닛의 softmax 출력층으로 연결된 매우 단순한 구조. 이는 다중 클래스 로지스틱 회귀와 동일.
신경망 구조: 3개의 은닉층(512, 256, 128 유닛)과 Dropout(0.3) 레이어를 포함해, 심층 신경망 구조. 출력층은 10개 유닛의 softmax.
신경망❌구조
md = Sequential()
md.add(Dense(10, activation = 'softmax', input_shape = (28*28,)))
신경망 구조
md = Sequential()
md.add(Dense(512, activation='relu', input_shape=(28*28,)))
md.add(Dropout(0.3))
md.add(Dense(256, activation='relu'))
md.add(Dropout(0.3))
md.add(Dense(128, activation='relu'))
md.add(Dropout(0.3))
md.add(Dense(10, activation='softmax'))
3. 정규화(Dropout) 적용 유무
op_mnist.py는 과적합 방지를 위해 Dropout 레이어를 3번 사용.
mnist.py는 Dropout 레이어 ❌
4. Optimizer 및 하이퍼파라미터 설정
신경망❌구조
md.compile(loss='sparse_categorical_crossentropy', optimizer = 'sgd', metrics=['acc'])
hist = md.fit(train_x2, train_y, epochs = 30, batch_size = 64, validation_split = 0.2)
신경망 구조
md.compile(loss='sparse_categorical_crossentropy', optimizer=Adam(learning_rate=0.0003), metrics=['acc'])
hist = md.fit(train_x2, train_y, epochs = 35, batch_size = 128, validation_split = 0.2)
5. 결과 비교
신경망❌ 구조
신경망 구조
신경망❌ 구조
신경망 구조
신경망❌ 구조
신경망 구조
6. 결론
- 신경망❌구조는 단일층 신경망(로지스틱 회귀) 구조로, 구현이 간단하고 빠르지만, 복잡한 데이터 표현력은 떨어진다.
- 신경망 구조는 심층 신경망(MLP) 구조에 Dropout과 Adam 옵티마이저를 적용해, 복잡한 패턴 학습과 과적합 방지에 중점을 둔 코드.
- 두 코드의 차이는 모델 구조(심층 vs. 단층), 정규화 적용, 옵티마이저 종류, 학습 파라미터 등에서 뚜렷하게 나타난다.
Cifar-10 실습
1. 차이점
항목
신경망 구조
신경망❌구조
모델 구조
4개 Dense 계층(512→256→128→10), Dropout 3회
1개 Dense 계층(10)
활성화 함수
relu(은닉층), softmax(출력층)
softmax(출력층)
Dropout 사용
있음(0.3 비율, 3회)
없음
Optimizer
Adam(learning_rate=0.0003)
SGD(기본값)
Epoch 수
35
30
Batch Size
128
64
모델 복잡도
높음
매우 단순(로지스틱 회귀와 유사)
2. 모델 구조 및 복잡도
신경망❌구조: 은닉층 없이 입력(784차원)에서 바로 10개 유닛의 softmax 출력층으로 연결된 매우 단순한 구조. 이는 다중 클래스 로지스틱 회귀와 동일.
신경망 구조: 3개의 은닉층(512, 256, 128 유닛)과 Dropout(0.3) 레이어를 포함해, 심층 신경망 구조. 출력층은 10개 유닛의 softmax.
신경망❌구조
md = Sequential()
md.add(Dense(10, activation = 'softmax', input_shape = (32*32*3,)))
신경망 구조
md = Sequential()
md.add(Dense(512, activation='relu', input_shape=(3072,)))
md.add(Dropout(0.3))
md.add(Dense(256, activation='relu'))
md.add(Dropout(0.3))
md.add(Dense(128, activation='relu'))
md.add(Dropout(0.3))
md.add(Dense(10, activation='softmax'))
3. 정규화(Dropout) 적용 유무
신경망 구조(op_cifar_10.py): 과적합 방지를 위해 Dropout 레이어를 3번 사용.
신경망❌구조(cifar_10.py): Dropout 레이어가 없다.
4. Optimizer 및 하이퍼파라미터 설정
신경망❌구조
md.compile(loss='sparse_categorical_crossentropy', optimizer = 'sgd', metrics=['acc'])
hist = md.fit(train_x2, train_y, epochs = 30, batch_size = 64, validation_split = 0.2)
신경망 구조
md.compile(loss='sparse_categorical_crossentropy', optimizer=Adam(learning_rate=0.0003), metrics=['acc'])
hist = md.fit(train_x2, train_y, epochs = 35, batch_size = 128, validation_split = 0.2)
5. 결과 비교
신경망❌ 구조
신경망 구조
신경망❌ 구조
신경망 구조
신경망❌ 구조
신경망 구조
6. 결론
신경망❌구조는 단일층 신경망(로지스틱 회귀) 구조로, 구현이 간단하고 빠르지만, 복잡한 데이터 표현력은 떨어진다.
신경망 구조는 심층 신경망(MLP) 구조에 Dropout과 Adam 옵티마이저를 적용해, 복잡한 패턴 학습과 과적합 방지.
두 코드의 차이는 모델 구조(심층 vs. 단층), 정규화 적용, 옵티마이저 종류, 학습 파라미터 등.
-
Day5: Linear Model
(Mnist, Cifar_10) Dataset
1. 데이터셋 및 코드 개요
❓ Mnist 데이터셋이란?
손으로 쓴 숫자(0~9)를 인식하는 머신러닝 및 딥러닝 모델의 성능 평가를 위해 널리 사용되는 대표적인 이미지 데이터셋이다.
총 70,000개의 흑백(그레이스케일) 이미지로 이루어져 있으며, 60,000개는 학습용, 10,000개는 테스트용이다. 각 이미지는 28x28 픽셀 크기의 정사각형 형태이다.
❓ Cifar_10 데이터셋이란?
컴퓨터 비전 분야에서 이미지 분류 모델의 성능을 평가하기 위해 널리 사용되는 컬러 이미지 데이터셋이다.
총 60,000개의 컬러(RGB, 3채널) 이미지로 이루어져 있으며, 50,000개는 학습용, 10,000개는 테스트용이다. 각 이미지는 32x32 픽셀 크기이다.
2. 데이터 전처리 및 모델 구조
Mnist 데이터셋
데이터: (60000, 28, 28) 크기의 흑백 이미지, 라벨(0~9)
전처리: 이미지를 1차원(784)으로 변환 후 0~1 정규화
모델:
입력: Dense(3072)
출력층: Dense(10, softmax) (은닉층 없음)
손실함수: sparse_categorical_crossentropy
최적화: SGD
평가: 정확도(acc)
# Mnist 데이터 전처리
train_x1 = train_x.reshape(60000, -1) # 1차원 배열
test_x1 = test_x.reshape(10000, -1) # 1차원 배열
train_x2 = train_x1/255
test_x2 = test_x1/255
print(train_x2.shape) # (60000, 784)
print(test_x2.shape) # (10000, 784)
md = Sequential()
md.add(Dense(10, activation = 'softmax', input_shape = (28*28,)))
md.summary()
md.compile(loss='sparse_categorical_crossentropy', optimizer = 'sgd', metrics=['acc'])
hist = md.fit(train_x2, train_y, epochs = 30, batch_size = 64, validation_split = 0.2)
Cifar_10 데이터셋
데이터: (50000, 32, 32, 3) 크기의 컬러 이미지, 라벨(0~9)
전처리: 이미지를 1차원(3072)으로 변환 후 0~1 정규화
모델:
입력: Dense(3072)
출력층: Dense(10, softmax) (은닉층 없음)
손실함수: sparse_categorical_crossentropy
최적화: SGD
평가: 정확도(acc)
# Cifar_10 데이터 전처리
train_x1 = train_x.reshape(50000, -1) # 1차원 배열
test_x1 = test_x.reshape(10000, -1) # 1차원 배열
train_x2 = train_x1/255
test_x2 = test_x1/255
print(train_x2.shape) #(50000, 3072)
print(test_x2.shape) #(10000, 3072)
md = Sequential()
md.add(Dense(10, activation = 'softmax', input_shape = (32*32*3,)))
md.summary()
md.compile(loss='sparse_categorical_crossentropy', optimizer = 'sgd', metrics=['acc'])
hist = md.fit(train_x2, train_y, epochs = 30, batch_size = 128, validation_split = 0.2)
3. 코드 실행 및 결과 시각화
Mnist 데이터셋
Cifar_10 데이터셋
4. 두 코드의 주요 차이점
항목
MNIST 코드
CIFAR-10 코드
데이터 타입
흑백(1채널), 28x28
컬러(3채널), 32x32
입력 차원
784
3072
모델 구조
은닉층 ❌
은닉층 ❌
난이도
상대적으로 쉬움
상대적으로 어려움
분류 대상
손글씨 숫자(0~9)
10가지 사물
성능 기대치
높은 정확도 달성 용이
단순 모델로는 낮은 정확도
데이터 복잡성: CIFAR-10은 색상, 배경, 형태가 다양해 단순 신경망으로는 분류가 어렵고, MNIST는 단순한 흑백 숫자 이미지라 기본 신경망도 높은 성능을 보임.
5. CIFAR-10 정확도 향상을 위한 하이퍼파라미터 조정 방법
1. 은닉층 추가 및 크기 조정: Dense 레이어(은닉층)를 추가하고, 노드 수를 늘리면 더 복잡한 패턴을 학습
은닉층이 없는 구조에 Dense(100, activation=’softmax’)로 하면 100개의 클래스에 대한 확률을 내놓기 때문에, 10개 클래스 분류 문제에서는 올바른 결과 ❌
2. 활성화 함수 변경: 은닉층에 relu 등 비선형 활성화 함수를 적용해 모델 표현력을 높일 수 있다.
3. 배치 사이즈(batch size) 변경: 작은 배치는 더 빠른 업데이트, 큰 배치는 더 안정적인 학습을 유도
4. 에포크 수 조정: 더 오래 학습시키면 성능이 오를 수 있으나, 과적합에 주의
과적합은 모델이 학습 데이터의 노이즈나 세부적인 패턴까지 지나치게 학습하여, 새로운 데이터(테스트 데이터)에 대한 일반화 성능이 떨어지는 현상.
과적합된 모델은 학습 데이터에서는 높은 정확도를 보이지만, 테스트 데이터에서는 성능이 급격히 떨어진다.
❗과적합 방지법
조기 종료(Early Stopping): 검증 데이터의 성능이 더 이상 개선되지 않으면 학습 중단.
정규화(Regularization): L1, L2 정규화, 드롭아웃(Dropout) 등을 사용해 모델 복잡도 제어.
데이터 증강(Data Augmentation): 학습 데이터를 인위적으로 늘려 모델이 더 일반화되도록 한다.
적절한 에포크 수 설정: 검증 성능이 최고일 때 학습을 멈추는 것이 이상적이다.
6. 결론
정확도가 너무 낮은 것은 모델 구조의 한계 때문이다. 하이퍼파라미터 조정만으로는 근본적인 해결이 어렵다. 은닉층을 추가하거나 CNN을 사용하는 것이 좋을 것 같다.
-
-
Day4: Deep Learning
Compare Perceptron, Multi Layer perceptron XOR Gate
1. 네트워크 구조의 차이
Perceptron
- Single layer : 입력층과 출력층만 존재하며, 입력값에 가중치와 바이어스를 더한 뒤 바로 출력
self.weights = np.zeros(input_size)
self.bias = 0
- 활성화 함수: 계단함수와 같은 단순한 함수를 사용한다.
Multi Layer Perceptron
- Multi layer : 입력층, 은닉층, 출력층으로 구성된다.
self.w1 = np.random.randn(input_size, hidden_size)
self.b1 = np.zeros(hidden_size)
self.w2 = np.random.randn(hidden_size, output_size)
self.b2 = np.zeros(output_size)
- 활성화 함수: sigmoid, tanh 등 연속적이고 미분 가능한 함수 사용. 각 층마다 적용한다.
2. 순전파 연산의 차이
Perceptron
- 입력층 -> 출력층
linear_output = np.dot(x, self.weights) + self.bias
return self.activation(linear_output)
Multi Layer Perceptron
- 입력층 -> 은닉층 -> 출력층
self.z1 = np.dot(x, self.w1) + self.b1
self.a1 = sigmoid(self.z1)
self.z2 = np.dot(self.a1, self.w2) + self.b2
self.a2 = sigmoid(self.z2)
return self.a2
3. 가중치 업데이트 방식의 차이
Perceptron
- 단순 업데이트
update = self.lr * (target - prediction)
self.weights += update * x1
self.bias += update
Multi Layer Perceptron
- 역전파(Backpropagation) 사용
출력층 오차를 은닉층까지 전파하여 모든 가중치/바이어스를 미분값(gradient)으로 업데이트한다
# 출력층 오차
error_output = self.a2 - y
delta2 = error_output * sigmoid_diff(self.z2)
# 은닉층 오차
error_hidden = np.dot(self.w2, delta2)
delta1 = error_hidden * sigmoid_diff(self.z1)
# 가중치 업데이트
self.w2 -= self.lr * np.outer(self.a1, delta2)
self.b2 -= self.lr * delta2
self.w1 -= self.lr * np.outer(x, delta1)
self.b1 -= self.lr * delta1
4. 문제 해결 능력의 차이
Perceptron
- 퍼셉트론: XOR처럼 선형적으로 구분 불가능한 문제는 절대 풀 수 없음. 단일 직선(혹은 평면)만으로 데이터를 나눈다.
Multi Layer Perceptron
- MLP: 은닉층의 비선형 변환 덕분에 XOR 등 복잡한 패턴도 학습 가능. 실제로 MLP 코드는 XOR 문제를 성공적으로 해결할 수 있음
5. 코드 예시
Perceptron
출력층 오차만 사용
class Perceptron:
def __init__(self, input_size, ...):
self.weights = np.zeros(input_size)
self.bias = 0
def predict(self, x):
return self.activation(np.dot(x, self.weights) + self.bias)
def train(self, X, y):
Multi Layer Perceptron
여러 층 순전파
역전파로 모든 층 가중치 업데이트
class MLP:
def __init__(self, input_size, hidden_size, output_size, ...):
self.w1 = np.random.randn(input_size, hidden_size)
self.b1 = np.zeros(hidden_size)
self.w2 = np.random.randn(hidden_size, output_size)
self.b2 = np.zeros(output_size)
def forward(self, x):
def backward(self, x, y):
6. 요약
구분
퍼셉트론
MLP
층 구조
입력-출력(단일층)
입력-은닉-출력(다층)
가중치/바이어스
1개(입력→출력)
2세트(입력→은닉, 은닉→출력)
순전파
한 번의 선형 연산+활성화
여러 층의 선형 연산+비선형 활성화 반복
학습 방식
출력층 오차로 단순 업데이트
역전파로 모든 층의 가중치/바이어스 업데이트
활성화 함수
계단함수/시그모이드(단순)
시그모이드/탄젠트 등(비선형, 미분 가능)
문제 해결력
선형 문제만 해결(XOR 불가)
비선형 문제(XOR 등) 해결 가능
-
Day3: Perceptron_MLP
#
📌 Perceptron이란?
1957년 프랭크 로젠브라트가 고안한 최초의 인공신경망 모델 중 하나.
생물학적 뉴런을 수학적으로 모델링한 인공 뉴런으로, 여러 입력 신호를 받아 각각의 가중치를 곱한 후 이를 합산하여, 활성화 함수를 통해 단일 신호를 출력한다.
퍼셉트론의 출력은 신호 유무 (1 또는 0)로 표현된고, 이진 분류 문제 해결에 효과적이다.
📝 Perceptron AND_GATE 실습
🔍 AND 게이트 모델 훈련 후 결과 확인
import numpy as np
import matplotlib.pyplot as plt
class Perceptron:
def __init__(self, input_size, lr=0.1, epochs=10):
self.weights = np.zeros(input_size)
self.bias = 0
self.lr = lr
self.epochs = epochs
self.errors = []
def activation(self, x):
return np.where(x >= 0, 1, 0)
def predict(self, x):
linear_output = np.dot(x, self.weights) + self.bias
return self.activation(linear_output)
def train(self, X, y):
for epoch in range(self.epochs):
total_error = 0
for x1, target in zip(X, y):
prediction = self.predict(x1)
update = self.lr * (target - prediction)
self.weights += update * x1
self.bias += update
total_error += int(update != 0)
self.errors.append(total_error)
print(f"Epoch {epoch+1}/{self.epochs}, Errors: {total_error}")
# AND 게이트 데이터
X_and = np.array([[0,0],[0,1],[1,0],[1,1]])
y_and = np.array([0,0,0,1])
# 퍼셉트론 모델 훈련
ppn_and = Perceptron(input_size=2)
ppn_and.train(X_and, y_and)
# 예측 결과 확인
print("\nAND Gate Test:")
for x in X_and:
print(f"Input: {x}, Predicted Output: {ppn_and.predict(x)}")
💡 출력 결과
🔍 AND 게이트 결정 경계 시각화
from matplotlib.colors import ListedColormap
def plot_decision_boundary(X, y, model):
cmap_light = ListedColormap(['#FFAAAA', '#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000', '#0000FF'])
h = .02 # mesh grid 간격
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.figure(figsize=(8, 6))
plt.contourf(xx, yy, Z, cmap=cmap_light)
# 실제 데이터 포인트 표시
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold,
edgecolor='k', s=100, marker='o')
plt.xlabel('Input 1')
plt.ylabel('Input 2')
plt.title('Perceptron Decision Boundary')
plt.show()
# AND 게이트 결정 경계 시각화
plot_decision_boundary(X_and, y_and, ppn_and)
💡 출력 결과
🔍 오류 시각화
plt.figure(figsize=(8, 5))
plt.plot(range(1, len(ppn_and.errors) + 1), ppn_and.errors, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Number of Errors')
plt.title('Perceptron Learning Error Over Epochs (AND Gate)')
plt.grid(True)
plt.show()
💡 출력 결과
📝 Perceptron OR_GATE 실습
🔍 OR 게이트 모델 훈련 후 결과 확인
import numpy as np
import matplotlib.pyplot as plt
class Perceptron:
def __init__(self, input_size, lr=0.1, epochs=10):
self.weights = np.zeros(input_size)
self.bias = 0
self.lr = lr
self.epochs = epochs
self.errors = []
def activation(self, x):
return np.where(x >= 0, 1, 0)
def predict(self, x):
linear_output = np.dot(x, self.weights) + self.bias
return self.activation(linear_output)
def train(self, X, y):
for epoch in range(self.epochs):
total_error = 0
for x1, target in zip(X, y):
prediction = self.predict(x1)
update = self.lr * (target - prediction)
self.weights += update * x1
self.bias += update
total_error += int(update != 0)
self.errors.append(total_error)
print(f"Epoch {epoch+1}/{self.epochs}, Errors: {total_error}")
# OR 게이트 데이터
X_or = np.array([[0,0],[0,1],[1,0],[1,1]])
y_or = np.array([0,1,1,1])
# 퍼셉트론 모델 훈련
ppn_or = Perceptron(input_size=2)
ppn_or.train(X_or, y_or)
# 예측 결과 확인
print("\nOR Gate Test:")
for x in X_or:
print(f"Input: {x}, Predicted Output: {ppn_or.predict(x)}")
💡 출력 결과
🔍 OR 게이트 결정 경계 시각화
from matplotlib.colors import ListedColormap
def plot_decision_boundary(X, y, model):
cmap_light = ListedColormap(['#FFAAAA', '#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000', '#0000FF'])
h = .02 # mesh grid 간격
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.figure(figsize=(8, 6))
plt.contourf(xx, yy, Z, cmap=cmap_light)
# 실제 데이터 포인트 표시
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold,
edgecolor='k', s=100, marker='o')
plt.xlabel('Input 1')
plt.ylabel('Input 2')
plt.title('Perceptron Decision Boundary')
plt.show()
# OR 게이트 결정 경계 시각화
plot_decision_boundary(X_or, y_or, ppn_or)
💡 출력 결과
🔍 오류 시각화
plt.figure(figsize=(8, 5))
plt.plot(range(1, len(ppn_or.errors) + 1), ppn_or.errors, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Number of Errors')
plt.title('Perceptron Learning Error Over Epochs (OR Gate)')
plt.grid(True)
plt.show()
💡 출력 결과
📝 Perceptron NAND_GATE 실습
🔍 NAND 게이트 모델 훈련 후 결과 확인
import numpy as np
import matplotlib.pyplot as plt
class Perceptron:
def __init__(self, input_size, lr=0.1, epochs=10):
self.weights = np.zeros(input_size)
self.bias = 0
self.lr = lr
self.epochs = epochs
self.errors = []
def activation(self, x):
return np.where(x >= 0, 1, 0)
def predict(self, x):
linear_output = np.dot(x, self.weights) + self.bias
return self.activation(linear_output)
def train(self, X, y):
for epoch in range(self.epochs):
total_error = 0
for x1, target in zip(X, y):
prediction = self.predict(x1)
update = self.lr * (target - prediction)
self.weights += update * x1
self.bias += update
total_error += int(update != 0)
self.errors.append(total_error)
print(f"Epoch {epoch+1}/{self.epochs}, Errors: {total_error}")
# NAND 게이트 데이터
X_nand = np.array([[0,0],[0,1],[1,0],[1,1]])
y_nand = np.array([1,1,1,0])
# 퍼셉트론 모델 훈련
ppn_nand = Perceptron(input_size=2)
ppn_nand.train(X_nand, y_nand)
# 예측 결과 확인
print("\nNAND Gate Test:")
for x in X_nand:
print(f"Input: {x}, Predicted Output: {ppn_nand.predict(x)}")
💡 출력 결과
🔍 NAND 게이트 결정 경계 시각화
from matplotlib.colors import ListedColormap
def plot_decision_boundary(X, y, model):
cmap_light = ListedColormap(['#FFAAAA', '#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000', '#0000FF'])
h = .02 # mesh grid 간격
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.figure(figsize=(8, 6))
plt.contourf(xx, yy, Z, cmap=cmap_light)
# 실제 데이터 포인트 표시
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold,
edgecolor='k', s=100, marker='o')
plt.xlabel('Input 1')
plt.ylabel('Input 2')
plt.title('Perceptron Decision Boundary')
plt.show()
# NAND 게이트 결정 경계 시각화
plot_decision_boundary(X_nand, y_nand, ppn_nand)
💡 출력 결과
🔍 오류 시각화
plt.figure(figsize=(8, 5))
plt.plot(range(1, len(ppn_or.errors) + 1), ppn_or.errors, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Number of Errors')
plt.title('Perceptron Learning Error Over Epochs (OR Gate)')
plt.grid(True)
plt.show()
💡 출력 결과
📝 Perceptron XOR_GATE 실습
🔍 XOR 게이트 모델 훈련 후 결과 확인
import numpy as np
import matplotlib.pyplot as plt
class Perceptron:
def __init__(self, input_size, lr=0.1, epochs=10):
self.weights = np.zeros(input_size)
self.bias = 0
self.lr = lr
self.epochs = epochs
self.errors = []
def activation(self, x):
return np.where(x >= 0, 1, 0)
def predict(self, x):
linear_output = np.dot(x, self.weights) + self.bias
return self.activation(linear_output)
def train(self, X, y):
for epoch in range(self.epochs):
total_error = 0
for x1, target in zip(X, y):
prediction = self.predict(x1)
update = self.lr * (target - prediction)
self.weights += update * x1
self.bias += update
total_error += int(update != 0)
self.errors.append(total_error)
print(f"Epoch {epoch+1}/{self.epochs}, Errors: {total_error}")
# XOR 게이트 데이터
X_xor = np.array([[0,0],[0,1],[1,0],[1,1]])
y_xor = np.array([0,1,1,0])
# 퍼셉트론 모델 훈련
ppn_xor = Perceptron(input_size=2)
ppn_xor.train(X_xor, y_xor)
# 예측 결과 확인
print("\nXOR Gate Test:")
for x in X_xor:
print(f"Input: {x}, Predicted Output: {ppn_xor.predict(x)}")
💡 출력 결과
🔍 XOR 게이트 결정 경계 시각화
from matplotlib.colors import ListedColormap
def plot_decision_boundary(X, y, model):
cmap_light = ListedColormap(['#FFAAAA', '#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000', '#0000FF'])
h = .02 # mesh grid 간격
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
np.arange(y_min, y_max, h))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.figure(figsize=(8, 6))
plt.contourf(xx, yy, Z, cmap=cmap_light)
# 실제 데이터 포인트 표시
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold,
edgecolor='k', s=100, marker='o')
plt.xlabel('Input 1')
plt.ylabel('Input 2')
plt.title('Perceptron Decision Boundary')
plt.show()
# XOR 게이트 결정 경계 시각화
plot_decision_boundary(X_xor, y_xor, ppn_xor)
💡 출력 결과
🔍 오류 시각화
plt.figure(figsize=(8, 5))
plt.plot(range(1, len(ppn_or.errors) + 1), ppn_or.errors, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Number of Errors')
plt.title('Perceptron Learning Error Over Epochs (OR Gate)')
plt.grid(True)
plt.show()
💡 출력 결과
🚨 단층 Perceptron의 한계점
XOR GATE는 퍼셉트론으로 학습이 되지 않는 문제가 발생하였다.
퍼셉트론은 직선 하나로 ●와 ○를 나눌 수 있어야 학습이 된다.
하지만 XOR은 직선 하나로는 절대 ●와 ○를 나눌 수 없다.
-
Basic Operation
📝 학습목표
OpenCV(Open Source Computer Vision Library)를 활용하여 이미지/비디오 처리하기
1. 이미지 Read & Write
📂 이미지 파일 준비
import numpy as np
import cv2
img = cv2.imread("image.jpg")
cv2.namedWindow("image", cv2.WINDOW_NORMAL)
print(img.shape)
cv2.imshow("image", img)
cv2.waitKey(0)
cv2.imwrite("output.png", img)
cv2.destroyAllWindows()
💡 출력 결과
2. 색상 채널 분리와 색공간 변환
📂 이미지 파일 준비
import numpy as np
import cv2
color = cv2.imread("strawberry.jpg", cv2.IMREAD_COLOR)
print(color.shape)
height, width, channels = color.shape
cv2.imshow("Original Image", color)
r,g,b = cv2.split(color)
rgb_split = np.concatenate((r,g,b), axis=1)
cv2.imshow("RGB Channels", rgb_split)
hsv = cv2.cvtColor(color, cv2.COLOR_RGB2HSV)
h,s,v = cv2.split(hsv)
hsv_split = np.concatenate((h,s,v),axis=1)
cv2.imshow("Split HSV", hsv_split)
cv2.waitKey(0)
cv2.imwrite("hsv2rgb_split.png", hsv_split)
💡 출력 결과
3. 이미지 일부 영역 자르기, 크기 바꾸기, 회전하기
📂 이미지 파일 준비
import numpy as np
import cv2
img = cv2.imread("image.jpg")
print(img.shape) # 0,100
cropped = img[0:220, 185:385] #220, 200, 3
print(cropped.shape)
resized = cv2.resize(cropped, (400,200))
print(resized.shape)
rotated_90 = cv2.rotate(resized, cv2.ROTATE_90_CLOCKWISE)
#rotated_180 = cv2.rotate(image, cv2.ROTATE_180)
#rotated_270 = cv2.rotate(image, cv2.ROTATE_90_COUNTERCLOCKWISE)
cv2.imshow("Origin", img)
cv2.imshow("Cropped image", cropped)
cv2.imshow("Resized image", resized)
cv2.imshow("Rotated 90 image", rotated_90)
cv2.waitKey(0)
cv2.destroyAllWindows()
💡 출력 결과
cropped
resized
rotated_90
4. 원본 색상 반전시키기
📂 이미지 파일 준비
import numpy as np
import cv2
src = cv2.imread("output.png", cv2.IMREAD_COLOR)
dst = cv2.bitwise_not(src)
cv2.imshow("src", src)
cv2.imshow("dst", dst)
cv2.waitKey()
cv2.destroyAllWindows()
💡 출력 결과
5. 임계값 기준으로 이진화시키기
📂 이미지 파일 준비
import cv2
src = cv2.imread("image.jpg", cv2.IMREAD_COLOR)
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
ret, dst = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)
cv2.imshow("dst", dst)
cv2.waitKey()
cv2.destroyAllWindows()
💡 출력 결과
6. 이미지 흐리게(블러) 처리
📂 이미지 파일 준비
import cv2
src = cv2.imread("image.jpg", cv2.IMREAD_COLOR)
dst = cv2.blur(src, (9, 9), anchor=(-1, -1), borderType=cv2.BORDER_DEFAULT)
cv2.imshow("dst", dst)
cv2.waitKey()
cv2.destroyAllWindows()
💡 출력 결과
7. 세 가지 대표적인 엣지(경계) 검출 알고리즘
📂 이미지 파일 준비
import cv2
src = cv2.imread("image.jpg", cv2.IMREAD_COLOR)
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
sobel = cv2.Sobel(gray, cv2.CV_8U, 1, 0, 3)
cv2.imshow("sobel", sobel)
laplacian = cv2.Laplacian(gray, cv2.CV_8U, ksize=3)
cv2.imshow("laplacian", laplacian)
canny = cv2.Canny(gray, 100, 200)
cv2.imshow("canny", canny)
cv2.waitKey()
cv2.destroyAllWindows()
💡 출력 결과
sobel
laplacian
canny
8. 컬러 이미지의 BGR(Blue, Green, Red) 채널을 분리 후 채널 순서를 바꿔서 이미지 합치기
📂 이미지 파일 준비
import numpy as np
import cv2
src = cv2.imread("image.jpg", cv2.IMREAD_COLOR)
#b,g,r = cv2.split(src)
b = src[:, :, 0]
g = src[:, :, 1]
r = src[:, :, 2]
inverse = cv2.merge((r,g,b))
cv2.imshow("b", b)
cv2.imshow("g", g)
cv2.imshow("r", r)
cv2.imshow("inverse", inverse)
cv2.waitKey()
cv2.destroyAllWindows()
💡 출력 결과
B
G
R
inverse
9. 컬러 이미지의 BGR(Blue, Green, Red) 채널을 분리 후 Red 채널만 0(검정색)
📂 이미지 파일 준비
import numpy as np
import cv2
src = cv2.imread("bgr.png", cv2.IMREAD_COLOR)
b = src[:, :, 0]
g = src[:, :, 1]
r = src[:, :, 2]
height, width, channel = src.shape
zero = np.zeros((height, width, 1), dtype=np.uint8)
bgz = cv2.merge((b, g, zero))
cv2.imshow("b", b)
cv2.imshow("g", g)
cv2.imshow("r", r)
cv2.imshow("bgz", bgz)
cv2.waitKey()
cv2.destroyAllWindows()
💡 출력 결과
B
G
R
bgz
10. 동영상에서 원하는 장면을 이미지로 캡처하기
📂 동영상 파일 준비
import numpy as np
import cv2
import os
save_dir = "SON"
os.makedirs(save_dir, exist_ok=True)
cap = cv2.VideoCapture("output.mp4")
img_idx = 1
while cap.isOpened():
ret, frame = cap.read()
if not ret:
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
continue
height, width = frame.shape[:2]
small_frame = cv2.resize(frame, (width // 2, height // 2), interpolation=cv2.INTER_AREA)
cv2.imshow("Frame", small_frame)
key = cv2.waitKey(80)
if key & 0xFF == ord('q'):
break
if key & 0xFF == ord('c'):
while True:
filename = f"{img_idx:03d}.jpg"
filepath = os.path.join(save_dir, filename)
if not os.path.exists(filepath):
cv2.imwrite(filepath, small_frame)
print(f"Saved {filepath}")
img_idx += 1
break
else:
img_idx += 1
cap.release()
cv2.destroyAllWindows()
💡 출력 결과
11. 다양한 OpenCV 그리기 함수 사용해보기
import numpy as np
import cv2
cap = cv2.VideoCapture(5)
circle_centers = []
def draw_circle(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
circle_centers.append((x, y))
cv2.namedWindow("Camera")
cv2.setMouseCallback("Camera", draw_circle)
topLeft = (50, 50)
bottomRight = (300, 300)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
cv2.line(frame, topLeft, bottomRight, (0, 255, 0), 3)
cv2.rectangle(frame,
[pt+30 for pt in topLeft], [pt-30 for pt in bottomRight], (255, 0, 255), 3)
font = cv2.FONT_ITALIC
cv2.putText(frame, 'me',
[pt+40 for pt in bottomRight], font, 2, (255, 0, 255), 5)
for center in circle_centers:
cv2.circle(frame, center, 30, (255, 255, 0), 3)
cv2.imshow("Camera", frame)
key = cv2.waitKey(1)
if key & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
💡 출력 결과
12. 실시간 카메라 영상 위에 글자 출력하고 트랙바로 굵기, 크기, 색상 조절하기
import numpy as np
import cv2
cap = cv2.VideoCapture(4)
#initial
topLeft = (100, 100)
bold = 0
font_size = 1
r, g, b = 0, 255, 255
def on_bold_trackbar(value):
global bold
bold = value
def on_fontsize_trackbar(value):
global font_size
font_size = max(1, value)
def on_r(val):
global r
r = val
def on_g(val):
global g
g = val
def on_b(val):
global b
b = val
cv2.namedWindow("Camera")
cv2.createTrackbar("bold", "Camera", bold, 10, on_bold_trackbar)
cv2.createTrackbar("font size", "Camera", font_size, 10, on_fontsize_trackbar)
cv2.createTrackbar('R', 'Camera', 0, 255, on_r)
cv2.createTrackbar('G', 'Camera', 255, 255, on_g)
cv2.createTrackbar('B', 'Camera', 255, 255, on_b)
while cap.isOpened():
ret, frame = cap.read()
if ret is False:
print("Can't receive frame (stream end?). Exiting . . .")
break
# Text
cv2.putText(frame, 'TEXT', topLeft, cv2.FONT_HERSHEY_SIMPLEX, font_size, (b, g, r), 1 + bold)
# Display
cv2.imshow("Camera", frame)
key = cv2.waitKey(1)
if key & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
💡 출력 결과
13. 실시간 카메라 영상 위에 한글 출력하고 트랙바로 굵기, 크기, 색상 조절하기
import numpy as np
import cv2
from PIL import ImageFont, ImageDraw, Image
cap = cv2.VideoCapture(4)
topLeft = (100, 100)
bold = 0
font_size = 10
r, g, b = 0, 255, 255
def on_bold_trackbar(value):
global bold
bold = value
def on_fontsize_trackbar(value):
global font_size
font_size = max(10, value * 5)
def on_r(val):
global r
r = val
def on_g(val):
global g
g = val
def on_b(val):
global b
b = val
cv2.namedWindow("Camera")
cv2.createTrackbar("bold", "Camera", bold, 10, on_bold_trackbar)
cv2.createTrackbar("font size", "Camera", font_size//5, 10, on_fontsize_trackbar)
cv2.createTrackbar('R', 'Camera', 0, 255, on_r)
cv2.createTrackbar('G', 'Camera', 255, 255, on_g)
cv2.createTrackbar('B', 'Camera', 255, 255, on_b)
font_path = "NanumGothic.ttf"
while cap.isOpened():
ret, frame = cap.read()
if not ret:
print("Can't receive frame (stream end?). Exiting . . .")
break
img_pil = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img_pil)
font = ImageFont.truetype(font_path, font_size)
text = 'LEE 은성'
# Bold 효과: 여러 번 겹쳐 그리기
for dx in range(-bold, bold+1):
for dy in range(-bold, bold+1):
draw.text((topLeft[0]+dx, topLeft[1]+dy), text, font=font, fill=(r, g, b, 0))
frame = cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
cv2.imshow("Camera", frame)
key = cv2.waitKey(1)
if key & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
💡 출력 결과
-
Day1: AI Algotirhm and Structure
Von Neumann Architecture
폰 노이만 구조
폰 노이만 병목 현상
하버드 구조
파이프라인
1. 폰 노이만 구조
폰 노이만 구조란?
폰 노이만 구조가 등장하기 전까지는 하드와이어드 프로그래밍 방식을 사용했다. 폰 노이만 구조가 등장하면서, 프로그램 내장 방식을 사용하게 되었고, 특징은 명령어와 데이터가 같은 메모리 공간에 저장되고 순차적으로 실행된다.
하드와이어드 프로그래밍 방식 : 폰 노이만 구조가 등장하기 전까지는 계산을 할 때마다 손으로 직접 진공관의 회로 스위치를 조정하여 새 입력을 처리하는 하드웨어 프로그램 방식
폰 노이만 구조의 주요 구성 요소
중앙처리장치(CPU)
메모리(Memory)
입출력장치(In.Out Device)
버스 시스템(Bus)
폰 노이만 구조의 동작 원리
폰 노이만 구조의 컴퓨터는 명령어 실행 사이클을 반복 동작한다.
명령어 인출(Fetch): 메모리에서 명령어를 가져온다.
명령어 해석(Decode): 메모리에서 가져온 명령어가 어떤 명령어인지 해석한다.
명령어 실행(Execute): 명령어를 실행한다.
메모리 연산(Data Memory): 명령어 수행을 위해 메모리와 데이터 레지스터 간의 데이터 이동을 처리
저장(WriteBack): 연산 결과를 메모리에 저장한다.
//사진 넣기
2. 폰 노이만 구조의 병목 현상
폰 노이만 구조의 단점
폰노이만 구조의 가장 치명적인 단점은 폰노이만 병목현상이다.
단일 버스 구조
명령어와 데이터가 같은 버스를 공유하기 때문에 나타나는 현상이다. CPU는 한번에 명령어 또는 데이터를 가져올 수 있기 때문에 동시에 불가능하다.
메모리 벽
CPU의 성능은 기하급수적으로 발전했지만, 메모리의 속도가 그에 미치지 못해 이 속도 격차가 CPU의 대기 시간을 늘려 CPU의 제 성능을 발휘하지 못한다.
순차적 처리
명령어가 순차적으로 실행이 되는데, 이러한 처리 방식은 갈수록 데이터 종류가 다양해지고, 대규모 병렬 연산이 필요한 현대 사회에서는 비효율적이다.
폰 노이만 구조의 병목현상이 미치는 영향
상대적으로 메모리보다 빠른 CPU가 대부분의 시간을 메모리를 기다리게 되므로 시스템의 성능 저하로 이어진다. (CPU의 유후 시간 증가)
데이터가 CPU와 메모리를 왔다갔다하는 것이 전력 소모가 크다.
-> 신호 전이(Transition)에 따른 전력 소모
버스에서 데이터가 0->1, 1->0으로 바뀔 때마다 transition이 발생 -> transition의 횟수가 많아질수록 전력 소모 증가
-> 캐패시터 충전과 방전
버스의 선로는 캐패시터 역할을 함 -> 데이터가 변경 될 때마다 커패시터를 충방전하게 된다 -> 더 빠른 스위칭을 위해서는 높은 과도 전류가 필요하게 되어 전력 소모가 증가하게 된다.
3. 하버드 구조
하버드 구조란?
폰 노이만 구조에서는 하나의 버스 시스템에서 데이터와 명령어가 이동했지만, 하버드 구조는 명령어와 데이터를 물리적으로 분리된 메모리에 저장하고 접근하는 구조이다.
폰 노이만 구조 vs 하버드 구조
하버드 구조에서는 폰 노이만 구조와 달리 명령어를 메모리로부터 읽는 것과 데이터를 메모리로부터 읽는 것을 동시에 할 수 있다.
하버드 구조는 병렬 처리를 통한 성능 향상이 가능하다. 현재 명령어를 처리함과 동시에 다음 명령어를 읽을 수 있다. (파이프라인)
하버드 구조 적용 사례
디지털 신호 처리기 (DSP)에서 주로 사용한다. 실시간 데이터 처리가 중요한 프로세서로, 하버드 구조의 병렬 메모리 접근 능력이 더 높은 메모리 대역폭을 제공하기 때문이다.
메모리 대역폭이란?
-> 단위 시간당 전송 가능한 데이터의 양, 초당 얼마나 많은 비트(bit)를 주고받을 수 있는 지.
-> CPU가 명령어를 인출하면서 동시에 데이터 메모리에서 연산에 필요한 데이터를 읽어올 수 있다. 즉, 두 개의 독립된 명령어 버스, 데이터 버스를 통해 동시에 전송이 가능하므로 전체 메모리 대역폭을 두배로 사용 가능.
-
-
-
-
CMOS Inverter
CMOS Inverter Simulation with Synopsys Custom Compiler
This guide walks through creating, simulating, and analyzing a CMOS inverter schematic using Synopsys Custom Compiler and PrimeWave.
1. Library and Cell Setup
Create a new library:
New → Library
Set attributes:
Name: Library name
Technology: Select tech library
Create a new CellView:
File → New → CellView
Configure:
Cell Name: Inverter
View Name: schematic
Design Settings:
Options → Design → Configure:
Snap Spacing (X,Y): Grid spacing
Solder Dot Size: Connection point size
Fat Wire Width: Thick wire width
Default Net Prefix: Signal prefix
2. Schematic Design
Add Components:
Use the Add tool (I=Instance, W=Wire, L=Label, P=Pin):
Add
I
W
L
P
Instance
Wire
Label
Pin
CMOS Inverter Schematic:
Place PMOS and NMOS transistors
Connect to VDD (top) and VSS (bottom)
Add input (VIN) and output (VOUT) pins
CMOS Schematic
Component Properties:
Select components → Press q → Configure:
Transistor dimensions (W/L)
Net connections
3. Symbol Creation
Generate Symbol:
Pin Arrangement:
Position
Pin Name
Left
VIN
Right
VOUT
Top
VDD
Bottom
VSS
Adjust Pins
Final Inverter Symbol:
Not symbol
4. Test Schematic Setup
Create Testbench:
Add Components:
Inverter symbol (Instance)
Ground (GND)
Voltage source (VDC)
Configure Voltage Sources:
Component
Property
Value
VDD
Voltage
1.8V
VIN
Voltage
DC variable
VSS
Voltage
0V
5. Simulation with PrimeWave
Launch PrimeWave:
Set Model Files:
Configure Simulation:
Model Section: Select (e.g., FF)
Variables: Copy from Design → Set VIN=0 (설정하지 않으면 simulation이 안나올 수 있다)
Simulation Engine: PrimeSim HSPICE
Run Analysis:
Setup → Analyses
Analysis Type: dc
DC Analysis → Design Variable
Variable Name, Sweep Type: VIN
Start, Stop, Step Size: e.g., 0, 1.8, 0.01
Run Simulation:
Results:
NOT WaveView
6. Troubleshooting
Schematic Lock Issue:
Delete lock file: *sch.oa.cdslck
Advanced Configuration:
Variable overrides
Simulator options
Key Notes
VIN Initialization: Must be set to 0V for DC sweep
Model Selection: Use correct technology corner (e.g., FF)
Port Connections: Verify VDD/VSS connections in test schematic
This structured guide ensures reproducible CMOS inverter simulation with clear visualization at each step.
-
-
[ex46]
문제 설명
정답 코드
//stm32f10x_it.c
volatile int Uart1_Rx_In = 0;
volatile int Uart1_Rx_Data = 0;
void USART1_IRQHandler(void)
{
Uart1_Rx_Data = (unsigned char)USART1->DR;
Uart1_Send_Byte(Uart1_Rx_Data);
Uart1_Rx_In = 1;
NVIC_ClearPendingIRQ(37);
}
volatile int note_end = 0;
void TIM2_IRQHandler(void)
{
Macro_Clear_Bit(TIM2->SR, 0);
NVIC_ClearPendingIRQ(28);
note_end = 1;
}
//main.c
#include "device_driver.h"
static void Sys_Init(void)
{
Clock_Init();
LED_Init();
Uart_Init(115200);
Key_Poll_Init();
SCB->VTOR = 0x08003000;
SCB->SHCSR = 0;
}
#define BASE (500) //msec
enum key{C1, C1_, D1, D1_, E1, F1, F1_, G1, G1_, A1, A1_, B1, C2, C2_, D2, D2_, E2, F2, F2_, G2, G2_, A2, A2_, B2};
enum note{N16=BASE/4, N8=BASE/2, N4=BASE, N2=BASE*2, N1=BASE*4};
const int song1[][2] = { {G1,N4},{G1,N4},{E1,N8},{F1,N8},{G1,N4},{A1,N4},{A1,N4},{G1,N2},{G1,N4},{C2,N4},{E2,N4},{D2,N8},{C2,N8},{D2,N2} };
static void Buzzer_Beep(unsigned char tone, int duration)
{
const static unsigned short tone_value[] = {261,277,293,311,329,349,369,391,415,440,466,493,523,554,587,622,659,698,739,783,830,880,932,987};
TIM3_Out_Freq_Generation(tone_value[tone]);
TIM2_Delay(duration);
}
extern volatile int Uart1_Rx_In;
extern volatile int Uart1_Rx_Data;
extern volatile int note_end;
void Main(void)
{
Sys_Init();
TIM4_Out_Init();
TIM3_Out_Init();
Uart1_RX_Interrupt_Enable(1);
static int timer_run = 0;
volatile int i = 0;
Buzzer_Beep(song1[i][0], song1[i][1]);
for(;;)
{
if (Uart1_Rx_In)
{
Uart1_Rx_Data = Uart1_Rx_Data - '0';
if (Uart1_Rx_Data == 0)
{
TIM4_Out_Stop();
timer_run = 0;
}
else
{
if (timer_run == 0)
{
TIM4_Out_PWM_Generation(1000, Uart1_Rx_Data);
timer_run = 1;
}
else
{
TIM4_Change_Duty(Uart1_Rx_Data);
}
}
Uart1_Rx_In = 0;
}
if (note_end)
{
TIM3_Out_Stop();
i++;
if (i >= sizeof(song1)/sizeof(song1[0]))
{
i = 0;
}
Buzzer_Beep(song1[i][0], song1[i][1]);
note_end = 0;
}
}
}
메모
printf 내부의 \n 습관화 필요
-
Manage blog comments with Giscus
Giscus is a free comments system powered without your own database. Giscus uses the Github Discussions to store and load associated comments based on a chosen mapping (URL, pathname, title, etc.).
To comment, visitors must authorize the giscus app to post on their behalf using the GitHub OAuth flow. Alternatively, visitors can comment on the GitHub Discussion directly. You can moderate the comments on GitHub.
Prerequisites
Create a github repo
You need a GitHub repository first. If you gonna use GitHub Pages for hosting your website, you can choose the corresponding repository (i.e., [userID].github.io)
The repository should be public, otherwise visitors will not be able to view the discussion.
Turn on Discussion feature
In your GitHub repository Settings, make sure that General > Features > Discussions feature is enabled.
Activate Giscus API
Follow the steps in Configuration guide. Make sure the verification of your repository is successful.
Then, scroll down from the manual page and choose the Discussion Category options. You don’t need to touch other configs.
Copy _config.yml
Now, you get the giscus script. Copy the four properties marked with a red box as shown below:
Paste those values to _config.yml placed in the root directory.
# External API
giscus_repo: "[ENTER REPO HERE]"
giscus_repoId: "[ENTER REPO ID HERE]"
giscus_category: "[ENTER CATEGORY NAME HERE]"
giscus_categoryId: "[ENTER CATEGORY ID HERE]"
None
· 2024-02-03
-
Classic Literature #2: Don Quixote
About the book
Author: Miguel de Cervantes
Original title: El ingenioso hidalgo don Quixote de la Mancha
Country: Spain
Genre: Novel
Publication date:
1605 (Part One)
1615 (Part Two)
Chapter I.
In a village of La Mancha, the name of which I have no desire to call to mind, there lived not long since one of those gentlemen that keep a lance in the lance-rack, an old buckler, a lean hack, and a greyhound for coursing. An olla of rather more beef than mutton, a salad on most nights, scraps on Saturdays, lentils on Fridays, and a pigeon or so extra on Sundays, made away with three-quarters of his income. The rest of it went in a doublet of fine cloth and velvet breeches and shoes to match for holidays, while on week-days he made a brave figure in his best homespun. He had in his house a housekeeper past forty, a niece under twenty, and a lad for the field and market-place, who used to saddle the hack as well as handle the bill-hook. The age of this gentleman of ours was bordering on fifty; he was of a hardy habit, spare, gaunt-featured, a very early riser and a great sportsman. They will have it his surname was Quixada or Quesada (for here there is some difference of opinion among the authors who write on the subject), although from reasonable conjectures it seems plain that he was called Quexana. This, however, is of but little importance to our tale; it will be enough not to stray a hair’s breadth from the truth in the telling of it.
You must know, then, that the above-named gentleman whenever he was at leisure (which was mostly all the year round) gave himself up to reading books of chivalry with such ardour and avidity that he almost entirely neglected the pursuit of his field-sports, and even the management of his property; and to such a pitch did his eagerness and infatuation go that he sold many an acre of tillageland to buy books of chivalry to read, and brought home as many of them as he could get. But of all there were none he liked so well as those of the famous Feliciano de Silva’s composition, for their lucidity of style and complicated conceits were as pearls in his sight, particularly when in his reading he came upon courtships and cartels, where he often found passages like “the reason of the unreason with which my reason is afflicted so weakens my reason that with reason I murmur at your beauty;” or again, “the high heavens, that of your divinity divinely fortify you with the stars, render you deserving of the desert your greatness deserves.” Over conceits of this sort the poor gentleman lost his wits, and used to lie awake striving to understand them and worm the meaning out of them; what Aristotle himself could not have made out or extracted had he come to life again for that special purpose. He was not at all easy about the wounds which Don Belianis gave and took, because it seemed to him that, great as were the surgeons who had cured him, he must have had his face and body covered all over with seams and scars. He commended, however, the author’s way of ending his book with the promise of that interminable adventure, and many a time was he tempted to take up his pen and finish it properly as is there proposed, which no doubt he would have done, and made a successful piece of work of it too, had not greater and more absorbing thoughts prevented him.
Many an argument did he have with the curate of his village (a learned man, and a graduate of Siguenza) as to which had been the better knight, Palmerin of England or Amadis of Gaul. Master Nicholas, the village barber, however, used to say that neither of them came up to the Knight of Phoebus, and that if there was any that could compare with him it was Don Galaor, the brother of Amadis of Gaul, because he had a spirit that was equal to every occasion, and was no finikin knight, nor lachrymose like his brother, while in the matter of valour he was not a whit behind him. In short, he became so absorbed in his books that he spent his nights from sunset to sunrise, and his days from dawn to dark, poring over them; and what with little sleep and much reading his brains got so dry that he lost his wits. His fancy grew full of what he used to read about in his books, enchantments, quarrels, battles, challenges, wounds, wooings, loves, agonies, and all sorts of impossible nonsense; and it so possessed his mind that the whole fabric of invention and fancy he read of was true, that to him no history in the world had more reality in it. He used to say the Cid Ruy Diaz was a very good knight, but that he was not to be compared with the Knight of the Burning Sword who with one back-stroke cut in half two fierce and monstrous giants. He thought more of Bernardo del Carpio because at Roncesvalles he slew Roland in spite of enchantments, availing himself of the artifice of Hercules when he strangled Antaeus the son of Terra in his arms. He approved highly of the giant Morgante, because, although of the giant breed which is always arrogant and ill-conditioned, he alone was affable and well-bred. But above all he admired Reinaldos of Montalban, especially when he saw him sallying forth from his castle and robbing everyone he met, and when beyond the seas he stole that image of Mahomet which, as his history says, was entirely of gold. To have a bout of kicking at that traitor of a Ganelon he would have given his housekeeper, and his niece into the bargain.
In short, his wits being quite gone, he hit upon the strangest notion that ever madman in this world hit upon, and that was that he fancied it was right and requisite, as well for the support of his own honour as for the service of his country, that he should make a knight-errant of himself, roaming the world over in full armour and on horseback in quest of adventures, and putting in practice himself all that he had read of as being the usual practices of knights-errant; righting every kind of wrong, and exposing himself to peril and danger from which, in the issue, he was to reap eternal renown and fame. Already the poor man saw himself crowned by the might of his arm Emperor of Trebizond at least; and so, led away by the intense enjoyment he found in these pleasant fancies, he set himself forthwith to put his scheme into execution.
The first thing he did was to clean up some armour that had belonged to his great-grandfather, and had been for ages lying forgotten in a corner eaten with rust and covered with mildew. He scoured and polished it as best he could, but he perceived one great defect in it, that it had no closed helmet, nothing but a simple morion. This deficiency, however, his ingenuity supplied, for he contrived a kind of half-helmet of pasteboard which, fitted on to the morion, looked like a whole one. It is true that, in order to see if it was strong and fit to stand a cut, he drew his sword and gave it a couple of slashes, the first of which undid in an instant what had taken him a week to do. The ease with which he had knocked it to pieces disconcerted him somewhat, and to guard against that danger he set to work again, fixing bars of iron on the inside until he was satisfied with its strength; and then, not caring to try any more experiments with it, he passed it and adopted it as a helmet of the most perfect construction.
He next proceeded to inspect his hack, which, with more quartos than a real and more blemishes than the steed of Gonela, that “tantum pellis et ossa fuit,” surpassed in his eyes the Bucephalus of Alexander or the Babieca of the Cid. Four days were spent in thinking what name to give him, because (as he said to himself) it was not right that a horse belonging to a knight so famous, and one with such merits of his own, should be without some distinctive name, and he strove to adapt it so as to indicate what he had been before belonging to a knight-errant, and what he then was; for it was only reasonable that, his master taking a new character, he should take a new name, and that it should be a distinguished and full-sounding one, befitting the new order and calling he was about to follow. And so, after having composed, struck out, rejected, added to, unmade, and remade a multitude of names out of his memory and fancy, he decided upon calling him Rocinante, a name, to his thinking, lofty, sonorous, and significant of his condition as a hack before he became what he now was, the first and foremost of all the hacks in the world.
Having got a name for his horse so much to his taste, he was anxious to get one for himself, and he was eight days more pondering over this point, till at last he made up his mind to call himself “Don Quixote,” whence, as has been already said, the authors of this veracious history have inferred that his name must have been beyond a doubt Quixada, and not Quesada as others would have it. Recollecting, however, that the valiant Amadis was not content to call himself curtly Amadis and nothing more, but added the name of his kingdom and country to make it famous, and called himself Amadis of Gaul, he, like a good knight, resolved to add on the name of his, and to style himself Don Quixote of La Mancha, whereby, he considered, he described accurately his origin and country, and did honour to it in taking his surname from it.
So then, his armour being furbished, his morion turned into a helmet, his hack christened, and he himself confirmed, he came to the conclusion that nothing more was needed now but to look out for a lady to be in love with; for a knight-errant without love was like a tree without leaves or fruit, or a body without a soul. As he said to himself, “If, for my sins, or by my good fortune, I come across some giant hereabouts, a common occurrence with knights-errant, and overthrow him in one onslaught, or cleave him asunder to the waist, or, in short, vanquish and subdue him, will it not be well to have some one I may send him to as a present, that he may come in and fall on his knees before my sweet lady, and in a humble, submissive voice say, ‘I am the giant Caraculiambro, lord of the island of Malindrania, vanquished in single combat by the never sufficiently extolled knight Don Quixote of La Mancha, who has commanded me to present myself before your Grace, that your Highness dispose of me at your pleasure’?” Oh, how our good gentleman enjoyed the delivery of this speech, especially when he had thought of some one to call his Lady! There was, so the story goes, in a village near his own a very good-looking farm-girl with whom he had been at one time in love, though, so far as is known, she never knew it nor gave a thought to the matter. Her name was Aldonza Lorenzo, and upon her he thought fit to confer the title of Lady of his Thoughts; and after some search for a name which should not be out of harmony with her own, and should suggest and indicate that of a princess and great lady, he decided upon calling her Dulcinea del Toboso—she being of El Toboso—a name, to his mind, musical, uncommon, and significant, like all those he had already bestowed upon himself and the things belonging to him.
-
Classic Literature #1: Romeo and Juliet
About the book
Author: William Shakespeare
Country: England
Genre: Shakespearean tragedy
Publication date: 1597
Synopsis
The prologue of Romeo and Juliet calls the title characters “star-crossed lovers”—and the stars do seem to conspire against these young lovers.
Romeo is a Montague, and Juliet a Capulet. Their families are enmeshed in a feud, but the moment they meet—when Romeo and his friends attend a party at Juliet’s house in disguise—the two fall in love and quickly decide that they want to be married.
A friar secretly marries them, hoping to end the feud. Romeo and his companions almost immediately encounter Juliet’s cousin Tybalt, who challenges Romeo. When Romeo refuses to fight, Romeo’s friend Mercutio accepts the challenge and is killed. Romeo then kills Tybalt and is banished. He spends that night with Juliet and then leaves for Mantua.
Juliet’s father forces her into a marriage with Count Paris. To avoid this marriage, Juliet takes a potion, given her by the friar, that makes her appear dead. The friar will send Romeo word to be at her family tomb when she awakes. The plan goes awry, and Romeo learns instead that she is dead. In the tomb, Romeo kills himself. Juliet wakes, sees his body, and commits suicide. Their deaths appear finally to end the feud.
-
Classic Literature #1: Romeo and Juliet
About the book
Author: William Shakespeare
Country: England
Genre: Shakespearean tragedy
Publication date: 1597
Synopsis
The prologue of Romeo and Juliet calls the title characters “star-crossed lovers”—and the stars do seem to conspire against these young lovers.
Romeo is a Montague, and Juliet a Capulet. Their families are enmeshed in a feud, but the moment they meet—when Romeo and his friends attend a party at Juliet’s house in disguise—the two fall in love and quickly decide that they want to be married.
A friar secretly marries them, hoping to end the feud. Romeo and his companions almost immediately encounter Juliet’s cousin Tybalt, who challenges Romeo. When Romeo refuses to fight, Romeo’s friend Mercutio accepts the challenge and is killed. Romeo then kills Tybalt and is banished. He spends that night with Juliet and then leaves for Mantua.
Juliet’s father forces her into a marriage with Count Paris. To avoid this marriage, Juliet takes a potion, given her by the friar, that makes her appear dead. The friar will send Romeo word to be at her family tomb when she awakes. The plan goes awry, and Romeo learns instead that she is dead. In the tomb, Romeo kills himself. Juliet wakes, sees his body, and commits suicide. Their deaths appear finally to end the feud.
-
My personal Online Library
What is Lorem Ipsum?
This is an example post ‘<’. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry’s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
Why do we use it?
It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using ‘Content here, content here’, making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for ‘lorem ipsum’ will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).
Where does it come from?
Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of “de Finibus Bonorum et Malorum” (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, “Lorem ipsum dolor sit amet..”, comes from a line in section 1.10.32.
The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from “de Finibus Bonorum et Malorum” by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.
Where can I get some?
There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don’t look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn’t anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.
-
Touch background to close