OPERATORS
LOGICAL OPERATORS • • • • • • • •
Priority not (top priority) and, or, nand, nor, xor, xnor (equal priority) Predefined for bit, bit_vector boolean Data types have to match
entity LOGIC_OP is port (A, B, C, D : in bit; Z1: out bit; EQUAL : out boolean); end LOGIC_OP; architecture EXAMPLE of LOGIC_OP is begin Z1 <= A and (B or (not C xor D))); EQUAL <= A xor B; • end EXAMPLE;
-- wrong
Logical Operations with Arrays • Operands of the same length and type • Assignment via the position of the elements (according to range definition)
architecture EXAMPLE of LOGICAL_OP is signal A_BUS, B_BUS : bit_vector (3 downto 0); signal Z_BUS : bit_vector (4 to 7); begin Z_BUS <= A_BUS and B_BUS; end EXAMPLE;
Shift Operators: Examples
Arithmetic Operators • Operands of the same type • Predefined for integer real (except mod and rem) physical types (e.g. time) Not defined for bit_vector
• The typical algebraic operators are available for integers, such as +,-,* (multiplication), and / (division). Although these operations are not built-in for bit_vectors, they are often provided in libraries that come with your VHDL software. They are used with bit_vectors by interpreting them as a binary representation of integers, which may be added, subtracted, multiplied, or divided.
Relational operators • They are =, /=, <, <=, > and >= and have their usual meanings (/= denotes the not equal operator). The result of all these operators is a boolean value (TRUE or FALSE).
• The arguments to the = and /= operators may be of any type. The arguments of the <, <=, > and >= operators may be any scalar type (integer, real, and physical types) or the bit_vector type. If the arguments are bit_vectors, then the arguments must be the same length and the result is TRUE only if the relation is true for each corresponding element of the array arguments.
When operands are discrete array types , comparison is performed one element at a time from left to right .
BIT_VECTOR “011”
architecture EXAMPLE of COMPARISON is signal NIBBLE: bit_vector(3 downto 0); signal BYTE: bit_vector(0 to 7); begin NIBBLE <= "1001"; BYTE <= "00001111"; COMPARE: process (NIBBLE, BYTE) begin if (NIBBLE < BYTE) then -- evaluated as: -- if (NIBBLE(3) < BYTE(0)) or -- ((NIBBLE(3) = BYTE(0)) and -- (NIBBLE(2) < BYTE(1))) or -- ((NIBBLE(3) = BYTE(0)) and -- (NIBBLE(2) = BYTE(1)) and -- (NIBBLE(1) < BYTE(2))) or ... -- better: if (( "0000"& NIBBLE) <= BYTE) then
• Operands of the same type • Arrays: may differ in length • left-alignment prior to comparison • are compared element after element • No numerical interpretation • (unsigned, 2-complement, etc.) •
• When comparing array types it must be considered that the comparison is carried out from the left side to the right. • That means for arrays of varying length that "111" is greater than "1001", for example. If it is not desired, hence shall be compared right-aligned, then the arrays will have to be brought upon the equal length by hand, • e.g. by means of concatenation: '0'&"111" is then smaller than "1001".
BEHAVIORAL MODELING • The IF statement The if condition must evaluate to a boolean value ('true' or 'false'). After the first if condition, any number of elsif conditions may follow. Overlaps may occur within different conditions. An else branch, which combines all cases that have not been covered before, can optionally be inserted last. The if statement is terminated with 'end if'. • The first if condition has top priority: if this condition is fulfilled, the corresponding statements will be carried out and the rest of the 'if - end if' block will be skipped.
•
if CONDITION then -- sequential statements end if;
• if CONDITION then -- sequential statements else -- sequential statements end if;
if CONDITION then -- sequential statements elsif CONDITION then -- sequential statements ··· else -- sequential statements end if;
IF Statement: Example entity IF_STATEMENT is port (A, B, C, X : in bit_vector (3 downto 0); Z : out bit_vector (3 downto 0); end IF_STATEMENT;
architecture EXAMPLE1 of IF_STATEMENT is begin process (A, B, C, X) begin Z <= A; if (X = "1111") then Z <= B; elsif (X > "1000") then Z <= C; end if; end process; end EXAMPLE1;
architecture EXAMPLE2 of IF_STATEMENT is begin process (A, B, C, X) begin if (X = "1111") then Z <= B; elsif (X > "1000") then Z <= C; else Z <= a; end if; end process; end EXAMPLE2;
• The example code shows two different implementations of equivalent behaviour. The signal assignment to the signal Z in the first line of the left process (architecture EXAMPLE1) is called a default assignment, as its effects will only be visible if it is not overwritten by another assignment to Z. •
• Note that the two conditions of the 'if' and 'elsif' part overlap, because X="1111" is also true when X>"1000". As a result of the priority mechanism of this if construct, Z will receive the value of B if X="1111".
IF -EXAMPLE library ieee; use ieee.std_logic_1164.all;
entity tristate_dr is port(d_in:in std_logic_vector(7 downto 0); en: in std_logic; d_out:out std_logic_vector(7 downto 0) ); end tristate_dr;
architecture behavior of tristate_dr is begin process(d_in, en) begin if en='1' then d_out <= d_in; else -- array can be created simply by using vector d_out <= "ZZZZZZZZ"; end if; end process; end behavior;
• Architecture BEH of DEMUX is begin process (e,s) begin if e<=‘1’ then if s <=“00” then d(0) <=e; elsif s<=“01” then d(1) <=e;
elsif s<= “10” then d(2)<=e; else d(3) <=e; endif; else d<=“0000”; endif; end process; end beh;
Comparator entity Comparator is
port(A:in std_logic_vector(3 downto 0); B:in std_logic_vector(3 downto 0); less:out std_logic; equal:out std_logic; greater:out std_logic ); end Comparator;
architecture behv of Comparator is begin process (A,B) begin if (A
elsif (A=B) then less <= '0'; equal <= '1'; greater <= '0'; else less <= '0'; equal <= '0'; greater <= '1'; end if; end process; end behv;
D FF library ieee ; use ieee.std_logic_1164.all; use work.all; entity dff is port(data_in:in std_logic; clock:in std_logic; data_out:out std_logic); end dff;
architecture behv of dff is begin process (data_in, clock) begin -- clock rising edge if (clock='1' and clock'event) then data_out <= data_in; end if; end process; end behv;
JK FF library ieee; use ieee.std_logic_1164.all; entity JK_FF is port (clock:in std_logic; J, K:in std_logic; reset:in std_logic; Q, Qbar:out std_logic); end JK_FF;
architecture behv of JK_FF is -- define the useful signals here signal state: std_logic; signal input: std_logic_vector(1 downto 0); begin -- combine inputs into vector input <= J & K; p: process (clock, reset) begin if (reset='1') then state <= '0'; elsif (clock=‘1’ and clock’event) then
• • • • • • • • • • • •
-- compare to the truth table case (input) is when "11" => state <= not state; when "10" => state <= '1'; when "01" => state <= '0'; when others => null; end case; end if;
•
end process;
• • •
-- concurrent statements Q <= state; Qbar <= not state;
•
end behv;
CASE Statement case EXPRESSION is when VALUE_1 => -- sequential statements when VALUE_2 | VALUE_3 => -- sequential statements when VALUE_4 to VALUE_N => -- sequential statements when others => -- sequential statements end case ;
• • • • • • •
Choice options must not overlap All choice options have to be covered single values value range selection of values ("|" means "or") "when others" covers all remaining choice options
• Ranges can be defined for data types with a fixed order, only, e.g. user defined enumerated types or integer values. This way, it can be decided whether one value is less than, equal to or greater than another value. • For ARRAY types (e.g. a BIT_VECTOR) there is no such order, i.e. the range "0000" TO "0100" is undefined and therefore not admissible.
CASE :EXAMPLE entity CASE_STATEMENT is port (A, B, C, X : in integer range 0 to 15 Z : out integer range 0 to 15; end CASE_STATEMENT;
architecture EXAMPLE of CASE_STATEMENT is begin process (A, B, C, X) begin case X is when 0 => Z <= A; when 7 | 9 => Z <= B; when 1 to 5 => Z <= C; when others => Z <= 0; end case; end process; end EXAMPLE;
DECODER library ieee; use ieee.std_logic_1164.all; entity DECODER is port(I:in std_logic_vector(1 downto 0); O:out std_logic_vector(3 downto 0)); end DECODER;
architecture behv of DECODER is begin -- process statement process (I) begin -- use case statement case I is when "00" => O <= "0001"; when "01" => O <= "0010"; when "10" => O <= "0100"; when "11" => O <= "1000" when others => O <= "XXXX"; end case; end process; end behv;
architecture when_else of DECODER is begin -- use when..else statement O <= "0001" when I = "00" else "0010" when I = "01" else "0100" when I = "10" else "1000" when I = "11" else "XXXX"; end when_else;
FOR Loops • • • •
Loop parameter is implicitly declared can not be declared externally read only access The loop parameter adopts all values from the range definition • integer ranges • enumerated types
Loop SYNTAX [LOOP_LABEL :] for IDENTIFIER in DISCRETE_RANGE loop -- sequential statements end loop [LOOP_LABEL] ; [LOOP_LABEL :] while CONDITION loop -- sequential statements end loop [LOOP_LABEL] ;
• • • • •
Optional label FOR loop identifier not declared read only not visible outside the loop
entity FOR_LOOP is port (A : in integer range 0 to 3; Z : out bit_vector (3 downto 0)); end FOR_LOOP; architecture EXAMPLE of FOR_LOOP is begin process (A) begin Z <= "0000"; for I in 0 to 3 loop if (A = I) then Z(I) <= `1`; end if; end loop; end process; end EXAMPLE;
for identifier in range EXAMPLE FACTORIAL :=1; for NUMBER in 2 to 5 loop FACTORIAL :=FACTORIAL *NUMBER ; end loop; NO EXPLICIT DECLARATION FOR NUMBER IS REQUIRED
Loop Examples entity CONV_INT is port (VECTOR: in bit_vector(7 downto 0); RESULT: out integer); end CONV_INT;
architecture A of CONV_INT is begin process(VECTOR) variable TMP: integer; begin TMP := 0; for I in 7 downto 0 loop if (VECTOR(I)='1') then TMP := TMP + 2**I; end if; end loop; RESULT <= TMP; end process; end A;
WAIT Statement • 'wait' statements stop the process execution • The process is continued when the instruction is fulfilled
Different types of wait statements: • wait for a specific time wait for 5 ns; wait for a signal event wait for SUM; wait for a true condition (requires an event) wait until SUM >100; indefinite (process is never reactivated) wait;
WAIT • Wait statements must not be used in processes with sensitivity list
Latch model
entity FF is port (D, CLK : in bit; Q : out bit); end FF;
LATCH architecture BEH_1 of FF is begin process begin wait on CLK; if (CLK = '1') then Q <= D; end if; end process; end BEH_1;
LATCH architecture BEH_2 of FF is begin process begin wait until CLK=`1`; Q <= D; end process; end BEH_2;
Testbench: stimuli generation STIMULUS: process begin SEL <= `0`; BUS_B <= "0000"; BUS_A <= "1111"; wait for 10 ns; SEL <= `1`; wait for 10 ns; SEL <= `0`; wait for 10 ns; wait; end process STIMULUS;
WAIT
• Wait constructs, in general, are an excellent tool for describing timing specifications. • For example it is easy to implement a bus protocol for simulation. The timing specification can directly be translated to simulatable VHDL code. • But keep in mind that this behavioural modelling can only be used for simulation purposes as it is definitely not syntheziable
Entity of CPU Entity CPU is Port(CPU_DATA_VALID: CPU_DATA_READ: LOCAL_BUFFER : std_logic_vector(0 to 7); CPU_DATA: std_logic_vector(0 to 7); end CPU;
in std_logic; in std_logic; in out
READ_CPU : process begin wait until CPU_DATA_VALID = `1`; CPU_DATA_READ <= `1`; wait for 20 ns; LOCAL_BUFFER <= CPU_DATA; wait for 10 ns; CPU_DATA_READ <= `0`; end process READ_CPU;
Variables • Variables are available within processes, only • named within process declarations • known only in this process • VHDL 93: shared variables • immediate assignment • keep the last value
VARIABLES • • • •
Possible assignments signal to variable variable to signal types have to match
Variables architecture RTL of XYZ is signal A, B, C : integer range 0 to 7; signal Y, Z : integer range 0 to 15; begin process (A, B, C) variable M, N : integer range 0 to 7; begin M := A; N := B; Z <= M + N; M := C; Y <= M + N; end process; end RTL;
VARIABLE –EXAMPLE Process (A) variable EVENTS: integer =-1; Begin EVENTS:=EVENTS +1; end process;
Signal A,Z:INTEGER; process (A) variable V1,V2 :INTEGER; begin V1:=A-V2; Z<=-V1; V2:=Z+V1*2; end process;
VARIABLE • If an event occurred on signal A at time T1 ,and variable V2 was associated a value ,say 10 ,in statement 3 ,then the next time an event occurs on signal A, say at time T2 ,the value of V2 used in statement 1 would still be 10.
SIGNALS • Signal values are assigned after the process execution • Only the last signal assignment is carried out signal-object <=expression[after delay value];
• A signal assignment can appear outside a process.Then it is considered to be a concurrent signal assignment statement. • Within a process, it is a sequential signal assignment and is executed in sequence with other statements.
• When a signal assignment is excuted,the value of the expression is computed, and this value is scheduled to be assigned to the signal after the specified delay. • It is important to note that the expression is evaluated at the time the statement is executed which is the current simulation time ,and not after the specified delay. • e.g . Z<= M+N after 5 ns; • Z<= M+N;
• If no after clause (e.g. after delay) is specified ,the delay is assumed to be a default delay. • DELTA DELAY • is a very small delay ,and actual simulation time does not advance .
Process (A,B,C,D); variable T1,T2,T3:bit; Begin T1:=A and B; T2:=C and D; T3:=T1 or T2; Z<=not T3; End process;
• T1,T2 and T2 get their values immediately • But Z gets its value only after a delta delay
• In the process ..if an event occurs on A at time T, execution of statement 1 causes V1 to get a value, • Signal Z is then scheduled to get a value at time T+delta, and statement 3 is executed in which the old value of Z is used .The reason is ,new value of Z comes only after the delta delay
Global Variables (VHDL'93) • Accessible by all processes of an architecture • (shared variables) • Can introduce non-determinism •
• Not to be used in synthesizable code
architecture BEHAVE of SHARED is shared variable S : integer; begin process (A, B) begin S := A + B; end process; process (A, B) begin S := A - B; end process; end BEHAVE;
Variables and Signals • Variables and signals show a fundamentally different behaviour. • In a process, the last signal assignment to a signal is carried out when the process execution is suspended. • Value assignments to variables, however, are carried out immediately. • To distinguish between a signal and a variable assignment different symbols are used: ' <= ' indicates a signal assignment and ' := ' indicates a variable assignment.
SIGNAL ASSIGNMENT Signal-object<=expression [after delay value]; e.g. Z<= X after 5 ns; Z<=X;
• When a signal assignment statement is executed , the value of the expression is computed ,and this value is scheduled to be assigned to the signal after the specified delay . • The expression is executed currently ,but the signal is ‘assigned ‘ the value or ‘scheduled to be assigned the value’ after the specified delay plus a ‘delta delay’
Delta Delay • A delta delay is a very small delay . • This delay models the actual hardware .
Wait for 0 ns Process begin wait on DATA; A<=DATA; wait for 0 ns; B<=A; End process;
DATA T
DATA A
B
B without the wait statement
Creating waveforms signal A : std_logic;
Process (A) begin A <= not A after 10 ns; End process;
Example 3: D FF with Asynchronous Reset -----
Declarations........ CLK: in STD_LOGIC; RESET: in STD_LOGIC; DIN: in STD_LOGIC; DOUT: out STD_LOGIC;
process (CLK, RESET) begin if RESET='1' then --asynchronous RESET active High DOUT <= '0'; elsif (CLK'event and CLK='1') then --CLK rising edge DOUT <= DIN; end if; end process;
D FF with Synchronous Reset process (CLK) begin if (CLK'event and CLK='1‘) then --CLK rising edge if RESET='1' then --synchronous RESET active High DOUT <= '0'; else DOUT <= DIN; end if; end if; end process;
3-bit Shift-Register/Shifter
entity shift_reg is port(I:in std_logic; clock:in std_logic; shift:in std_logic; Q:out std_logic); end shift_reg;
architecture behv of shift_reg is -- initialize the declared signal signal S: std_logic_vector(2 downto 0):="111"; begin process(I, clock, shift, S) begin if clock'event and clock='1' then if shift = '1' then S <= I & S(2 downto 1); end if; end if; end process;
32-bit Shift Register, sync rst entity SER_PAR_SH_REG is port ( CLK, RST, Serial_Din : in
std_logic;
Data : out std_logic_vector(31 downto 0) ); end entity SER_PAR_SH_REG;
architecture behavioral of SER_PAR_SH_REG is Signal Internal_Data : std_logic_vector(31 downto 0); begin process (CLK) begin if CLK’event and CLK = ‘1’ then if RST = ‘1’ then Internal_Data <= x”00000000”; else Internal_Data <= Serial_Din & Internal_Data(31 downto 1); end if; end if; end process; Data <= Internal_Data; end behavioral;
16-bit Loadable Counter, async reset entity CNTR_16_async is port ( CLK, RST, Load : in std_logic; Input_Data : in std_logic_vector(15 downto 0); Count : out std_logic_vector(15 downto 0) ); end entity CNTR_16_async ;
architecture behavioral of CNTR_16_async is Signal Internal_Count : std_logic_vector(15 downto 0) := X”0000”; begin process (CLK, RST) begin if RST = ‘1’ then Internal_Count <= ”0000”; elsif CLK’event and CLK = ‘1’ then if Load = ‘1’ then Internal_Count <= Input_Data; else Internal_Count <= Internal_Count + 1; end if; end if; end process; Count <= Internal_Count; end behavioral;