https://electronic-hwan.tistory.com/category/Verilog
https://blog.naver.com/doksg/221701633438
베릴로그 HDL(Hardware Description Language)
반도체 및 전자 설계 산업에서 전자 시스템을 모델링 하기 위한 언어로 C언어와 유사한 문법을 가지고 있으나 순차성(Sequential)을 지닌 C언어와 달리 동시성(concurrent, 여러 작업을 두고 하나씩 처리)과 병렬성(parellel, 동시에 여러 작업을 처리)이라는 차이점도 존재한다.
설계 수준에 따라 동작적(Behavioral), 구조적(Structural), 데이터 흐름(Dataflow) 모델링 방식으로 나눌 수 있다. 각 모델링 방식은 추상화 수준과 회로의 기술 방법에 따라 차이가 있다
높은 추상화 수준은 시스템의 전체적인 기능을 강조하고, 낮은 추상화 수준은 시스템의 구체적인 세부 사항을 강조한다.
높은 추상화 수준
시스템의 기능과 동작을 중심으로 설명

if~else, case, while, for 등의 구문을 사용하며, 인간의 사고에 가장 근접한 표현 방식으로 동작을 구성할 수 있다. 우측의 진리표를 사용한 동작적 모델링을 사용하는 데 이를 매핑(Mapping)이라고도 하며 임의의 입력에 사용하기 좋다.
중간 추상화 수준
데이터가 회로 내에서 어떻게 이동하고 처리되는지를 설명
신호 간의 관계와 데이터의 흐름을 설명
수학적 및 논리적 연산을 통해 데이터 경로를 표현

연속할당문으로 불리기도 하며 연산자 등을 이용하여 ^, &, | 등의 연산자를 이용하여 데이터의 흐름을 표현하는 방식이다.
낮은 추상화 수준
회로의 구체적인 구성 요소와 그들 간의 연결을 설명
실제 하드웨어 배치와 구조를 구체적으로 묘사
작은 구성 요소를 결합하여 복잡한 시스템을 설계

내부 박스(모듈)을 만들어서 설계하며, 동일한 기능을 여러 곳에서 만들 때 인스턴스화하여 좀 더 간결하게 구현할 수 있다
Net 자료형은 하드웨어의 물리적 연결을 모델링한다. 신호가 서로 연결되어 전파되는 경로를 표현하는 데 사용됨. Net은 기본적으로 드라이버(소스)에서부터 연결되어 신호를 전파한다.
가장 일반적으로 사용되는 Net 자료형. wire는 기본적으로 다른 신호로부터의 값을 받아서 전달함.
연결된 신호 간의 상호작용을 표현할 때 사용된다.
Variable 자료형은 회로의 상태를 저장하고 조작하는 데 사용된다. 이 자료형들은 값을 저장하고 이후에 읽거나 수정할 수 있다.
레지스터 자료형. 값이 할당되면 그 값을 유지한다.
값을 저장하거나 유지할 때 사용된다. always 블록 내에서 주로 사용된다.
특정 필요에 따라 사용자가 정의할 수 있는 자료형.

