10월 6일
어제 한 건 크게 보면 반도체를 설계한 거라고 한다. 별로 와닿지는 않는다...
어제 한 부분에서 net list를 만든다. 이 파일을 가지고 반도체 게이트 회로 등을 배열을 한다(P&R 작업). pcb로 얘기해보자면 schematic에서 설계를 한 거로 net list를 만들고 pcb editor work로 로딩을 한다. 그러면 라이브러리에 맞춰 부품들이 화면에 나타난다.
무질서한 부품의 나열에서 어떤 배치를 하느냐로 pcb 성능이 달라진다. 선을 어떻게 연결하느냐 두껍게 하느냐 길게 하느냐 등 안정성에 영향을 준다. 하드웨어가 복잡할수록, 클락이 높아질수록 민감해지며 관련 노하우가 중요하다. 심하면 선길이 1cm 차이로도 에러가 나타난다고 하는데 자주 일어나는 일이 아니라서 이런 경우 정말 알아차리기 힘들다고... 경험담이신가?
다시 돌아와서 wafer에다 찍어내는 회로를 위한 작업을 P&R이라고 한다. pcb에서 배치를 다 하면 거버파일이 만들어지는 것처럼 P&R 작업을 끝내면 특정 파일이 만들어진다. 그걸 wafer 공정에 넘기면 리소그래피를 통해 회로를 그린다. 그냥 흐름을 알라고 개발자 상식으로 말씀해주신 부분.
어쨌든 우리는 반도체 칩을 설계하는 거라고 할 수 있다. 현재 FPGA에 대해 verilog로 코딩을 진행하는데, 실제 반도체 칩 설계도 verilog로 한다고 한다. 게이트 그리고 뭐 그리고..., 그런 거 안 한다고 한다.
-----------
어제 4bit짜리 Adder, Subtractor를 만든 건 기초회로다. remind) A - B 뺄셈은 B의 2의 보수를 더하면 된다.
가산기에 대한 건 미세하게나마 더 빠르게 연산될 수 있도록 다양한 종류의 회로가 있다고 한다.
오늘은 Decoder를 배우고 FND에 1자리 숫자를 표시하자. 좀 더 구체적으로는 가산기, 감산기의 결과값을 FND에 출력하자.
--------
그래서 Decoder란?
일단, 흔하게 쓰는 걸로 74LS139가 있음.
https://pdf1.alldatasheet.com/datasheet-pdf/view/8082/NSC/74LS139.html
74LS139 pdf, 74LS139 Description, 74LS139 Datasheet, 74LS139 view ::: ALLDATASHEET :::
pdf1.alldatasheet.com
이걸 2*4 decoder라고 하고, 74 series를 TTL이라고 부른다.
빨강, 파랑 각각 입력을 받는 핀 2개와 출력을 보내는 핀 4개가 있음. 즉, 디코더가 두 개 들어있다.(138은 3*8 decoder라고 한다. 입력 수와 출력 수를 요약해서 부르는 방식인 거 같다.)
다시 한 번 진리표를 보자면, 아래와 같은데 입력값이 010이면 출력값이 1101로 정해져있다. 이렇듯 입력에 대한 출력값이 정해져있는 게 decoder이다. 이때 G(enable)이 high면 입력에 상관없이 출력이 1111이 되면서 동작을 하지 않는다.
~G | B | A | Y0 | Y1 | Y2 | Y3 |
0 | 0 | 0 | 0 | 1 | 1 | 1 |
0 | 0 | 1 | 1 | 0 | 1 | 1 |
0 | 1 | 0 | 1 | 1 | 0 | 1 |
0 | 1 | 1 | 1 | 1 | 1 | 0 |
1 | x | x | 1 | 1 | 1 | 1 |
인코더는 반대로 입력값이 4개에 출력값이 2개다. 암호화하고 디코더는 복호화, 해독한다고 표현한다. 난 그냥 입력 출력이 명확한 걸 의미하는 줄 알았는데, 조금 달랐다. 이렇게 보니 어제 잠깐 말했던 디코더, 인코더 설명이 이해된다.
https://woodforest.tistory.com/123
디코더, 인코더 (Decoder, Encoder)
디코더 (Decoder) n비트의 정보를 입력으로 받아 2^n개의 출력으로 해독한다 명령어의 operand/address를 해독할 때 주로 사용 복호기로서 복호화 작업 수행 3*8 디코더의 회로와 진리표 인코더 (Encoder) 2
woodforest.tistory.com
입력에 따라 하나만 0이 나온다.(하나만 1이 나오는 디코더도 물론 있다.) 이런 특성을 어떻게 사용하냐면 보통 Chip select에 이용했다고 한다. 옛날엔 외부 메모리 ROM 따로 만들고, RAM 따로 만들고 I/O도 따로 만들고 UART 통신을 위해서도 따로 만들고.. 이러니까 chip select이 필요했는데, 요즘 나오는 건 다 one chip 형태다. 안에 플래시메모리도 RAM도 I/O도 uart 통신 기능도 다 들어있으니까 그만큼 사용이 확 줄었다. 하지만 반도체 설계할 때는 알아야 한다.
우리는 이걸 어떻게 사용해야 좋을까. 현재 보드에는 FND 4개가 있다. 데이터시트를 보면 아래와 같다.
https://digilent.com/reference/_media/basys3:basys3_rm.pdf
**
pn junction의 forward bias를 생각해서 전류가 흐르는 방향으로 tr 구분을 했었는데(P->N), 나침반을 떠올려서 화살표가 꽂히는 곳을 N으로 생각하라고 하심.
--------
tr 왜 이렇게 헷갈리지?;; 다 이해했던 건데...
------------
timer interrupt는 주기마다 자리수를 달리해 하나씩 출력했음.(잔상이 남아 우리 눈에는 동시에 보였음)
-------
생성하고 전체 복사해서 .gitignore에 붙여넣기하면 끝.
begin end는 중괄호 역할임.
always @() begin
@이 있어야 바라보는데, 항상 소괄호 속 입력을 바라보고 있다는 의미. or을 써도 되고 comma를 써도 된다고 함.
(i_DigitSelect, i_En) (i_DigitSelect or i_En)
always 안에서만 if를 쓸 수 있음.
verilog는 hardware를 설계하기 위한 코드임.
: if를 always문 밖에서 쓰면 조건 변수를 계속 바라봐야 하나 하드웨어는 의문이 생김.
입력을 low로 줘야 FND가 동작하는 상황임. 따라서 Enable로 high가 오면 전부 high로 출력해서 동작하지 않도록 함.
그 부분이
if(i_En) beign
o_digit = 4b'1111;
end
임.
case는 endcase로 닫음.
module FND_select_decoder(
input [1:0] i_DigitSelect,
input i_En,
output [3:0] o_digit
);
always @(i_DigitSelect, i_En) begin //always @(i_DigitSelect or i_En) begin
if(i_En) begin
o_digit = 4'b1111;
end
else begin
case (i_DigitSelect)
2'h0 : o_digit = 4'b1110;
2'h1 : o_digit = 4'b1101;
2'h2 : o_digit = 4'b1011;
2'h3 : o_digit = 4'b0111;
endcase
end
end
endmodule
에러남.
input, output의 default는 wire type임. 메모리기능이 없음. 그래서 값 대입이 안 됨. 수정하면 아래와 같음.
module FND_select_decoder(
input [1:0] i_DigitSelect,
input i_En,
output [3:0] o_digit
);
reg [3:0] r_digit;
assign o_digit = r_digit;
always @(i_DigitSelect, i_En) begin //always @(i_DigitSelect or i_En) begin
if(i_En) begin
r_digit = 4'b1111;
end
else begin
case (i_DigitSelect)
2'h0 : r_digit = 4'b1110;
2'h1 : r_digit = 4'b1101;
2'h2 : r_digit = 4'b1011;
2'h3 : r_digit = 4'b0111;
endcase
end
end
endmodule
concurrency 때문에 assign의 위치는 어디에 있든 상관없지만 c언어 하던 버릇 때문에 상단에 assign하는게 눈에 잘 띔.
------
module BCDtoFND_decoder(
input [3:0] i_value,
input i_En,
output [7:0] o_font
);
reg [7:0] r_font;
assign o_font = r_font;
always @(i_value, i_En) begin
if (i_En) begin
r_font = 8'hff;
end
else begin
case (i_value)
4'h0 : r_font = 8'hc0;
4'h1 : r_font = 8'hf9;
4'h2 : r_font = 8'ha4;
4'h3 : r_font = 8'hb0;
4'h4 : r_font = 8'h99;
4'h5 : r_font = 8'h92;
4'h6 : r_font = 8'h82;
4'h7 : r_font = 8'hf8;
4'h8 : r_font = 8'h90;
4'h9 : r_font = 8'h7f;
endcase
end
end
endmodule
경우의 수가 다 입력되지 않은 경우 원치 않는 latch가 생길 수 있음. default를 추가하거나 아예 밖에서 지정할 수도 있음.
module BCDtoFND_decoder(
input [3:0] i_value,
input i_En,
output [7:0] o_font
);
reg [7:0] r_font;
assign o_font = r_font;
always @(i_value, i_En) begin
if (i_En) begin
r_font = 8'hff;
end
else begin
case (i_value)
4'h0 : r_font = 8'hc0;
4'h1 : r_font = 8'hf9;
4'h2 : r_font = 8'ha4;
4'h3 : r_font = 8'hb0;
4'h4 : r_font = 8'h99;
4'h5 : r_font = 8'h92;
4'h6 : r_font = 8'h82;
4'h7 : r_font = 8'hf8;
4'h8 : r_font = 8'h90;
4'h9 : r_font = 8'h7f;
default r_font = 8'hff;
endcase
end
end
endmodule
module BCDtoFND_decoder(
input [3:0] i_value,
input i_En,
output [7:0] o_font
);
reg [7:0] r_font;
assign o_font = r_font;
always @(i_value, i_En) begin
if (i_En) begin
r_font = 8'hff;
end
else begin
r_font = 8'hff;
case (i_value)
4'h0 : r_font = 8'hc0;
4'h1 : r_font = 8'hf9;
4'h2 : r_font = 8'ha4;
4'h3 : r_font = 8'hb0;
4'h4 : r_font = 8'h99;
4'h5 : r_font = 8'h92;
4'h6 : r_font = 8'h82;
4'h7 : r_font = 8'hf8;
4'h8 : r_font = 8'h90;
4'h9 : r_font = 8'h7f;
endcase
end
end
endmodule
------
contraints 수정
##7 segment display
set_property -dict { PACKAGE_PIN W7 IOSTANDARD LVCMOS33 } [get_ports { o_font[0] }]; #IO_L13P_T2_MRCC_34 ,Sch=CA
set_property -dict { PACKAGE_PIN W6 IOSTANDARD LVCMOS33 } [get_ports { o_font[1] }]; #IO_L13N_T2_MRCC_34 ,Sch=CB
set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS33 } [get_ports { o_font[2] }]; #IO_L14P_T2_SRCC_34 ,Sch=CC
set_property -dict { PACKAGE_PIN V8 IOSTANDARD LVCMOS33 } [get_ports { o_font[3] }]; #IO_L14N_T2_SRCC_34 ,Sch=CD
set_property -dict { PACKAGE_PIN U5 IOSTANDARD LVCMOS33 } [get_ports { o_font[4] }]; #IO_L16P_T2_34 ,Sch=CE
set_property -dict { PACKAGE_PIN V5 IOSTANDARD LVCMOS33 } [get_ports { o_font[5] }]; #IO_L16N_T2_34 ,Sch=CF
set_property -dict { PACKAGE_PIN U7 IOSTANDARD LVCMOS33 } [get_ports { o_font[6] }]; #IO_L19P_T3_34 ,Sch=CG
set_property -dict { PACKAGE_PIN V7 IOSTANDARD LVCMOS33 } [get_ports { o_font[7] }]; #IO_L19N_T3_VREF_34 ,Sch=DP
set_property -dict { PACKAGE_PIN U2 IOSTANDARD LVCMOS33 } [get_ports { o_digit[0] }]; #IO_L9N_T1_DQS_34 ,Sch=DP
set_property -dict { PACKAGE_PIN U4 IOSTANDARD LVCMOS33 } [get_ports { o_digit[1] }]; #IO_L11P_T1_SRCC_34 ,Sch=DP
set_property -dict { PACKAGE_PIN V4 IOSTANDARD LVCMOS33 } [get_ports { o_digit[2] }]; #IO_L11N_T1_SRCC_34 ,Sch=DP
set_property -dict { PACKAGE_PIN W4 IOSTANDARD LVCMOS33 } [get_ports { o_digit[3] }]; #IO_L12N_T1_MRCC_34 ,Sch=DP
## Switches
set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { i_value[0] }]; #IO_L19N_T3_A09_D25_VREF_14 ,Sch=SW0
set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { i_value[1] }]; #IO_L19P_T3_A10_D26_14 ,Sch=SW1
set_property -dict { PACKAGE_PIN W16 IOSTANDARD LVCMOS33 } [get_ports { i_value[2] }]; #IO_L20P_T3_A08_D24_14 ,Sch=SW2
set_property -dict { PACKAGE_PIN W17 IOSTANDARD LVCMOS33 } [get_ports { i_value[3] }]; #IO_L20N_T3_A07_D23_14 ,Sch=SW3
#set_property -dict { PACKAGE_PIN W15 IOSTANDARD LVCMOS33 } [get_ports { sw[4] }]; #IO_L21N_T3_DQS_A06_D22_14 ,Sch=SW4
#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { sw[5] }]; #IO_L21P_T3_DQS_14 ,Sch=SW5
#set_property -dict { PACKAGE_PIN W14 IOSTANDARD LVCMOS33 } [get_ports { sw[6] }]; #IO_L22N_T3_A04_D20_14 ,Sch=SW6
#set_property -dict { PACKAGE_PIN W13 IOSTANDARD LVCMOS33 } [get_ports { sw[7] }]; #IO_L22P_T3_A05_D21_14 ,Sch=SW7
#set_property -dict { PACKAGE_PIN V2 IOSTANDARD LVCMOS33 } [get_ports { sw[8] }]; #IO_L5P_T0_34 ,Sch=SW8
#set_property -dict { PACKAGE_PIN T3 IOSTANDARD LVCMOS33 } [get_ports { sw[9] }]; #IO_L2N_T0_34 ,Sch=SW9
#set_property -dict { PACKAGE_PIN T2 IOSTANDARD LVCMOS33 } [get_ports { sw[10] }]; #IO_L1N_T0_34 ,Sch=SW10
#set_property -dict { PACKAGE_PIN R3 IOSTANDARD LVCMOS33 } [get_ports { sw[11] }]; #IO_L2P_T0_34 ,Sch=SW11
#set_property -dict { PACKAGE_PIN W2 IOSTANDARD LVCMOS33 } [get_ports { sw[12] }]; #IO_L5N_T0_34 ,Sch=SW12
set_property -dict { PACKAGE_PIN U1 IOSTANDARD LVCMOS33 } [get_ports { i_DigitSelect[0] }]; #IO_L3N_T0_DQS_34 ,Sch=SW13
set_property -dict { PACKAGE_PIN T1 IOSTANDARD LVCMOS33 } [get_ports { i_DigitSelect[1] }]; #IO_L3P_T0_DQS_34 ,Sch=SW14
set_property -dict { PACKAGE_PIN R2 IOSTANDARD LVCMOS33 } [get_ports { i_En }]; #IO_L1P_T0_34 ,Sch=SW15
window에서 git쓰는 것도 리눅스 명령어랑 거의 다르지 않음.
--------------
always @(*) begin //*을 쓰면 모든 입력에 대해 감시
module simple_calculator(
input [3:0] i_a, i_b,
input [1:0] i_selOperator,
output [3:0] o_result
);
reg [3:0] r_result;
assign o_result = r_result;
always @(*) begin
case (i_selOperator)
2'b00 : r_result = i_a + i_b;
2'b01 : r_result = i_a - i_b;
2'b10 : r_result = i_a * i_b;
2'b11 : begin
if(i_b == 0) r_result = 0;
else r_result = i_a / i_b;
end
endcase
end
endmodule
module calculator(
input [3:0] i_a, i_b,
input [1:0] i_selOperator, i_digitSelect,
input i_En,
output [3:0] o_digit,
output [7:0] o_font
);
wire [3:0] w_result;
simple_calculator udt(
.i_a(i_a),
.i_b(i_b),
.i_selOperator(i_selOperator),
.o_result(w_result)
);
BCDtoFND udt1(
.i_DigitSelect(i_digitSelect),
.i_value(w_result),
.i_En(i_En),
.o_digit(o_digit),
.o_font(o_font)
);
endmodule
https://youtube.com/shorts/BNEqlk0DIGo?feature=share

