# 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 ; ``` ![image](https://hackmd.io/_uploads/H1XA3Ry7ge.png) ### 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)** | **條件性產生硬體結構** | **編譯時期決定是否產生邏輯** |