Ch.5 행위 수준 모델링
조합회로 모델링
- Level Trigger
- 회로의 입력 신호 모두 나열
@(*)
함축적 감지 신호 사용 가능 ← 모든 입력 감시
module or2 (input a, input b, output out);
reg out;
always @(a or b) begin // always @(a, b)
if (a == l'bl II b == l'bl) out = l'bl;
else out = l'b0;
end
endmodule
순차회로 모델링
- Edge Trigger
- 동기식(synchronous) : 클록 신호만 포함
- 비동기식(asynchronous) : 클록 신호, set, reset 신호 포함
- 신호의 안정성 면에서는 동기식이 더 좋다고 할 수 있음(비동기식 : 클럭 신호와 set 신호가 완전히 겹칠경우 → metastable)
- 하지만 동기식에서 클럭에 오류가 발생할 경우 리셋 동작이 작동 안할 수 있음
module dff (input elk, input din, output qout); // D-ff modeling
reg qout;
always @(posedge elk)
qout <= din;
endmodule
<동기식>
always @(posedge clk)
if(reset)
...
----------------------------------------
<비동기식>
always @(posedge clk, negedge reset)
if(reset)
...
initial 구문
- 시뮬레이션이 진행되는 동안 한 번만 실행
- 논리합성이 지원되지 않으므로 시뮬레이션을 위한 테스트벤치에 사용
- begin - end 블록은 절차형 문장들로 구성되며, 나열된 순서가 결과에 영향
module periodic_sigjgen;
reg a, b;
initial begin
a = l'bl;
b = l'b0;
end
always
#50 a = ~a;
always
#100 b = ~b;
endmodule
blocking 할당문
- 순차적으로 실행 (
=
사용) → 조합회로에서 많이 사용
reg_lvalue = [delay_or_event_control] expression;
initial begin
rega = 0; // reg형 변수에 대한 할당
regb[3] = 1; // 단일 비트에 대한 할당
r egc[3:5] = 7; // 부분 비트에 대한 할당
mema [address] = 8'hff; // 메모리 요소에 대한 할당
{carry, acc) = rega + regb; // 결합에 대한 할당
end
nonblocking 할당문
- 동시 실행(
<=
사용) → 순차회로에서 많이 사용
reg_lvalue <= [delay_or_event_control] expression;
(b) nonblocking에서는 a와 b의 값이 계속 바뀌지만
(a) blocking 할당문에서는 a와 b의 값이 바뀌지 않음
module blk_nonblk_delay;
reg blk_a, blk」blk_c, nblk_a, nblk_b, nblk_c;
initial begin // blocking assignments
blk_a = #15 l'bl; // blk_a will be assigned 1 at time 15
blk_b = #5 l'b0; // blk_b will be assigned 0 at time 20
blk_c = #10 l'bl; // blk_c will be assigned 1 at time 30
#50 $finish;
end
initial begin // non-blocking assignments
nblk_a <= #15 l'bl; // nblk_a will be assigned 1 at time 15
nblk_b <= #5 l'b0; // nblk_b will be assigned 0 at time 5
nblk_c <= #10 1'bl; // nblk_c will be assigned 1 at time 10
#50 5finish;
end
endmodule
if 조건문
module dff_async_sr(input elk, input d, input rb, input sb,
output q, output qb);
reg q;
always @(posedge elk or negedge rb or negedge sb) begin
if(rb == 0)
q <= 0;
else if (sb == 0)
q <= 1;
else
q <= d;
end
assign qb = ~q;
endmodule
→ assing qb는 q의 값이 바뀌어야 바뀜
case 문
case(expression)
casejtem case_item) : statement_or_nuU;
| default [:] statement_or_null;
endcase
- casejtem들에 대한 비교에서 일치되는 항이 없고 default 항이 있으면 default 항이 실행되고, default 항이 없으면 변수는 이전에 할당받은 값을 유지한다.
- 각 비트가 0, 1, X, Z 포함하여 정확히 같은 경우에만 일치되는 것으로 판단
casez & casex
- casez : Z(high-impedence)를 don't - care로 취급하여 해당 비트를 비교에서 제외
- casex : X(unknown)와 Z를 don't - care로 취급하여 해당 비트를 비교에서 제외
reg [7:0] ir;
casez(ir)
8'bl???_????: instructionl(ir);
8'b01??_????: instruction2(ir);
8'b0001_0???: instruction3(ir);
8'b0000_01??: instruction4(ir);
endcase
8'bl???_????: instructionl(ir)
: Z만 포함
reg [1:0] enc;
always ©(encode) begin
casex(encode)
4'blxxx : enc = 2'bll;
4'b01xx : enc = 2'bl0;
4'b001x : enc = 2'b01;
4'b0001 : enc = 2'b00;
endcase
end
4'blxxx : enc = 2'bll
: X, Z 포함
반복문
forever statement;
| repeat(expression) statement;
| while(expression) statement;
| for(variable_assign; expression; variable_assign) statement;
- forever 문 : 조건 없이 무한히 반복 실행된다,
- repeat 문 : 지정된 횟수만큼 반복 실행된다. 반복 횟수를 나타내는 수식이 x(unknown) 또는 z(high-impedance)로 평가되면 반복 횟수는 이 되어 실행되지 않는다.
- while 문: 조건이 참(tr니e)인 동안 반복 실행된다. 조건식의 초기 값이 거짓이면 실행되지 않는다.
- for 문 : 반복을 제어하는 변수의 초기 값에서부터 조건이 참(true)인 동안 반복 실행되며, 매 반복마다 반복 제어 변
수를 갱신한다. 반복 제어 변수는 integer로 선언되어야 한다.
타이밍 제어
named event
- system Verilog에서 검증시 사용
- event로 선언된 named event는 절차형 할당문의 실행을 제어하기 위해 사용된다.
- named event : 데이터 값을 유지하지 않으며, 다음과 같은 특성을 갖는다.
- 임의의 특정한 시간에 발생될 수 있으며, 지속 시간을 갖지 않는다
- 이벤트 제어 구문을 이용해서 이벤트의 발생을 감지할 수 있다.
- event 자료형 선언
event list_of_event_names;
- 이벤트 트리거
-> event_name;
- 사용 예시
module dff_event (input clock, input reset, input din, output qout);
reg qout;
event upedge; // 이벤트 선언
always @(posedge clock) // 이벤트 트리거
-> upedge;
always @(upedge or negedge reset) begin
if(reset == 0) qout = 0;
else qout = din;
end
endmodule
intra-assignment 타이밍 제어
- repeat 문
q = repeat(3) @(posedge elk) b;
→ 3클럭 이후에 q = b 하겠다.
블록문
fork-join (← 중요)
- 회로 합성 지원 X
- symtem Verilog에서 많이 사용
fork [ : block_name
{ block_item_declaration } ] { statement }
join
... 다음 코드
- 블록 내의 문장들은 나열된 순서에 무관하게 동시에 실행된다.
: block-name
형식의 블록이름을 붙일 수 있으며, 해당 블록에 대한 지역변수, parameter 그리고 named event 를 선언할수 있다.- 블록 내부에서 사용되는 reg, real, integer, realtime, time, event, local parameter, parameter 등을 선언할 수 있다.
join
: process가 모두 끝나면 다음 코드 실행join_any
: process 중 하나만 끝나도 다음 코드 실행join_none
: process가 모두 실행 후 process의 끝나는것과 상관없이 다음 코드 실행
Ch.6 구조적 모델링
모듈 포트 선언
module port_example (a, b, sel, c, result, sum, data_bus, addr);
input [15:0] a, b; // 2개의 16비트 입력 포트 선언
input sel; // 스칼라(1 비트) 입력 포트 선언
input signed [7:0] c; //8비트 입력 포트 선언. 포트로 입력되는 값은 2의 보수로 해석됨
----------------------------------------
module (
input [15:0] a, b;
input sel;
input signed [7:0] c;
);
위 2개는 같음
모듈 인스턴스
- 순서에 의한 포트 연결
module_name instance_name (signall, signal2, ...);
- 이름에 의한 포트 연결
module_name instance_name (
.port_namel(signall),
.port_name2(signal2),
...);
모듈 parameter
- 파라미터 선언을 갖는 모듈
module mod_param (a, b);
real rl, r2;
parameter [2:0] A = 3'h2; // 자료형과 범위가 지정된 parameter 선언
parameter B = 2; // 자료형과 범위가 지정되지 않은 parameter 선언
initial begin
rl = A;
r2 = B;
$display("rl is r2 is %f",rlJ,r2);
end
endmodule
- defparam을 이용한 파라미터 값 변경
module mod_defparam;
wire a, b;
def param U0.A = 3.1415;
def param U0.B = 3.1415;
mod_param U0 (a, b); // 모듈 인스턴스
endmodule
define & parameter
define | parameter | |
---|---|---|
범위 | 파일 전체에서 유효한 전역적인 범위 | 해당 모듈 내에서만 유효 |
타입 | 단순한 텍스트 치환으로 처리되므로, 값의 타입을 지정할 수 없음 | 데이터 타입을 사용하여 정의될 수 있음 |
재할당? | 한 번 정의되면 다시 할당할 수 없음 | 초기 값으로 정의되지만 나중에 다른 값으로 재할당할 수 있음 |
생성문
generate - endgenerate
블록 모델링 ← 많은 모듈 인스턴스를 만들어야 할 때genvar genvar_name { , genvar_name };
- : generate 블록 내에서만 사용되는 integer 변수
module gray2binl (output [SIZE-1:0] bin, input [SIZE-1 :0] gray);
parameter SIZE = 4;
genvar i;
generate
for(i=0; i<SIZE; i=i+l) begin :bit
assign bin[i] = ^gray[SIZE-1 :i];
end
endgenerate
endmodule
→ for문 안의 계산을 genvar(= i) 번 만들겠다!
계층
module wave;
reg stiml, stim2;
cct a (stiml, stim2); // instantiate cct
initial begin :wavel
#100 fork :innerwave
reg hold;
join
#150 begin
stiml = 0;
end
end
endmodule
module cct (input stiml, input stim2);
mod Amod (stiml), Bmod (stim2); // instantiate mod
endmodule
module mod (input in);
always ©(posedge in) begin :keep
reg hold;
hold = in;
end
endmodule
Ch.7 함수와 태스크
함수 & 태스크
- Verilog의 function, task는 HW 구조
- System Verilog의 function, task는 SW 구조
함수
→ return 값은 함수의 이름과 같아야한다.
태스크
module bit_counter (input [7:0] data_word, output [3:0] bit_count);
reg [3:0] bit_count;
always @(data_word)
count_ones(data_word, bit_count); // 태스크 호출
task count_ones; // 태스크 선언
input [7:0] reg_a; // 인수가 여러 개인 경우, 순서가 중요함.
output [3:0] count;
reg [3:0] co니nt;
reg [7:0] temp_reg;
begin
count=0;
temp_reg = reg_a;
while (te叩reg) begin
if (temp_reg[0]) count = count+ 1;
temp_reg = temp_reg » 1;
end
end
endtask
endmodule
→ 인수가 여러개면 순서 중요!
Ch.8 컴파일러 지시어
define
`define wordsize 32
reg [1:'wordsize] data;
'define first_half "start of string
$display('first_half end of string");
- 문자 ```로 시작,
;
붙이지 않음 - define된 매크로를 사용할 때 ``` 붙여야함
timescale
시간과 지연 값의 측정 단위와 정밀도 지정
'timescale time_unit base / time_precision base
- time_unit : 시뮬레이션 시간 지연 등에 적용될 지연 1 의 시간 크기를 나타내며, 1,10,100 등이 되어야 한다.
- base : 시간에 대한 단위이며, s, ms, 니s, ns, ps, fs 중 하나가 되어야 한다
- time_precision : 시간 단위에 대한 정밀도를 지정한다. time.unit 이상의 정밀도를 가져야 하며, time_unit보다 큰 단위를 time_precision의 단위로 지정할 수 없다.
'timescale 1 ns / 1 ps
'timescale 10 us / 100 ns
include
'include "filename"
- 모듈 밖, 안 모두 사용 가능
ifdef - else
module and_op (input a, input b, output c);
`ifdef behavioral
wire c = a & b; // behavioral이 define되어 있으면 실행
`else
and u0 (c, a, b); // define되어 있지 않으면 실행
`endif
endmodule
Ch.9 시스템 태스크와 시스템 함수
$write & $display
module disp_write ();
initial begin
$display("$display ends with a new line.");
$write("$write does not end with a new line ");
$write("like this. To start new line, use newline character \n");
$display("$display always starts on a new line.");
end
endmodule
------------------------------------------------
<실행 결과>
$display ends with a new line.
$write does not end with a new line like this. To start new line, use newline character
$display always starts on a new line.
→ $display : 줄 바꿈 자동 / $wire : 줄 바꿈 안됨
$monitor
initial begin
$monitor ($time, “clock = %b reset =幼,elk, rst);
end
→ clk, rst 값이 바뀔 때마다 실행
$fopen & $fclose
module file_fdisplay ();
integer fd, n, result;
initial begin
fd = $fopenC'sum.dat", "wn); // file open + write mode
if(fd == 0)
$display(HFile open ERROR !!");
result = 0;
for (n = 0; n <= 10; n = n+1) begin
result = result + n;
$fdisplay(fd? "n=%0d : Cumulative Sum = %0d", n, result);
end
$fclose(fd);
end
endmodule
---------------------------------------------
<실행 결과>
n=l : Cumulative Sum = 1
n=2 : Cumulative Sum = 3
n=3 : Cumulative Sum = 6
n=4 : Cumulative Sum = 10
n=5 : Cumulative Sum = 15
n=6 : Cumulative Sum = 21
n=7 : Cumulative Sum = 28
n=8 : Cumulative Sum = 36
n=9 : Cumulative S니m = 45
n=10 : Cumulative Sum = 55
$readmemh
reg [7:0] mem口256];
initial
$readmemh('mem.data",, mem); // 예-1
initial
$readmemh('mem.data'\ mem, 16); // 예-2
initial
$readmemh("mem.data", mem, 128, 1); // 예-3
- 예-1 : 파일 “mem.data”의 데이터를 읽어서 mem의 주소 1부터 순차적으로 로드한다.
- 예-2 : 파일 “mem.data”의 데이터를 읽어서 mem의 주소 16부터 시작하여 주소 256까지 순차적으로 로드한다.
- 예-3 : “mem.data”의 데이터를 읽어서 mem의 주소 128부터 시작하여 주소 1까지 역순으로 로드한다. 이 경우, 로드가 완료되면 파일에 담겨 있는 데이터가 정확하게 128개인지를 확인하는 과정을 거치며, 만약 128개가 되지 않는 경우에는 경고 메시지가 출력된다.
Ch.10 조합회로 모델링
조합회로
- MUX : case, if, 조건 연산자
- 인코더/디코더 : case(입출력 bit 다름), if, for문
- 비교기 : if
3NOR Gate 예시)
module nor3_redop (input [2:0] a, output out_nor3);
assign out_nor3 = ~|a; // == out_nor3 = ~(a[2] | a[1] | a[0]);
endmodule
~|
: 축약 NOR 연산자
4bit 2XOR Gate 예시)
module xor4b_bitop (input [3:0] a, input [3:0] b, output [3:0] xor4b);
assign xor4b = a^b; // == xor U0 [3:0] (xor4b, a, b);
// assign xor4b[0] = a[0] b[0];
// assign xor4b[l] = a[l] b[l];
// assign xor4b[2] = a[2] b[2];
// assign xor4b[3] = a[3] b[3];
endmodule
LUT(Look Up Table)
예시)
function [7:0] data」Linel;
input [3:0] address;
begin
case(address)
0 : data.linel = 8'b0010_0000;
1 : data_Unel = 8'b0100_0100;
2 : data_linel = 8'b0110_1001;
15 : data_linel = 8'b0010_0000;
default : data_linel = 8'b0000_0000;
endcase
end
endfunction
4 : 2 우선순위 인코더
module pri_enc_4to2_case (input [3:0] enc_in, output valid, output [1:0] enc_out);
reg valid;
reg [1:0] enc_out;
always @(enc_in) begin
valid = l'bl;
casex(enc_in)
4'blxxx : enc_out = 2'bll;
4'b01xx : enc_out = 2'bl0;
4'b001x : enc_out = 2'b01;
4'b0001 : enc_out = 2'b00;
default : begin
...
→ 입력의 MSB enc_in[3]이 4개의 case 항목들 중 가장 높은 우선순위로 사용되고 있다.
→ 1xxx : 1000 ~ 1111
3상태 버스
module bus_driver_conop (
input [7:0] data_A,
input enA,
input [7:0] data_Bj,
input enB,
output [7:0] bus_data);
assign bus_data = enA ? data_A :
enB ? data_B : 8'hzz;
//bufifl bfl [7:0] (bus_data, data_A, enA);
//bufifl bf2 [7:0] (bus_data, data_B, enB);
//->같은 회로
endmodule
원치 않는 Latch 합성
if문 ← else 생략
코드(1) - latch 합성
module if_latch (input [1:0] sei, input [7:0] ini, input [7:0] in2,
output [7:0] out);
reg [7:0] out;
always @(sel, ini, in2) begin
if (sei == 2'b01) out = ini;
else if (sei == 2'bl0) out = in2;
end
endmodule
-----------------------------------------------------------------------------
코드(2) - latch 미합성
module if_latch (input [1:0] sel, input [7:0] ini, input [7:0] in2,
output [7:0] out);
reg [7:0] out;
always @(sel, ini, in2) begin
if (sel == 2'b01) out = in1;
else if (sel == 2'b10) out = in2;
else out = in1;
end
endmodule
- else 생략시 Latch 합성 ← 조건에 해당하지 않는 상태를 저장할 Latch
- 해결 : else 포함 or 초기화
case문
코드(1) - Latch 합성
module case_no_latch (input [1:0] sei, input [7:0] ini,
input [7:0] in2, output reg [7:0] out);
always @(sel, ini, in2) begin
case(sel)
2'b01 : out = ini;
2'b10 : out = in2;
endcase
endmodule
-------------------------------------------------------------------------------
코드(2) - Latch 미합성
module case_no_latch (input [1:0] sei, input [7:0] ini,
input [7:0] in2, output reg [7:0] out);
always @(sel, ini, in2) begin
out = 8'b0; // 초기화
case(sel)
2'b01 : out = ini;
2'b10 : out = in2;
//default : out = 8'hxx; // 초기화 부분 없으면 default로 해도 똑같이 작동함
endcase
endmodule
(1) : 코드(1) RTL schematic / (2) : 코드(2) RTL schematic
- case 항목들이 완전하게 나열되지 않고 default도 포함되지 않은 경우 Latch 합성
- 해결 : 항목 모두 나열 or default 포함 or 초기화
Ch.11 순차회로 모델링
D-Latch
- 클럭의 레벨(High, Low)에 따라 출력 업데이트
비동기식 active-high 리셋을 갖는 positive D 래치의 모델링
module dlatch_pos_AHrst (input clock, input rst, input din, output qout);
reg qout;
always @(clock or rst or din) begin
if(rst)
qout = l'b0;
else if(clock)
qout = din;
end
endmodule
- Blocking 할당문 사용
D-FlipFlop
상승에지 트리거 D 플립플롭 모델링
module dff_pos (input clk, input din, output qout);
reg qout;
always @(posedge clk)
qout <= din;
endmodule
- nonBlocking 할당문 사용
- 클럭 rising edge에서만 qout = cin
동기 & 비동기식 reset
<동기식>
module dff_sync_ALrst (input elk, input din, i叩ut rstn, output qout);
reg qout;
always @(posedge elk) begin
if(!rstn) qout <= l'b0; // active-low reset
else qout <= din;
end
endmodule
---------------------------------------------------------------------
<비동기식>
module dff_async_ALrst (input elk, input din, input rst_n, output qout);
reg qout;
always ©(posedge elk or negedge rst_n) begin // include both elk and rst.n
if (!rst_n) // active-low reset
qout <= l'b0;
else
qout <= din;
end
endmodule
Blocking & nonBlocking
always @(posedge elk) begin
q0 = din;
ql = q0;
q2 = ql;
q3 = q2;
end
위 nonblocking 값 할당 순서가 달라질 경우 출력값도 달라지게 됨.
코딩 가이드 라인
1. 플립플롭 또는 래치를 모델링하는 always 블록에서는 nonblocking 할당문을 사용
a. edge 있으면 nonblocking 사용할 것
2. 조합회로를 모델링하는 always 블록에서는 blocking 할당문을 사용
3. 동일한 always 블록에서 순차회로와 조합회로를 함께 모델링하는 경우에는 nonblocking 할당문을 사용
4. 동일한 always 블록 내에서 blocking 할당문과 nonbkxking 할당문을 혼합해서 사용 X
5. 다수의 always 블록에서 동일한 reg 변수에 값을 할당 X
module Not_recommend_3 (input elk, input rstn, input dl, input d2, output qout); reg qout; always @(posedge elk or negedge rstn) if(!rstn) qout <= l'b0; else qout <= dl; always @(posedge elk or negedge rstn) if(!rstn) qout <= l'b0; else qout <= d2; endmodulemodule Not_recommend_3 (input elk, input rstn, input dl, input d2, output qout); reg qout; always @(posedge elk or negedge rstn) if(!rstn) qout <= l'b0; else qout <= dl; always @(posedge elk or negedge rstn) if(!rstn) qout <= l'b0; else qout <= d2; endmodule
→ 여러개의 always문은 동시 실행됨 → 같은 변수에 값 할당할 경우 race condition 발생
shift Register
- 직렬입력 - 직렬출력(SISO)
- 직렬입력 - 병렬출력(SIPO)
- 병렬입력 - 직렬출력(PISO)
- 시리얼 통신, 센서 등
- 병렬입력 - 병렬출력(PIPO)
- 일반적인 register
직렬입력 -직렬출력 8비트 시프트 레지스터 모델링
module shift_reg_nblk2 (input clk, input rst, input s_in, output s_out);
reg [7:0] q;
assign s_out = q[7];
always ©(posedge clk) begin
if(rst) q <= 8'h00;
else begin
q <= {s_in, q[7:1]};
//q[0] <= s_in;
//q[7:1] <= q[6:0];
end
end
endmodule
병렬입력-병렬출력 8비트 시프트 레지스터 모델링
module pload_shift_reg (input clk, input rstn, input load, input [7:0] din, output [7:0] pout);
reg [7:0] shift_reg;
assign pout = shift_reg;
always @(posedge clk) begin
if(lrstn) shift_reg <= 0;
else
if(load) shift_reg <= din;
else shift_reg <= shift_reg « 1;
end
endmodule
FSM(유한상태 머신)
- Moore 머신 : 출력이 현재상태에 의해 결정
- output에 현재 상태만 들어감
- Mealy 머신 : 현재상태와 입력에 의해 출력이 결정
- output에 현재 상태와 입력이 함께 들어감
Made By Minseok KIM
'VerilogHDL > 이론' 카테고리의 다른 글
[VerilogHDL] Verilog 이론 (Ch.1 ~ 4) (0) | 2024.05.20 |
---|
Let's Be Happy!
도움이 되었으면 좋겠어요 :)