Last update: 25-04-12
module top_module(
input a,
input b,
output wire out_assign,
output reg out_alwaysblock
);
assign out_assign = a & b;
always @(*)
out_alwaysblock = a & b;
endmodule
always @(*) 구문을 보여주는 예제이다.
- Combinational: always @(*)
- Clocked: always @(posedge clk)
Combinational always 블록은 assign 구문과 동일한, 조합논리를 표현하는 방법이다. 둘 중 편한 걸 사용하면 되지만, if-then, case 등의 블록 안에서는 assign을 사용할 수 없다.
module top_module(
input clk,
input a,
input b,
output wire out_assign,
output reg out_always_comb,
output reg out_always_ff );
assign out_assign = a ^ b;
always @(*) out_always_comb = a ^ b;
always @(posedge clk) out_always_ff <= a ^ b;
endmodule
세 가지 assignment 방식에 대해 알려주는 문제이다.
- Continuous assignments (assign x = y;). Can only be used when not inside a procedure ("always block").
- Procedural blocking assignment: (x = y;). Can only be used inside a procedure.
- Procedural non-blocking assignment: (x <= y;). Can only be used inside a procedure.
procedure는 always, initial, task, function 블록을 말한다. 이런 프로시저 안에서는 블로킹/논블로킹 assignment를 사용해야 하고, 밖에서는 assign 구문을 사용해야 한다.
Combinational의 경우 blocking assignment를 사용하고, Clocked의 경우 non-blocking assignment를 사용한다. 그렇게 하는 편이 비결정적인 동작이나 합성 과정에서 발생하는 오류를 줄이고 해결하기 쉽게 해 준다고 한다.
module top_module(
input a,
input b,
input sel_b1,
input sel_b2,
output wire out_assign,
output reg out_always );
assign out_assign = sel_b1 & sel_b2 ? b : a;
always @(*) begin
if (sel_b1 & sel_b2) out_always = b;
else out_always = a;
end
endmodule
? : 구문 대신 if ~ else를 사용하는 문제이다. if문을 사용할 때 주의할 점으로, 모든 경우에 대해 out에 assign해주지 않으면 조합논리로 생성되지 않는다!!! 반드시 모든 케이스를 커버해야 한다.
module top_module (
input cpu_overheated,
output reg shut_off_computer,
input arrived,
input gas_tank_empty,
output reg keep_driving ); //
always @(*) begin
if (cpu_overheated)
shut_off_computer = 1;
else shut_off_computer = 0;
end
always @(*) begin
if (~arrived)
keep_driving = ~gas_tank_empty;
else keep_driving = 0;
end
endmodule
위에서 말한 모든 경우를 커버하지 않으면 조합논리가 생성되지 않는다를 체험시켜주는 문제이다. 난 다른 이유로 틀렸는데, 문제를 제대로 안 읽고 마지막에 else keep_driving = gas_tank_empty;로 써서 틀렸다.
module top_module (
input [2:0] sel,
input [3:0] data0,
input [3:0] data1,
input [3:0] data2,
input [3:0] data3,
input [3:0] data4,
input [3:0] data5,
output reg [3:0] out );//
always@(*) begin // This is a combinational circuit
case(sel)
3'b000: out = data0;
3'b001: out = data1;
3'b010: out = data2;
3'b011: out = data3;
3'b100: out = data4;
3'b101: out = data5;
default: out = 0;
endcase
end
endmodule
C언어의 switch 구문과 비슷해서 헷갈렸는데, 얘는 case로 시작하며 case item들을 바로 숫자로 나타낸다. begin을 사용하지 않으며 endcase로 끝을 낸다. break가 없지만 하나의 case item만 실행된다.
각 case item별 실행 구문은 1문장이 기본으로, 여러 문장을 쓰려면 begin ~ and를 사용한다.
똑같은 case item을 여러 개 쓰거나 중첩되는 경우가 있을 경우, 가장 먼저 선언된 구문만 실행된다.
위의 래치 문제와 마찬가지로 모든 경우를 커버하지 않을 경우 래치가 발생할 수 있다. 아마도
module top_module (
input [3:0] in,
output reg [1:0] pos );
always @(*) begin
// casex (in)
// 4'bxxx1: pos = 0;
// 4'bxx1x: pos = 1;
// 4'bx1xx: pos = 2;
// 4'b1xxx: pos = 3;
// default: pos = 0;
// endcase
case(in)
4'b0000: pos = 0;
4'b0001: pos = 0;
4'b0010: pos = 1;
4'b0011: pos = 0;
4'b0100: pos = 2;
4'b0101: pos = 0;
4'b0110: pos = 1;
4'b0111: pos = 0;
4'b1000: pos = 3;
4'b1001: pos = 0;
4'b1010: pos = 1;
4'b1011: pos = 0;
4'b1100: pos = 2;
4'b1101: pos = 0;
4'b1110: pos = 1;
4'b1111: pos = 0;
endcase
end
endmodule
x, z의 사용을 수업시간에 이미 들은 탓에 진도를 너무 빨리 나갔다.
module top_module (
input [7:0] in,
output reg [2:0] pos );
always @(*) begin
casez (in)
8'bzzzzzzz1: pos = 0;
8'bzzzzzz1z: pos = 1;
8'bzzzzz1zz: pos = 2;
8'bzzzz1zzz: pos = 3;
8'bzzz1zzzz: pos = 4;
8'bzz1zzzzz: pos = 5;
8'bz1zzzzzz: pos = 6;
8'b1zzzzzzz: pos = 7;
default: pos = 0;
endcase
end
endmodule
casez 구문에서 z는 don't-care로 처리된다. 같은 의미로 ?을 사용할 수도 있다.
casex 구문의 경우 x와 z를 모두 don't-care로 처리하는데, 이 구문 자체가 잘 안 쓰인다고 한다.
한편 일반 case 구문에서도 x, z를 사용할 수 있는데, 출력에 high-z를 주는 경우 등에 사용하는 듯 하다.
module top_module (
input [15:0] scancode,
output reg left,
output reg down,
output reg right,
output reg up );
always @(*) begin
up = 0; down = 0; right = 0; left = 0;
case (scancode)
16'he06b: left = 1;
16'he072: down = 1;
16'he074: right = 1;
16'he075: up = 1;
endcase
end
endmodule
단순히 default를 집어넣는 것만으로는 래치의 발생을 막을 수 없다는 걸 설명해주는 문제다. case문 안에서 건드리는 left, down, right, up이 모든 경우에서 각자 assign이 되어야 한다. 다만 각 경우에 대해 네 개를 모두 assign하는 것은 귀찮으므로, case문 이전에 default value를 설정해 래치를 더 간단히 방지할 수 있다. 이렇게 하면 default case item도 필요가 없다!!