------------
과제
기존 FND와 4비트 가산기를 합쳐보자.
---
디자인
---
module FND_adder(
input [1:0] i_DigitSelect,
input i_En,
output [3:0] o_digit,
output [7:0] o_font,
input [3:0] i_a, i_b
);
wire [3:0] w_value;
BCDtoFND U2(
.i_DigitSelect(i_DigitSelect),
.i_value(w_value),
.i_En(i_En),
.o_digit(o_digit),
.o_font(o_font)
);
four_bit_full_adder U1(
.i_a(i_a),
.i_b(i_b),
.i_cin(i_cin),
.o_sum(w_value),
.o_carry(o_carry)
);
endmodule
## Switches
set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { i_a[0] }]; #IO_L19N_T3_A09_D25_VREF_14 ,Sch=SW0
set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { i_a[1] }]; #IO_L19P_T3_A10_D26_14 ,Sch=SW1
set_property -dict { PACKAGE_PIN W16 IOSTANDARD LVCMOS33 } [get_ports { i_a[2] }]; #IO_L20P_T3_A08_D24_14 ,Sch=SW2
set_property -dict { PACKAGE_PIN W17 IOSTANDARD LVCMOS33 } [get_ports { i_a[3] }]; #IO_L20N_T3_A07_D23_14 ,Sch=SW3
set_property -dict { PACKAGE_PIN W15 IOSTANDARD LVCMOS33 } [get_ports { i_b[0] }]; #IO_L21N_T3_DQS_A06_D22_14 ,Sch=SW4
set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { i_b[1] }]; #IO_L21P_T3_DQS_14 ,Sch=SW5
set_property -dict { PACKAGE_PIN W14 IOSTANDARD LVCMOS33 } [get_ports { i_b[2] }]; #IO_L22N_T3_A04_D20_14 ,Sch=SW6
set_property -dict { PACKAGE_PIN W13 IOSTANDARD LVCMOS33 } [get_ports { i_b[3] }]; #IO_L22P_T3_A05_D21_14 ,Sch=SW7
# set_property -dict { PACKAGE_PIN V2 IOSTANDARD LVCMOS33 } [get_ports { i_cin }]; #IO_L5P_T0_34 ,Sch=SW8
# set_property -dict { PACKAGE_PIN T3 IOSTANDARD LVCMOS33 } [get_ports { i_a[3] }]; #IO_L2N_T0_34 ,Sch=SW9
# set_property -dict { PACKAGE_PIN T2 IOSTANDARD LVCMOS33 } [get_ports { i_b[0] }]; #IO_L1N_T0_34 ,Sch=SW10
#set_property -dict { PACKAGE_PIN R3 IOSTANDARD LVCMOS33 } [get_ports { i_selOperator[0] }]; #IO_L2P_T0_34 ,Sch=SW11
#set_property -dict { PACKAGE_PIN W2 IOSTANDARD LVCMOS33 } [get_ports { i_selOperator[1] }]; #IO_L5N_T0_34 ,Sch=SW12
set_property -dict { PACKAGE_PIN U1 IOSTANDARD LVCMOS33 } [get_ports { i_DigitSelect[0] }]; #IO_L3N_T0_DQS_34 ,Sch=SW13
set_property -dict { PACKAGE_PIN T1 IOSTANDARD LVCMOS33 } [get_ports { i_DigitSelect[1] }]; #IO_L3P_T0_DQS_34 ,Sch=SW14
set_property -dict { PACKAGE_PIN R2 IOSTANDARD LVCMOS33 } [get_ports { i_En }]; #IO_L1P_T0_34 ,Sch=SW15
##7 segment display
set_property -dict { PACKAGE_PIN W7 IOSTANDARD LVCMOS33 } [get_ports { o_font[0] }]; #IO_L13P_T2_MRCC_34 ,Sch=CA
set_property -dict { PACKAGE_PIN W6 IOSTANDARD LVCMOS33 } [get_ports { o_font[1] }]; #IO_L13N_T2_MRCC_34 ,Sch=CB
set_property -dict { PACKAGE_PIN U8 IOSTANDARD LVCMOS33 } [get_ports { o_font[2] }]; #IO_L14P_T2_SRCC_34 ,Sch=CC
set_property -dict { PACKAGE_PIN V8 IOSTANDARD LVCMOS33 } [get_ports { o_font[3] }]; #IO_L14N_T2_SRCC_34 ,Sch=CD
set_property -dict { PACKAGE_PIN U5 IOSTANDARD LVCMOS33 } [get_ports { o_font[4] }]; #IO_L16P_T2_34 ,Sch=CE
set_property -dict { PACKAGE_PIN V5 IOSTANDARD LVCMOS33 } [get_ports { o_font[5] }]; #IO_L16N_T2_34 ,Sch=CF
set_property -dict { PACKAGE_PIN U7 IOSTANDARD LVCMOS33 } [get_ports { o_font[6] }]; #IO_L19P_T3_34 ,Sch=CG
set_property -dict { PACKAGE_PIN V7 IOSTANDARD LVCMOS33 } [get_ports { o_font[7] }]; #IO_L19N_T3_VREF_34 ,Sch=DP
set_property -dict { PACKAGE_PIN U2 IOSTANDARD LVCMOS33 } [get_ports { o_digit[0] }]; #IO_L9N_T1_DQS_34 ,Sch=DP
set_property -dict { PACKAGE_PIN U4 IOSTANDARD LVCMOS33 } [get_ports { o_digit[1] }]; #IO_L11P_T1_SRCC_34 ,Sch=DP
set_property -dict { PACKAGE_PIN V4 IOSTANDARD LVCMOS33 } [get_ports { o_digit[2] }]; #IO_L11N_T1_SRCC_34 ,Sch=DP
set_property -dict { PACKAGE_PIN W4 IOSTANDARD LVCMOS33 } [get_ports { o_digit[3] }]; #IO_L12N_T1_MRCC_34 ,Sch=DP
---
시뮬
---
https://youtube.com/shorts/WmTI19Jn1Nc?feature=share