모듈은 Verilog에서 디지털 회로를 구성하는 기본적인 단위. 모듈은 특정 기능을 수행하는 회로 블록을 정의하며, 복잡한 설계를 여러 개의 모듈로 나누어 구조화할 수 있다.
특정 기능을 수행하는 논리 블록을 정의합니다.
한번 정의된 모듈은 설계 내에서 여러 번 사용될 수 있습니다.
작은 모듈을 조합하여 더 큰 모듈을 설계할 수 있습니다.
모듈은 외부와 통신하기 위한 입력과 출력을 정의합니다.
module and_gate (
input A,
input B,
output Y
);
assign Y = A & B;
endmodule
인스턴스는 모듈의 구체적인 구현이다. 즉, 모듈은 회로의 설계를 정의하고, 인스턴스는 이 모듈의 실제 사용을 의미. Verilog에서는 모듈을 인스턴스화하여 설계의 일부로 사용할 수 있다.
모듈 정의를 실제 회로에서 사용하는 구체적인 형태.
동일한 모듈을 여러 번 인스턴스화하여 설계 내에서 여러 곳에서 사용할 수 있다.
인스턴스는 외부 신호와 포트를 연결하여 설계 내에서 데이터를 주고받는다.
인스턴스를 사용하여 계층적인 설계를 구축할 수 있다.
module top_module (
input A,
input B,
input C,
output Y1,
output Y2
);
// AND 게이트 인스턴스
and_gate and1 (
.A(A),
.B(B),
.Y(Y1)
);
// AND 게이트의 또 다른 인스턴스
and_gate and2 (
.A(B),
.B(C),
.Y(Y2)
);
endmodule
Positional Association은 포트를 연결할 때 포트 순서를 사용하여 연결한다. 즉, 모듈 인스턴스에 선언된 포트 순서대로 연결한다
Named Association은 포트를 연결할 때 포트 이름을 명시하여 연결한다. 이 방법은 포트의 순서와 관계 없이 명시된 포트 이름에 따라 포트를 연결한다. 이것은 특히 포트 순서가 바뀔 가능성이 있거나, 명시적으로 어떤 포트를 연결하는지를 나타내고자 할 때 유용하다.
module my_module(
input a,
input b,
output c
);
// 모듈의 동작을 정의하는 부분
assign c = a & b; // AND 연산을 수행하여 c에 할당
endmodule
(암시적 연결이라고도 한다)
module top_module;
wire w1, w2, c_output; // 와이어들을 정의
// Positional Association을 사용한 모듈 인스턴스화
my_module instance_pos(w1, w2, c_output); // 포트를 순서대로 연결
//my_module을 가져와 instance_pos이름 붙임
//my_module에서 선언한 순서대로 입력, 입력, 출력 순서로 연결
(명시적 연결이라고도 한다)
module top_module;
wire w1, w2, c_output; // 와이어들을 정의
// Named Association을 사용한 모듈 인스턴스화
my_module instance_named(.a(w1), .b(w2), .c(c_output)); // 각 포트를 명시적으로 지정하여 연결
//my_module을 가져와 instance_named이름 붙임
//my_module의 a,b,c를 top_module의 w1,w2,c_output과 연결
//인스턴스의 명시적 연결//.가져온 인스턴스가 선언된 모듈의 변수 a,b,c(현재 속해있는 모듈의 변수 w1,w2,c_output)
// 다른 작업 수행
endmodule
연속적 할당(Continuous Assignment)과 절차적 할당(Procedural Assignment)이 존재
연속적, 절차적이라는 단어에서 느낌이 오듯이
연속적 할당은 특별한 조건 없이 연속적으로 이루어지는 할당인 반면
절차적 할당의 경우 어떤 절차, 조건이 만족됐을 때, 할당이 되는 방식으로 볼 수 있다.
연속적 할당의 경우, 우변의 값에 변화가 있을 때마다 좌변에 할당을 해주게 된다.
즉, 우변 값이 변하게 되는 순간에 좌변에 할당이 되는 것.
그러면 wire와 reg와 연관지어서 생각해 볼 때 연속적 할당은 wire와 reg 중 어떤 port type과 어울릴까?
연속적 할당의 경우, Clock을 기다리는 어떤 절차(조건)를 기다렸다가 할당하는 것이 아니라
우변의 값이 변화하는 즉시 좌변에 할당을 하는 것이다.
따라서 값을 저장하고 있다가 어떤 특정 타이밍에 값을 Update하는 reg보다는
값을 저장할 수 없기에 항상 값을 Update하는 wire와 연관이 깊다.
module AndGate(
input A, // 입력 A
input B, // 입력 B
output Y // 출력 Y
);
assign Y = A & B; // Y에는 A와 B의 논리 AND 결과가 할당
endmodule
always block은 계속 실행됨.
always문은 always @(sensitive list) begin ~ end 형태로 작성을 하게 되는데
sensitive list가 변할 때마다 할당을 해라~ 라는 의미. 변화에 따른 동작에서 변화 자체는 두가지 종류가 있는데 level sensitive와 edge sensitive가 있다.
level sensitive는 @뒤에 (괄호) 속에 들어있는 input port중 변하는게 있다면 always 문이 수행되는 것을 말하고
edge sensitive는 @뒤에 (괄호) 속에 들어있는 input port 앞에 posedge 혹은 negedge를 붙여서 edge에 따라 always문이 수행되게 만드는 것이다. posedge라는 것은 positive edge(상승 엣지)를 의미하고 negedge는 negative edge(하강 엣지)를 의미한다.
always @(a or b or sel)
begin
y =0;
if( sel == 0) begin
y = a;
end else
begin
y= b;
end
end
always @(posedge clk, negedge rstn) // clk가 rising edge일때 또는 rstn가 falling edge일때 동작한다.
begin
if(rstn == 0)
begin
value <=0;
end
else
begin
value <= input_value;
end
end
module and_gate( //모듈과 모듈이름은 같은 줄에 있어야 함
input a, b, //입력 a, b
output reg q //레지스터 자료형 출력 q
);
always @(a, b)begin // 몸체 시작 begin (c언어 '{' 역할)
case({a, b}) // 비트는 왼쪽에서 부터 순서대로 할당
2'b00: q = 0; // ';'까지가 한줄, beging과end 생략가능
2'b01: q = 0; // a는0 b는1인 상황
2'b10: q = 0;
2'b11: q = 1;
endcase
end // 몸체 끝 end (c언어 '}' 역할)
endmodule

