MUX(multiplexer)는 select signal에 따라 여러 개의 signal을 input으로 받아, 하나의 signal을 출력하는 디지털 회로입니다. DEMUX(de-multiplexer)는 반대로 하나의 signal을 input으로 받아서 여러 개의 signal을 출력하는 디지털 회로입니다.
verilog를 이용해서 MUX와 DEMUX를 구현해보겠습니다.
우선 MUX를 구현할 건데, verilog로 MUX를 구현하는 방법은 7가지가 있습니다. 제가 배우는 강의자료에서는 7가지라고 합니다. 혹시 다른 방법이 있다면 알려주세요.
우선 2 to 1 MUX의 Truth tabel을 살펴보겠습니다.
i0 | i1 | sel | y |
0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 |
0 | 1 | 0 | 0 |
0 | 1 | 1 | 1 |
1 | 0 | 0 | 1 |
1 | 0 | 1 | 0 |
1 | 1 | 0 | 1 |
1 | 1 | 1 | 1 |
sel이 0이라면 i0이 output이 되고, sel이 1이라면 i1이 output이 됩니다.
boolean equation으로 나타내면 다음과 같습니다.
Y = I0•S' + I1•S
1. Primitive gate를 이용하는 방법
boolean equation을 그대로 gate로 구현하는 방법입니다.
2개의 and gate, 1개의 inverter 그리고 1개의 or gate를 이용해 구현하며 코드는 다음과 같습니다.
module MUX_2_to_1(input i0, i1, sel, output y);
wire a0, a1, sel_b;
not (sel_b, sel)
and u2 (a0, i0, sel_b);
and u3 (a1, i1, sel);
or u4 (y, a0, a1);
endmodule
이 module을 instantiation 해서 tb에서 사용할 수 있습니다.
2. inverter를 쓰지 않고, 1개의 and gate를 쓰는 방법
not gate를 쓰지 않고 MUX를 구현할 수 있습니다. inverter와 sel_b라는 wire를 쓰는 대신 sel에 ~를 붙여 inverter를 사용한 효과를 낼 수 있습니다. 또한 and gate를 불러올 때 ,를 써서 여러 개의 instacne를 선언할 수 있습니다.
코드는 다음과 같습니다.
module MUX_2_to_1(input i0, i1, sel, output y);
wire a0, a1;
// not gate를 쓰지 않고, sel_b를 지우고 ~sel으로 대체할 수 있다.
and u2 (a0, i0, ~sel), u3 (a1, i1, sel);
or u4 (y, a0, a1);
endmodule
3. assign statement를 사용하는 방법
여기서부터는 gate level design이 아닌 dataflow level design입니다. 좀 더 직관적으로 고급 언어와 비슷한 형태로 코드를 짤 수 있습니다. 코드는 다음과 같습니다.
module MUX_2_to_1(
input i0, i1, sel,
output y
);
assign y = i0 & (~sel) | i1 & sel;
endmodule
assign문을 써서 간단히 MUX를 구현할 수 있습니다.
4. 삼항 연산자를 쓰는 방법
삼항 연산자를 써서 직관적으로 MUX를 짤 수 있습니다. 코드는 다음과 같습니다.
module MUX_2_to_1(
input i0, i1, sel,
output reg y
);
assign y = (sel) ? i1 : i0;
endmodule
sel이 참이면 i1을 y에 assign 하고, 거짓이면 i0을 y에 assign 합니다.
5. if / else statement를 쓰는 방법
C언어와 동일한 조건문을 사용해 MUX를 짤 수 있습니다. 이때 if / else만 쓰면 simulation 할 때 한 번만 실행되므로 always문과 함께 작성해야 합니다. 그리고 always문을 쓴다면 output을 reg형으로 선언해야 하는데, 이에 대한 이유는 아직 모르겠습니다.
module MUX_2_to_1(
input i0, i1, sel,
output reg y
);
always @(*) begin
if (sel == 1)
assign y = i1;
else
assign y = i0;
end // 항상 실행을 시키겠다는 의미
endmodule
6. case statement를 쓰는 방법
case문을 사용해서도 짤 수도 있는데, C언어의 문법과 동일하게 사용할 수 있습니다. 이 경우에도 always문과 함께 작성해야 하며 output을 reg형으로 선언해야 합니다. 코드는 다음과 같습니다.
module MUX_2_to_1(
input i0, i1, sel,
output reg y
);
always @(*) begin
case(sel) // based on select signal assign y as i1 or i0
1'b1 : y = i1;
1'b0 : y = i0;
endcase
end
endmodule
이번에는 4bit 4 to 1 MUX를 짜 보겠습니다. 4개의 input이 4bit이므로 vector로 선언하고, output 또한 4bit reg형으로 선언합니다. 2 to 1 MUX 3개를 이용해 4 to 1 MUX를 설계할 수 있지만 편의상 case문으로 작성해보겠습니다.
output이 가질 수 있는 경우의 수가 4가지(2^2) 이므로 sel을 2bit로 선언해야 합니다.
module코드와 tb코드는 다음과 같습니다.
module MUX_4_to_1(
input [3:0] i0,
input [3:0] i1,
input [3:0] i2,
input [3:0] i3,
input [1:0] sel,
output reg [3:0] z0292
);
always @(*) begin
case(sel)
2'b00 : z0292 = i0;
2'b01 : z0292 = i1;
2'b10 : z0292 = i2;
2'b11 : z0292 = i3;
endcase
end
endmodule
module MUX_4_to_1_tb();
reg [3:0] i0, i1, i2, i3; // reg, wire의 경우 array로 선언할 수 있음.
reg [1:0] sel;
wire [3:0] o0292;
MUX_4_to_1 mx1 (i0, i1, i2, i3, sel, o0292);
initial begin
i0 = $random;
i1 = $random;
i2 = $random;
i3 = $random;
sel = 2'b00;
end
always
begin
#5 sel = 2'b00;
#5 sel = 2'b01;
#5 sel = 2'b10;
#5 sel = 2'b11;
end
endmodule
위 사진은 25ns까지의 simulation입니다. sel signal에 맞게 output이 잘 출력되는 것을 확인할 수 있습니다.
이번에는 4bit 1 to 4 DEMUX를 짜 보겠습니다. 1개의 input이 4bit vector로 선언되고, output은 4bit reg형으로 4개를 선언합니다. case문으로 작성하였습니다.
DEMUX 또한 output이 4가지 sel signal에 따라 출력되므로 sel을 2bit로 선언하였습니다.
코드는 다음과 같습니다.
module DEMUX_1_to_4(
input [3:0] in,
input [1:0] sel,
output reg [3:0] out0, out1, out2, out3 // always문을 쓰면 output reg로 선언해야한다.
);
always @(*) begin
case(sel)
2'b00 : begin
out0 = in;
out1 = 0;
out2 = 0;
out3 = 0;
end
2'b01 : begin
out0 = 0;
out1 = in;
out2 = 0;
out3 = 0;
end
2'b10 : begin
out0 = 0;
out1 = 0;
out2 = in;
out3 = 0;
end
2'b11 : begin
out0 = 0;
out1 = 0;
out2 = 0;
out3 = in;
end
endcase
end
endmodule
module DEMUX_1_to_4_tb(
);
reg [3:0] IN;
reg [1:0] SEL;
wire [3:0] OUT0;
wire [3:0] OUT1;
wire [3:0] OUT2;
wire [3:0] OUT3; // input, output을 array로 선언할 수 없다.
DEMUX_1_to_4 dmx1 (.in(IN), .sel(SEL),
.out0(OUT0), .out1(OUT1), .out2(OUT2), .out3(OUT3)); // call by name
initial begin
IN = $random;
SEL = 2'b00;
end
always
begin
#5 SEL = 2'b00;
#5 SEL = 2'b01;
#5 SEL = 2'b10;
#5 SEL = 2'b11;
end
endmodule
위 사진은 DEMUX의 25ns까지의 simulation입니다. sel signal에 맞게 output이 잘 출력되는 것을 확인할 수 있습니다.
'EE > Verilog HDL' 카테고리의 다른 글
[verilog HDL] Syntax 5. Behavioral/Algorithmic Level Design (0) | 2022.02.27 |
---|---|
[verilog HDL] 16-bit ALU(Arithmetic Logic Unit) (0) | 2022.02.23 |
[verilog HDL] Syntax 3. Port (0) | 2022.02.22 |
[verilog HDL] Syntax 2. Data types (0) | 2022.02.22 |
[verilog HDL] Syntax 1. module & instantiation (0) | 2022.02.15 |