VHDL Syntax Review Matthew Murach Basic code layout Define data types (library declarations) o IEEE_std_logic_1163.all defines bit type (0,1,U,X,-,H,L) o IEEE_std_logic_unsigned.all defines arithmetic for unsigned numbers Define user packages o Custom packages Altera,Xilinx, or you come up with So… Library ieee; Use ieee.std_logic_1163.all; Use ieee.std_logic_unsigned.all; Use work.p1_pack.all; -- Use IEEE libraries note that the double -- hyphen is used for commenting -- Your custom package can define types for -- example as well as constants Define the black box (entity declaration) o What are the inputs and outputs o What should be the name of this component o Example 1-bit adder o Needs three inputs (one bit for operands a and b and the carry c) o Needs two outputs (sum and the carry bit) o Clock and enable (optional if you want to use synchronous design) So…. Entity one_bit_add is Port( A : in std_logic; B : in std_logic; Cin : in std_logic; S : out std_logic; Cout : out std_logic; Clk : in std_logic; En : in std_logic ); end one_bit_add; A S B Cout Cin ? clk Well, what is in the box…(architecture section) o Recall from logic design that the output can be computed as follows S A B Cin Cout AB BCin ACin (1.1) o The two outputs can be solved independently (two different trees of logic) o So use two process directives o Declare the architecture section as follows: Archtecture struct of one_bit_add is -- start defining the black box --declare signals and sub-components here Begin --start processes Sum : process(clk,en) -- clk for sync operation or use process(a,b,cin) for async --declare variables for this process Begin If clk = ‘1’ and en = ‘1’ and clk’event then --capture clk on the rising edge S <=a xor b xor c; -- logic End if; End process; Begin --start processes Carry : process(clk,en) -- clk for sync operation or use process(a,b,cin) for async --declare variables for this process Begin If clk = ‘1’ and en = ‘1’ and clk’event then --capture clk on the rising edge Cout <=(a and b) or (b and c) or (a and c); -- logic End if; End process; End struct; -- Note that the sensitivity list tells the process when to trigger. In the synchronous case -- the operation only happens when the clk pulse is received. Likewise for the -- asynchronous case, the answer is only re-evaluated on a changing input signal. Differences between variables and signals Signals are global (wire-like). That is that a signal can be used between processes. Note that it takes one delay unit for an update to occur (or one clock cycle in synchronous circuits). One one process may drive a signal, however multiple processes can read that signal. Signal assignment is concurrent. The following will swap A and B’s values A B; B A; is equal to B A; A B; (1.2) Variables are local (register-like). Updates are immediate and the variable can be read and written several times in a clock. Variable assignment is sequential. A : B; C : A; is NOT equal to C : A; A : B; (1.3) In the first case C gets B’s value. In the second case C gets A’s original value. Components Up to now, designs have been relatively simple enough to allow for the use of one VHDL file. But what if your design is complex and has multiple logic units. Component instancing allows you to use the same logic several times. For the previous case, a multiple bit adder might be preferred. To create this first examine the figure below. A(3 downto 0) B(3 downto 0) C(3 downto 0) S(4 downto 0) Figure 1. 4-bit adder. The four bit adder can be implemented using the one bit adder created above. Note that 2 control regions exist. The fourth adder is slightly different since its carry shows up at the output. Library ieee; Use ieee.std_logic_1164.all; Entity master is Port (a: IN std_logic_vector(3 downto 0); b: IN std_logic_vector(3 downto 0); s: OUT std_logic_vector(4 downto 0); ck, en : IN std_logic); End master; Architecture struct of master is -- Declare Signals Signal c: std_logic_vector(3 downto 0); -- Declare Components note that component declaration is similar to ---- entity declaration Component one_bit_add is Port( A : in std_logic; B : in std_logic; Cin : in std_logic; S : out std_logic; Cout : out std_logic; Clk : in std_logic; En : in std_logic); end component; Begin -- assign defaults c(0) <= ‘0’; -- Clearly the first carry in is zero -- For generate loops GI : for i in 0 to 3 Generate G1 : if (i /= 3) Generate cell : one_bit_add port map (A(i), B(i), C(i), S(i), C(i+1), clk,en); End Generate G1; G2 : if (i = 3) Generate cell : one_bit_add port map (A(i), B(i), C(i), S(i), S(i+1), clk,en); End Generate G2; End Generate GI; End Struct;