코드창 상단 저장->맨 왼쪽창 Simulation-Run Simulation
(시뮬레이션 화면)
입력 a,b의 값들을 변경했을때

오른쪽 클릭->force constant->force value값 1또는0 입력

각각 00,10,01,11
또는
다시 오른쪽 클릭->force clock(입력 비트들은 주기적으로 변화하기 때문에 클럭을 변화 시켜 결과를 확인할 수 있다)

Leading edge(상승엣지)와 Trailing edge(하강엣지) 0,1을 넣으면 파형이 신호0에서 시작해서 정해진 주기때 신호1로 상승

종료할때 맨 오른쪽위의 전체창 x를 눌러 종료해야함(탭 종료로 하면 안됨)

동작적 모델링(and_gate)과 구조적 모델링(half_adder)
and_gate를 반가산기의 인스턴스로 사용
반가산기는 xor 와 and 게이트 조합으로 만듬
베릴로그에서는 기본적인 논리 게이트(primitive gates)들은 제공한다
primitive gates : AND, OR, NOT, XOR, NAND, NOR
module and_gate(
input a, b,
output reg q
);
always @(a, b)begin
case({a, b})
2'b00: q = 0;
2'b01: q = 0;
2'b10: q = 0;
2'b11: q = 1;
endcase
end
endmodule
module half_adder
(
input a, b,
output s, c
);
and_gate carry
(
.a(a), .b(b), //.a .b .q는 and_gate
.q(c) // (a) (b) (c)는 half_adder
);
xor (s, a, b);
endmodule
위치 연결로 연결
module and_gate(
output reg q,
input a, b
);
always @(a, b)begin
case({a, b})
2'b00: q = 0;
2'b01: q = 0;
2'b10: q = 0;
2'b11: q = 1;
endcase
end
endmodule
module half_adder
(
input a, b,
output s, c
);
and carry (c, a, b); //기본제공 게이트 사용 게이트이름 (출력, 입력, 입력)
xor (s, a, b); //기본제공 게이트 사용 (출력, 입력, 입력)
endmodule
동작적 모델링
module half_adder_behavioral(
input a, b,
output reg s, c);
always @(a, b)begin
case({a, b})
2'b00: begin s = 0; c = 0; end
2'b01: begin s = 1; c = 0; end
2'b10: begin s = 1; c = 0; end
2'b11: begin s = 0; c = 1; end
endcase
end
endmodule
입출력단자 선언시 기본 와이어 자료형
always 안의 센서시브티 값
always의case는 모든경우가 다 있어야하고 아니면 default값
always안의 대입연산자 좌항 변수는 레지스터형 자료형만 가능
module half_adder_structural (
input a, b,
output s, c);
and (c, a, b);
xor (s, a, b);
endmodule
기본게이트들은 (출력, 입력, 입력) 순서, 출력은 하나
두개 이상의 출력은 모듈로 만듬
데이터 타입 : wire타입, 레지스터 타입
input은 기본 wire타입

시뮬레이션 안됌


and게이트 상승엣지1 하강엣지0 100ns
a:100ns b:50ns

and게이트 상승엣지0 하강엣지1 100ns
a:100ns b:50ns