Last update: 2025-04-12
module top_module ( input a, input b, output out );
mod_a inst(a,b,out);
endmodule
module top_module ( input a, input b, output out );
mod_a inst(.in1(a), .in2(b), .out(out));
endmodule
주어진 모듈 mod_a를 instantiation 하는 문제이다. 위 답안은 By position 연결이고, 아래 답안은 By name 연결이다. by name은 C++의 클래스 멤버 초기화 리스트하고 유사하다.
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a inst(out1, out2, a, b, c, d);
endmodule
위 문제와 별 차이 없다. by position 연결을 사용하라는 것 같다.
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a inst (.out1(out1), .out2(out2), .in1(a), .in2(b), .in3(c), .in4(d));
endmodule
마찬가지로 by name 연결을 사용하는 문제.
module top_module ( input clk, input d, output q );
wire w1, w2;
my_dff dff1(clk, d, w1);
my_dff dff2(clk, w1, w2);
my_dff dff3(clk, w2, q);
endmodule
3개의 D-FF를 적절히 연결하는 문제이다. 앞 단의 q와 뒷 단의 d를 연결할 wire를 미리 선언해주고, 적절히 연결하여 해결했다.
module top_module (
input clk,
input [7:0] d,
input [1:0] sel,
output [7:0] q
);
wire [7:0] w1, w2, w3;
my_dff8 dff1(clk, d, w1);
my_dff8 dff2(clk, w1, w2);
my_dff8 dff3(clk, w2, w3);
assign q = (sel & 2) ? ((sel & 1) ? w3 : w2) : ((sel & 1) ? w1 : d);
endmodule
8비트 단위의 D-FF를 연결하고, sel 신호를 통해 3개의 D-FF 중 어떤 것의 출력을 최종 출력으로 삼을지 결정한다. 벡터를 한 번에 모듈에 연결할 수 있음을 보여주는 문제같다.
사이트의 Solution에서는 always @(*) case(sel) ~ endcase 구문을 사용했는데, 나는 assign과 삼항 연산자를 조합하여 풀었다.
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire c;
add16 m1(a[15:0], b[15:0], 0, sum[15:0], c);
add16 m2(a[31:16], b[31:16], c, sum[31:16], );
endmodule
16비트 덧셈기 두 개를 연결해 32비트 덧셈기를 만드는 문제다. 중간에서 cout->cin을 이어줄 wire를 설정하는 것과, m2의 cout은 버리기 위해 쉼표만 찍고 생략하는 것 외에는 특이사항이 없다.
다만 저렇게 쉼표로 하면 뭔가 워닝 메세지가 뜨던데, 쉼표를 생략하니 잘 된다. By position에서도 맨 뒤의 포트를 무시할 때는 덜 적어도 무관한 듯 하다.
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire c;
add16 m1(a[15:0], b[15:0], 0, sum[15:0], c);
add16 m2(a[31:16], b[31:16], c, sum[31:16], );
endmodule
module add1 ( input a, input b, input cin, output sum, output cout );
assign {cout, sum} = a + b + cin;
endmodule
add16 모듈의 구현을 위해 내부에 들어가는 add1 모듈을 설계하고, 그 뒤로는 Adder 1 문제와 동일하다.
cout, sum에 대해 각각의 진리표를 그려서 a, b, cin의 적절한 논리 연산으로 표현할 수도 있지만, 나는 assign 구문과 { } 연산자를 사용하여 해결했다. 생각보다 베릴로그가 똑똑하다
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire c;
wire [15:0] suma, sumb;
add16 m1(a[15:0], b[15:0], 0, sum[15:0], c);
add16 m2a(a[31:16], b[31:16], 0, suma, );
add16 m2b(a[31:16], b[31:16], 1, sumb, );
assign sum[31:16] = c ? sumb : suma;
endmodule
기존의 ripple carry adder 구조는 carry가 뒷 단으로 전달되는 delay 때문에, 여러 단을 연결할 수록 연산 시간이 길어진다고 한다.
이를 해결하기 위해 cin이 1인 경우와 0인 경우 모두를 계산해 놓고, cout에 따라 MUX로 선택하여 출력하는 구조의 carry-select adder를 보여주고 있다.
구현은 어렵지 않게 세 개의 add16 모듈 인스턴스를 생성하고, assign ? : 구문을 통해 MUX를 생성했다.
module top_module(
input [31:0] a,
input [31:0] b,
input sub,
output [31:0] sum
);
wire c;
//wire [31:0] bs = b ^ { 32{sub} };
//add16 m1(a[15:0], bs[15:0], sub, sum[15:0], c);
//add16 m2(a[31:16], bs[31:16], c, sum[31:16], );
add16 m1(a[15:0], sub ? ~b[15:0] : b[15:0], sub, sum[15:0], c);
add16 m2(a[31:16], sub ? ~b[31:16] : b[31:16], c, sum[31:16], );
endmodule
2's complement를 활용해 뺄셈을 구현하는 회로이다. 처음엔 회로도에 XOR이 하나 떡하니 있어서 b와 sub를 XOR한 새 벡터 wire bs를 만들었는데, 생각해 보니 아래처럼 해도 괜찮을 것 같아서 바꿨다.
그런데 저렇게 식을 압축해서 쓰는 게 내 버릇인데, C에서도 자제해야 될 것 같다는 생각을 종종 하는데 논회설에서는 교수님이 직접 '베릴로그는 축약하기보다는 알아보기 쉽게 써야 한다'고 말씀하셨으니 주석처리한 방식으로 푸는 것도 좋을 것 같다.