10월 5일
코드 파일이 안 열리고 시뮬이 제대로 안 돌아갔다. 머신러닝 관련 부분이 추가되면서 무거워졌기 때문이라고 하여 2020.1 버전으로 깔았다.
새로 프로젝트를 만들었더니 보드 찾는데 조금 차이가 있었다.
install 이후에는 검색하면 나옴. Finish하면 됨.
우리가 할 건 조합논리회로
: 메모리기능이 없는 회로(그 전의 동작을 기억하지 못 함) == flip flop이 없는 회로 == Latch 기능이 없다.
<->
순차논리회로
: 메모리기능이 있는 회로 == flip flop이 있는 회로 == Latch 기능이 있다.
(메모리의 최소 단위가 flip flop, Latch라고 함)
-----------
셋 다 프로그램을 만들 수 있는 깡통칩. 차이는 집적도. PLD가 가장 작으며 FPGA가 가장 큼.
-FPGA
-CPLD
-PLD
--------
조합논리회로Combination Logic Circuit 책 index
-게이트
: and, nand, or, nor, xor, xnor, not, buff
-가산기 (반가산기 / 전가산기)
: carry의 유무로 갈림.
: 올림수를 계산할 수 있다는 얘기라는데 모르겠음;
: 반가산기를 만들고 이를 이용해 전가산기를 만듦. 1비트 전가산기를 이용해 4비트 전가산기를 만들면 스위치 입력을 통해 동작 가능. (??)
-디코더 특정입력 --> 특정 출력. ex 1 > ... 2 > ... 각 입력에 따라 출력이 정해져있음. 순차논리회로는 안 그럼. 같은 입력 1에 대해 결과가 다를 수 있음.(메모리 기능 때문에 상황이 달라질 수 있음)
cf)인코더 : 출력을 대입했을 때 해당 입력이 나옴.
-멀티플렉서 == MUX
: 입력이 여러 개인데 출력이 하나임. 이 중에 어떤 입력을 선택할 거냐 select해주는 단계가 있음.
-비교기 ex)PWM. counter register는 계속 증가하다가 기준값을 만나고 high or low 출력. 기준값을 토대로 비교하니까 비교기 사용한 것. --> timer count를 만들면서 PWM도 하게 될 것.
------------
가산기
carry bit : 자릿수 올림을 의미.
: 1 bit 연산에 대해서 overflow의 의미도 가지고 있음(컴퓨터 입장에서).
module half_adder(
input i_switch_0, i_switch_1,
output o_sum, o_carry
);
assign o_sum = i_switch_0 ^ i_switch_1;
assign o_carry = i_switch_0 & i_switch_1;
endmodule
half adder 추상화. 구체화시킨 코드 내용은 각 input, output 및 assign.
A | B | Sum | Carry |
0 | 0 | 0 | 0 |
1 | 0 | 1 | 0 |
0 | 1 | 1 | 0 |
1 | 1 | 0 | 1 |
test bench == 물리적으로는 사용하지 않고 논리적인 값을 내부에서 적용
dut == design under test
module tb_half_adder();
reg i_switch_0, i_switch_1;
wire o_sum, o_carry;
half_adder dut(
.i_switch_0(i_switch_0),
.i_switch_1(i_switch_1),
.o_sum(o_sum),
.o_carry(o_carry)
);
initial begin
#00 i_switch_0 = 1'b0; i_switch_1 = 1'b0;
#10 i_switch_0 = 1'b0; i_switch_1 = 1'b1;
#10 i_switch_0 = 1'b1; i_switch_1 = 1'b0;
#10 i_switch_0 = 1'b1; i_switch_1 = 1'b1;
#10 $finish;
end
endmodule
--------------
만든 반가산기를 이용해 전가산기를 만들 수 있다.
A | B | C | Sum | Carry |
0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 1 | 0 |
0 | 1 | 0 | 1 | 0 |
1 | 1 | 0 | 0 | 1 |
0 | 0 | 1 | 1 | 0 |
1 | 0 | 1 | 0 | 1 |
0 | 1 | 1 | 0 | 1 |
1 | 1 | 1 | 1 | 1 |
//full_adder.v
module full_adder(
input i_a, i_b, i_c,
output o_sum, o_carry
);
wire w_sum0, w_carry0, w_carry1;
half_adder HA_0(
.i_a(i_a),
.i_b(i_b),
.o_sum(w_sum0),
.o_carry(w_carry0)
);
half_adder HA_1(
.i_a(w_sum0),
.i_b(i_c),
.o_sum(o_sum),
.o_carry(w_carry1)
);
assign o_carry = w_carry1 | w_carry0;
endmodule
//tb_full_adder.v
module tb_full_adder();
reg i_a, i_b, i_c;
wire o_sum, o_carry;
full_adder dut(
.i_a(i_a),
.i_b(i_b),
.i_c(i_c),
.o_sum(o_sum),
.o_carry(o_carry)
);
initial begin
#00 i_a = 1'b0; i_b = 1'b0; i_c = 1'b0;
#10 i_a = 1'b0; i_b = 1'b0; i_c = 1'b1;
#10 i_a = 1'b0; i_b = 1'b1; i_c = 1'b0;
#10 i_a = 1'b0; i_b = 1'b1; i_c = 1'b1;
#10 i_a = 1'b1; i_b = 1'b0; i_c = 1'b0;
#10 i_a = 1'b1; i_b = 1'b0; i_c = 1'b1;
#10 i_a = 1'b1; i_b = 1'b1; i_c = 1'b0;
#10 i_a = 1'b1; i_b = 1'b1; i_c = 1'b1;
#10 $finish;
end
endmodule
--------------
만든 full_adder를 4bit로 확장했다.
module four_bit_full_adder(
input [3:0] i_a, i_b, //i_a[3], i_a[2], i_a[1], i_a[0]
input i_cin,
output [3:0] o_sum,
output o_carry
);
wire w_carry_0, w_carry_1, w_carry_2;
full_adder FA0(
.i_a(i_a[0]),
.i_b(i_b[0]),
.i_c(i_cin),
.o_sum(o_sum[0]),
.o_carry(w_carry_0)
);
full_adder FA1(
.i_a(i_a[1]),
.i_b(i_b[1]),
.i_c(w_carry_0),
.o_sum(o_sum[1]),
.o_carry(w_carry_1)
);
full_adder FA2(
.i_a(i_a[2]),
.i_b(i_b[2]),
.i_c(w_carry_1),
.o_sum(o_sum[2]),
.o_carry(w_carry_2)
);
full_adder FA3(
.i_a(i_a[3]),
.i_b(i_b[3]),
.i_c(w_carry_2),
.o_sum(o_sum[3]),
.o_carry(o_carry)
);
endmodule
module tb_four_bit_full_adder();
reg [3:0] i_a, i_b;
reg i_cin;
wire [3:0] o_sum;
wire o_carry;
four_bit_full_adder dut(
.i_a(i_a),
.i_b(i_b),
.i_cin(1'b0),
.o_sum(o_sum),
.o_carry(o_carry)
);
initial begin
#00 i_a = 4'b0000; i_b = 4'b0000;
#10 i_a = 4'd3; i_b = 4'd4;
#10 i_a = 4'ha; i_b = 4'hb;
#10 i_a = 4'd6; i_b = 4'd11;
#10 i_a = 4'd3; i_b = 4'd10;
#10 i_a = 4'd3; i_b = 4'd9;
#10 i_a = 4'd3; i_b = 4'd8;
#10 i_a = 4'd3; i_b = 4'd7;
#10 i_a = 4'd3; i_b = 4'd6;
#10 i_a = 4'd3; i_b = 4'd16;
#10 $finish;
end
endmodule
RTL Analysis에서 schematic을 보면 아래와 같이 볼 수 있다.
아래 결과를 보면 4bit라서 15 이후로 다시 0으로 셈. (16이 0인 이유)
carry가 1이면 16으로 계산함(4bit라서). 따라서 a + b = 10 + 11 = 21 = 5 + 16 . sum 5, carry 1로 결과가 나왔다.
4bit 넘어가는 경우를 1로 두는 걸 보니까 왜 컴퓨터 입장에서 overflow를 가리킨다는 건지 이해가 된다.
## 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 { 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 { sw[13] }]; #IO_L3N_T0_DQS_34 ,Sch=SW13
#set_property -dict { PACKAGE_PIN T1 IOSTANDARD LVCMOS33 } [get_ports { sw[14] }]; #IO_L3P_T0_DQS_34 ,Sch=SW14
#set_property -dict { PACKAGE_PIN R2 IOSTANDARD LVCMOS33 } [get_ports { sw[15] }]; #IO_L1P_T0_34 ,Sch=SW15
## LEDs
set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { o_sum[0] }]; #IO_L23N_T3_A02_D18_14 ,Sch=LED0
set_property -dict { PACKAGE_PIN E19 IOSTANDARD LVCMOS33 } [get_ports { o_sum[1] }]; #IO_L3N_T0_DQS_EMCCLK_14 ,Sch=LED1
set_property -dict { PACKAGE_PIN U19 IOSTANDARD LVCMOS33 } [get_ports { o_sum[2] }]; #IO_L15P_T2_DQS_RDWR_B_14 ,Sch=LED2
set_property -dict { PACKAGE_PIN V19 IOSTANDARD LVCMOS33 } [get_ports { o_sum[3] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 ,Sch=LED3
set_property -dict { PACKAGE_PIN W18 IOSTANDARD LVCMOS33 } [get_ports { o_carry }]; #IO_L16P_T2_CSI_B_14 ,Sch=LED4
#set_property -dict { PACKAGE_PIN U15 IOSTANDARD LVCMOS33 } [get_ports { led[5] }]; #IO_L23P_T3_A03_D19_14 ,Sch=LED5
#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { led[6] }]; #IO_25_14 ,Sch=LED6
#set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { led[7] }]; #IO_L24N_T3_A00_D16_14 ,Sch=LED7
#set_property -dict { PACKAGE_PIN V13 IOSTANDARD LVCMOS33 } [get_ports { led[8] }]; #IO_L24P_T3_A01_D17_14 ,Sch=LED8
#set_property -dict { PACKAGE_PIN V3 IOSTANDARD LVCMOS33 } [get_ports { led[9] }]; #IO_L6P_T0_34 ,Sch=LED9
#set_property -dict { PACKAGE_PIN W3 IOSTANDARD LVCMOS33 } [get_ports { led[10] }]; #IO_L6N_T0_VREF_34 ,Sch=LED10
#set_property -dict { PACKAGE_PIN U3 IOSTANDARD LVCMOS33 } [get_ports { led[11] }]; #IO_L9P_T1_DQS_34 ,Sch=LED11
#set_property -dict { PACKAGE_PIN P3 IOSTANDARD LVCMOS33 } [get_ports { led[12] }]; #IO_L12N_T1_MRCC_35 ,Sch=LED12
#set_property -dict { PACKAGE_PIN N3 IOSTANDARD LVCMOS33 } [get_ports { led[13] }]; #IO_L12P_T1_MRCC_35 ,Sch=LED13
#set_property -dict { PACKAGE_PIN P1 IOSTANDARD LVCMOS33 } [get_ports { led[14] }]; #IO_L19N_T3_VREF_35 ,Sch=LED14
#set_property -dict { PACKAGE_PIN L1 IOSTANDARD LVCMOS33 } [get_ports { led[15] }]; #IO_L6N_T0_VREF_35 ,Sch=LED15
이후 bitstream을 만들었다.
-----------
1의 보수, 2의 보수. 뺄셈의 방식은 알고 있었는데 용어를 몰랐다.
1의 보수와 2의 보수를 이해하자!
● 정수 표현 컴퓨터는 N개의 비트를 이용해 2^N개의 정수만 표현할 수 있습니다. 이러한 방식을 이용해서 수를 표현해야 하기 때문에 쉽지 않습니다. 또한 정수는 음의 정수와 양의 정수로 나누
ndb796.tistory.com
반복연산자
assign w_b_xor = {4{i_mode}} ^ i_b; //if i_mode == 1, then 1111; if i_mode == 0, then 0000;
mode에 따라 가산기, 감산기 전환
B에 대해 exclusive or 연산을 추가하면서 진리표가 조금 달라진다.
A | B | C | Sum | Carry |
0 | 0 | 0 | 1 | 0 |
1 | 0 | 0 | 0 | 1 |
0 | 1 | 0 | 0 | 0 |
1 | 1 | 0 | 1 | 0 |
0 | 0 | 1 | 0 | 1 |
1 | 0 | 1 | 1 | 1 |
0 | 1 | 1 | 1 | 0 |
1 | 1 | 1 | 0 | 1 |
module four_bit_full_sub(
input [3:0] i_a, i_b,
input i_mode,
output [3:0] o_sum,
output o_carry
);
wire [3:0] w_b_xor;
assign w_b_xor = {4{i_mode}} ^ i_b; //if i_mode == 1, then 1111; if i_mode == 0, then 0000;
four_bit_full_adder adder_sub(
.i_a(i_a),
.i_b(w_b_xor),
.i_cin(i_mode),
.o_sum(o_sum),
.o_carry(o_carry)
);
endmodule
module tb_four_bit_full_sub();
reg [3:0] i_a, i_b;
reg i_mode;
wire [3:0] o_sum;
wire o_carry;
four_bit_full_sub dut(
.i_a(i_a),
.i_b(i_b),
.i_mode(i_mode),
.o_sum(o_sum),
.o_carry(o_carry)
);
initial begin
#00 i_a = 4'b0000; i_b = 4'b0000; i_mode = 0;
#10 i_a = 4'd3; i_b = 4'd4; i_mode = 0;
#10 i_a = 4'ha; i_b = 4'hb; i_mode = 0;
#10 i_a = 4'd6; i_b = 4'd11; i_mode = 0;
#10 i_a = 4'd3; i_b = 4'd10; i_mode = 0;
#10 i_a = 4'd3; i_b = 4'd9; i_mode = 0;
#10 i_a = 4'd3; i_b = 4'd8; i_mode = 0;
#10 i_a = 4'd3; i_b = 4'd7; i_mode = 0;
#10 i_a = 4'd7; i_b = 4'd6; i_mode = 0;
#10 i_a = 4'd7; i_b = 4'd6; i_mode = 1;
#10 i_a = 4'd3; i_b = 4'd16; i_mode = 0;
#10 i_a = 4'd3; i_b = 4'd16; i_mode = 1;
#10 $finish;
end
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_mode }]; #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 { sw[13] }]; #IO_L3N_T0_DQS_34 ,Sch=SW13
#set_property -dict { PACKAGE_PIN T1 IOSTANDARD LVCMOS33 } [get_ports { sw[14] }]; #IO_L3P_T0_DQS_34 ,Sch=SW14
#set_property -dict { PACKAGE_PIN R2 IOSTANDARD LVCMOS33 } [get_ports { sw[15] }]; #IO_L1P_T0_34 ,Sch=SW15
## LEDs
set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { o_sum[0] }]; #IO_L23N_T3_A02_D18_14 ,Sch=LED0
set_property -dict { PACKAGE_PIN E19 IOSTANDARD LVCMOS33 } [get_ports { o_sum[1] }]; #IO_L3N_T0_DQS_EMCCLK_14 ,Sch=LED1
set_property -dict { PACKAGE_PIN U19 IOSTANDARD LVCMOS33 } [get_ports { o_sum[2] }]; #IO_L15P_T2_DQS_RDWR_B_14 ,Sch=LED2
set_property -dict { PACKAGE_PIN V19 IOSTANDARD LVCMOS33 } [get_ports { o_sum[3] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 ,Sch=LED3
set_property -dict { PACKAGE_PIN W18 IOSTANDARD LVCMOS33 } [get_ports { o_carry }]; #IO_L16P_T2_CSI_B_14 ,Sch=LED4
#set_property -dict { PACKAGE_PIN U15 IOSTANDARD LVCMOS33 } [get_ports { led[5] }]; #IO_L23P_T3_A03_D19_14 ,Sch=LED5
#set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { led[6] }]; #IO_25_14 ,Sch=LED6
#set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { led[7] }]; #IO_L24N_T3_A00_D16_14 ,Sch=LED7
#set_property -dict { PACKAGE_PIN V13 IOSTANDARD LVCMOS33 } [get_ports { led[8] }]; #IO_L24P_T3_A01_D17_14 ,Sch=LED8
#set_property -dict { PACKAGE_PIN V3 IOSTANDARD LVCMOS33 } [get_ports { led[9] }]; #IO_L6P_T0_34 ,Sch=LED9
#set_property -dict { PACKAGE_PIN W3 IOSTANDARD LVCMOS33 } [get_ports { led[10] }]; #IO_L6N_T0_VREF_34 ,Sch=LED10
#set_property -dict { PACKAGE_PIN U3 IOSTANDARD LVCMOS33 } [get_ports { led[11] }]; #IO_L9P_T1_DQS_34 ,Sch=LED11
#set_property -dict { PACKAGE_PIN P3 IOSTANDARD LVCMOS33 } [get_ports { led[12] }]; #IO_L12N_T1_MRCC_35 ,Sch=LED12
#set_property -dict { PACKAGE_PIN N3 IOSTANDARD LVCMOS33 } [get_ports { led[13] }]; #IO_L12P_T1_MRCC_35 ,Sch=LED13
#set_property -dict { PACKAGE_PIN P1 IOSTANDARD LVCMOS33 } [get_ports { led[14] }]; #IO_L19N_T3_VREF_35 ,Sch=LED14
#set_property -dict { PACKAGE_PIN L1 IOSTANDARD LVCMOS33 } [get_ports { led[15] }]; #IO_L6N_T0_VREF_35 ,Sch=LED15
Program device을 진행했을 때 i_mode에 해당하는 MSB에 매칭되는 것이 아니기 때문에 연산은 1로 된다. 따라서 adder(가산기)의 경우 0부터 30까지 나타난다. i_a[3] 및 i_b[3]는 8, i_a[2] 및 i_b[2]는 4, i_a[1] 및 i_b[1]는 2 그리고 i_a[0] 및 i_b[0]는 1로 계산된다.
그러나 subtractor(감산기)의 경우는 달라서 i_mode 스위치를 켜면 5번째 LED가 켜지면서 subtractor로 작동하게 된다.
contraints(MY_Basys-3-Master.xdc)의 경우 맨 위에 input, output과 일치시키면 된다. 이 경우 four_bit_full_sub.v에서 input, output을 일치시켰으면 하위 단인 four_bit_full_adder.v나 full_adder.v, half_adder.v와 이름을 일치시킬 필요가 없다는 거다. 물론 논리적 맥락에 맞게 적절히 대입하는 것은 필요하다.
--------
검색하고 보니 논리식? 이라는 개념이 나오는데 거기서 쓰이는 연산기호?? 같은 게 무슨 뜻인지 이해가 되지 않는다. 카르노맵이라는 단어도 나왔는데 뭔지 찾아봐야할 거 같다.