# Ch4:VHDL Advanced
本章節將講解進階的 VHDL 語法
在 VHDL 中,有以下兩種 subprogram:
| 項目 | 函數 (Function) | 程序 (Procedure) |
| ----------- | ------------- | ---------------------- |
| 用途 | 計算單一數值 | 分割大型行為描述 |
| 回傳值 | 恆為**一個值** | 可回傳**零個或多個值** |
| 是否可含 `wait` | ❌ 不可含有 | ✅ 可含有 |
| 模擬時間 | **零模擬時間** | 可能為零,也可能不是,視 `wait` 而定 |
| 呼叫方式 | 可用於表達式中 | 作為語句呼叫 |
| 適用場景 | 數學運算、資料轉換 | 控制流程、呼叫子模組 |
## Functions
```vhdl=
[pure|impure] function function-name (parameter-list) return return-type
begin
function-statements
end [function] [function-name];
```
- **parameter-list**:
- 只允許 **in** 模式
- 只有 constant, signal 可以寫入
- 預設的類型是 object
- **pure function**:只要輸入一樣,輸出一定一樣的數字
- **impure function**:輸入一樣有可能輸出**不一樣**
- return return-type:放入輸出的型別
- 範例:
:::warning
記得 function 要放在 archutecture 中
:::
```vhdl=
entity FULL_ADDER is
port(a, b, cin:in bit;
sum, count:out but);
end FULL_ADDER;
architecture df of FULL_ADDER is
function f_cout(a, b, cin: in bit) return bit is
begin
return (a and b) or (a and cin) or (b and cin);
end f_cout;
begin
cout <= f_cout(a, b, cin)
sum <= (a xor b) xor cin;
end df;
```
## Procedure
程序(Procedure)允許將大型行為分解成模組化的區塊。與函數不同,程序可以透過 `out` 和 `inout` 模式的參數傳回零個或多個值。
```vhdl=
procedure procedure-name(parameter-list)
begin
procedure-statements
end [procedure] [procedure-name];
```
- **parameter-list**:
- 參數可以是**常數(constants)、變數(variables)或訊號(signals)**,其模式可以是 `in`、`out` 或 `inout`。
- 如果沒有明確指定參數的類別(class),則根據模式會有預設行為:
| 模式 | 預設類別 | 備註 |
| ------- | -------- | -------------- |
| `in` | constant | 只能讀取值,不能改變參數內容 |
| `out` | variable | 可寫入值 |
| `inout` | variable | 可讀寫 |
- **範例**:
:::warning
記得 procedure 要放在 archutecture 中
:::
```vhdl=
procedure f_div(
signal div: in integer range 0 to 15;
signal count: inout integer range 0 to 15;
signal temp: inout bit) is
begin
if count < div then
ount <= count +1;
else
count <= 0;
temp<= not temp;
end if;
end f_div;
```
## Subprogram Overloading
:::danger
不是每一個工具都允許 subprogram overloading
:::
因為 VHDL 有嚴格的型別限制,因此 VHDL 允許我們可以擁有兩個一樣名字輸入型別卻不同的 function,也允許輸入的變數數量不一樣
```vhdl=
function COUNT(ORANGE: INTEGER) return INTERGER;
function COUNT(APPLE: BIT)return INTERGER;
function COUNT(A1, A2: INTERGER)return INTERGER;
```
在呼叫時,我們可以依據不同輸入來判斷是哪一個 function:
```vhdl=
COUNT(20); --> 第一個函數
COUNT('1'); --> 第二個函數
COUNT(12, 22); --> 第三個函數
```
此外,即使子程序具有**相同數量的參數**,且參數的**資料型別也相同**,如果它們的**回傳值資料型別不同**,這些子程序仍然可以**共用相同的名稱**。
## Operator Overloading
在 VHDL 中,operator overloading 的需求來自於:**operator 只能用於特定的資料型別**。
如果設計者想要在自訂資料型別(user-defined type)上使用某個 operator,那麼就必須對該 operator overload,以支援該型別的操作。
```vhdl=
Z <= A + B
```
以 `+` 為例,`+` 只能接受 `unsigned` 與 `interger` 型別,如果需要相加其他型別,就必須要 operator overload
```vhdl=
function "+" (r, l : bit_vector) return integer is
begin
return ( vector_to_int(r) + vector_to_int(l) );
end
```
## Packages
在 VHDL 裡,package 是用來宣告和共用:
- 常數(constants)
- 型別(types)
- 子程式(functions/procedures)
- 組件(components)
- 運算子 overloading
而這些定義可以在**多個設計單元(entity/architecture/process**)中重複使用。
**pakage** 的結構可以分為以下兩部分:
- **pakage declaration**:定義有哪些項目
- **pakage body**:定義 pakage 的行為
```vhdl=
-- 宣告區
package my_math is
constant PI : real := 3.14159;
type vector8 is array(0 to 7) of std_logic;
function square(x: integer) return integer;
end package;
-- 實作區
package body my_math is
function square(x: integer) return integer is
begin
return x * x;
end function;
end package body;
```
在其他設計單元時如果我們要使用該 package,我們可以這樣:
```vhdl=
--- 引入 package
library work;
use work.my_math.all;
signal a: integer := 5;
signal b: integer;
b <= square(a);
```
## Generics
Generic 就像模組的參數,允許你針對不同應用設定不同的數值,而不必改整個程式碼。
```vhdl=
entity my_counter is
generic (
MAX_COUNT : integer := 255 -- 預設值
);
port (
clk : in std_logic;
count : out integer
);
end my_counter;
```
- **實際案例**:
```vhdl=
entity counter is
generic (
N : integer := 8 -- 計數器寬度
);
port (
clk : in std_logic;
rst : in std_logic;
outp : out std_logic_vector(N-1 downto 0)
);
end entity;
architecture behav of counter is
signal count : unsigned(N-1 downto 0);
begin
process(clk, rst)
begin
if rst = '1' then
count <= (others => '0');
elsif rising_edge(clk) then
count <= count + 1;
end if;
end process;
outp <= std_logic_vector(count);
end architecture;
```
## Generate statement
:::warning
generate 都是在編譯期間就確定好的
:::
`generate` 是一種語法結構,讓你可以用迴圈或條件語法自動產生硬體模組的多重實例。
在 VHDL 中,不能像寫程式一樣直接用 `for` 直接產生邏輯,但你可以用:
- `for-generate`
- `if-generate`
來達到類似的效果,但要在**編譯時期**來決定產生哪些電路
### For-generation
用來產生**重複的相同邏輯多次**
```vhdl=
gen_adder : for i in 0 to 3 generate
adder_inst : full_adder port map (...);
end generate;
-- 也可以倒序(down to)
fa_generate: for K in 3 downto 0 generate
fa_3to0 : FA port map (A(K), B(K), CAR(K), CAR(K+1), SUM(K));
end generate ;
```

### If-generate
- 用來**根據條件決定是否產生某段邏輯**
- 適合用於不同配置的切換
```vhdl=
-- 如果 PIPE = true
use_pipeline : if PIPE = true generate
-- 插入 pipeline registers
end generate;
-- 如果 PIPE = false
nouse_pipeline : if PIPE = false generate
-- 插入 pipeline registers
end generate;
```
- **與 if-then-else 的差別**:
| 語法 | 類型 | 用途 | 執行時機 |
| ---------------------- | --------------------------------------- | --------------- | ---------------- |
| `if ... then ... else` | **順序語句(sequential statement)** | **模擬邏輯分支/流程控制** | **模擬/合成時期執行** |
| `if ... generate` | **併行語句(concurrent generate statement)** | **條件性產生硬體結構** | **編譯時期決定是否產生邏輯** |