540 likes | 751 Views
ASIC 120: Digital Systems and Standard-Cell ASIC Design. Tutorial 3: Intermediate VHDL November 9, 2005. Outline. Summary of previous tutorial Other signal values besides ‘0’ and ‘1’ More VHDL data types Attributes, type definitions Generics
E N D
ASIC 120: Digital Systems and Standard-Cell ASIC Design Tutorial 3: Intermediate VHDL November 9, 2005
Outline • Summary of previous tutorial • Other signal values besides ‘0’ and ‘1’ • More VHDL data types • Attributes, type definitions • Generics • Splitting a VHDL project across multiple design units and files • if … generate, for … generate • VHDL 1987 vs. 1993 vs. 2000 • Test benches • time, procedures, variables, file access, etc.
Summary of Previous Tutorial • HDL design flow • Format of a VHDL file • Combinational statements • assignments, conditionals, when … else • Sequential statements • processes, if … then … else, case, loops
Wires in the Real World • We think of digital logic as being either 0 or 1 • Electricity on a real, physical wire is analog • many different values • Basic VHDL types do not take this into account • bit • bit_vector • This is why we have the ieee.std_logic_1164 library • std_logic • std_logic_vector
std_logic_1164 Values Value Description ‘U’ Uninitialized ‘X’ Unknown ‘0’ Strong 0 (driving) ‘1’ Strong 1 (driving) ‘Z’ High impedance ‘W’ Weak unknown ‘L’ Weak 0 (reading) ‘H’ Weak 1 (reading) ‘-’ Don't care
Things to Watch For • Never have two output driving one wire • Tri-state buffers • the usual way of connecting components to a bus • compiler will often synthesize in a mux • explicitly use a mux instead • Summary: only design with ‘0’ and ‘1’, but be prepared to accept any value
std_logic_1164 example • Consider: caseSelis when“00” => X <= B; when“10” => X <= A; when“1-” => X <= D; whenothers => X <= C; endcase;
std_logic_1164 example • While this statement is valid, it is bad form • unsynthesizable • designing with values other than ‘0’ and ‘1’, instead of just being prepared to accept them caseSelis when“00” => X <= B; when“10” => X <= A; whenothers => X <= C; endcase;
More On Numeric Data Types • We have already seen • bit, bit_vector • std_logic, std_logic_vector • Now we look at • integer, real • std_logic_arith • numeric_std
Arithmetic Data Types • bit, bit_vector, std_logic, std_logic_vector are useful for working with wires • However, cannot perform arithmetic operations • not explicitly signed versus unsigned • integer vs. real representations
Arithmetic Data Types: integer • integer is to signed as bit_vector is to std_logic_vector • Not well standardized across VHDL tools • More on the real data type later
Arithmetic Data Types: std_logic_arith • Obfuscated • Use numeric_std instead
Arithmetic Data Types: numeric_std • Example: library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; signal data : unsigned(7 downto 0); … data <= 137; data <= data + 1;
Arithmetic Data Types: numeric_std • numeric_std allows the usual arithmetic operators to be used • Conversion to/from std_logic_vector • unsigned(…) • signed(…) • std_logic_vector(…) • Make sure your intermediate signals are large enough • 4-bit number + 4-bit number could equal 5-bit number
Attributes • Consider: process(clk) begin if (clk’event and clk = ‘1’) then if (resetn = ‘0’) q <= ‘0’; else q <= d; end if; end if; end process;
Attributes • event is an attribute of the clk signal • the apostrophe (‘) delimits the attribute • An attribute is a characteristic of a VHDL object • extra data attached to signal, pin, etc. • Can be user-defined:
Attributes • User-defined attributes are generally used to tap into specific compiler’s functionality • Pre-defined attributes include: • event, last_event, last_value • range, length, ascending • left, right, high, low • many more
Attributes Example entity eight_regs is port( clk : in std_ulogic; data_in, load : in std_ulogic_vector(7 downto 0); data_out : out std_ulogic_vector(7 downto 0) ); end eight_regs; architecture behavioural of eight_regs is begin signal data_q : std_ulogic_vector(data_in’range); process(clk) begin if (clk’event and clk = ‘1’) then for i in data_in’range loop if (data_in’left = ‘0’) then -- reset data_q(i) <= ‘0’; elsif (load(i) = ‘1’) then -- load data data_q(i) <= data_in(i); end if; end loop; end if; end process; data_out <= data_q; end behavioural;
Modular VHDL • Using the previous example, what if I want 16 registers? • modify the existing code • copy and paste • components
Components • Components provide a way to take an entity/architecture pair and reuse it • use it multiple times • map signals to component inputs and outputs
Component Example • Using the eight_regs entity/architecture defined earlier: … architecture behavioural of sixteen_regs is component eight_regs port( clk : in std_ulogic; data_in, load : in std_ulogic_vector(7 downto 0); data_out : out std_ulogic_vector(7 downto 0) ); end component; begin -- positional eight_regs1 : eight_regs port map ( clock, data_in(15 downto 8), load(15 downto 8), data_out(15 downto 8)); -- named eight_regs2 : eight_regs port map ( clk => clock, data_in => data_in(7 downto 0), load => load(7 downto 0), data_out => data_out(7 downto 0)); end behavioural;
Generics • Recall the attributes example • instead of creating two components, what if we doubled the size of data_in, data_out and load? • Generics allow us to be flexible with sizes of things • compile time decisions • passed from higher level into an entity • Syntax: generic(name : type [:= default_value])
Attributes Example entity eight_regs is port( clk : in std_ulogic; data_in, load : in std_ulogic_vector(7 downto 0); data_out : out std_ulogic_vector(7 downto 0) ); end eight_regs; architecture behavioural of eight_regs is begin signal data_q : std_ulogic_vector(data_in’range); process(clk) begin if (clk’event and clk = ‘1’) then for i in data_in’range loop if (data_in’left = ‘0’) then -- reset data_q(i) <= ‘0’; elsif (load(i) = ‘1’) then -- load data data_q(i) <= data_in(i); end if; end loop; end if; end process; data_out <= data_q; end behavioural;
Generics Example entity eight_regs is generic (bus_width : integer := 8); port( clk : in std_ulogic; data_in, load : in std_ulogic_vector(bus_width-1 downto 0); data_out : out std_ulogic_vector(bus_width-1 downto 0) ); end eight_regs; architecture behavioural of eight_regs is begin signal data_q : std_ulogic_vector(data_in’range); process(clk) begin if (clk’event and clk = ‘1’) then for i in data_in’range loop if (data_in’left = ‘0’) then -- reset data_q(i) <= ‘0’; elsif (load(i) = ‘1’) then -- load data data_q(i) <= data_in(i); end if; end loop; end if; end process; data_out <= data_q; end behavioural;
Generics Example: Up One Level • Using the eight_regs entity/architecture defined earlier: … architecture behavioural of sixteen_regs is component eight_regs generic(bus_width : integer); port( clk : in std_ulogic; data_in, load : in std_ulogic_vector(bus_width-1 downto 0); data_out : out std_ulogic_vector(bus_width-1 downto 0) ); end component; begin eight_regs : eight_regs generic map (bus_width => 16); port map (clock, data_in, load, data_out); end behavioural;
Generics • Note that the data type of the bus_width generic is integer, not signed or unsigned • in this case it’s okay
More On Data Types • User defined data types • Enumerations • Arrays
User Defined Data Types • It is possible to define your own data types in VHDL • Useful for • reusing type declarations • keeping variable types constant across or variable declarations components • Much more can be said on this • VHDL has many data types that we will continue to introduce throughout these tutorials
Enumerations • Relate human-meaningful text to underlying binary values • useful for state machines • Example (includes definition of user-defined data type t_states): architecture test1 of test is … type t_states is (STATE_BEGIN, STATE_RUN, STATE_TURN, STATE_END); signal curr_state : t_states begin process begin wait until rising_edge(clk); if (curr_state = STATE_BEGIN) then curr_state <= STATE_RUN) elsif … end if; end process; end test1;
Arrays • Collections of other data types • std_logic_vector is just an array of std_logic • Multidimensional arrays possible • useful for modelling memory • sometimes design tools can automatically infer memory from them, sometimes not
Arrays • Consider: type t_arr_single is array (31 downto 0) of std_logic; type t_arr_mult is array (31 downto 0, 31 downto 0) of std_logic; signal arr1 : t_arr_single; signal arr2 : t_arr_mult; • Also possible: signal arr3 : array (31 downto 0) of std_logic;
Ways to Replicate Hardware • How can we replicate VHDL functionality • We have seen • Manually (copy and paste) • Components and Generics • Loops • Now we explore • if…generate • for…generate
Generate Statements • Used to replicate concurrent constructs • Only valid outside of processes • Most useful for creating multiple component instantiations
if…, for… generate Example library ieee; use ieee_std_logic_1164.all; entity variable_shift_reg is generic( width : integer := 4; depth : integer := 3; one_or_two : integer := 1 ); port ( clk, reset : in std_logic; data_in : in std_logic_vector(width-1 downto 0); data_out : out std_logic_vector(width-1 downto 0) ); end variable_shift_reg;
if…, for… generate Example architecture structural of variable_shift_reg is component single_register_A port(clk, reset : in std_logic; data_in : in std_logic; data_out : out std_logic ); end component; component single_register_B port(clk, reset, reset2 : in std_logic; data_in : in std_logic; data_out : out std_logic ); end component; begin …
if…, for… generate Example architecture structural of variable_shift_reg is [ component declarations on previous slide] signal data_temp : array(0 to depth) of std_logic_vector(width-1 downto 0); begin width_gen : for i in width-1 downto 0 generate -- connect inputs data_temp(0)(i) <= data_in(i); -- generate “middle” shift registers (generic “one_or_two” selects between _A and _B) depth_gen : for j in 0 to depth-1 generate A_gen : if (one_or_two = 1) then generate sr_gen : single_register_A port map ( clk =>clk, reset => reset, data_in => data_temp(j)(i), data_out => data_temp(j+1)(i)); end generate A_gen; B_gen : if (one_or_two = 2) then generate sr_gen : single_register_B port map ( clk =>clk, reset => reset, reset2 => reset, data_in => data_temp(j)(i), data_out => data_temp(j+1)(i)); end generate B_gen; end generate depth_gen; -- connect outputs data_out(i) <= data_temp(depth)(i); end generate width_gen; end structural;
if…, for… generate Example • This example demonstrated how to construct a variable-width, variable-depth shift register • i.e., a width-bit shift register with depth-stages • You must name an if… or for… generate statement • so the compiler has a base name to give to each instance of a section
VHDL Versions: 1987, 1993, 2000 • There are three different revisions of VHDL • Modern development tools understand all three versions • Important to at least know they exist • Often development tools implement VHDL specification differently as well • We’re going to postpone further discussion on this for now, because we have more important things to look at
Test Benches • Testing synthesized HDL code in hardware happens in the final stages of development • time consuming, expensive, difficult • Test benches allows us to simulate a design • send test inputs • check the outputs • virtually connect different components together to see how they interact
Test Benches • Consider a VHDL entity/architecture pair • inputs and outputs will eventually be connected to physical pins on an FPGA or ASIC • An entity/architecture pair without inputs or outputs is a test bench • signals are generated internally • think of it like a bread board sitting on your desk
Simple Test Bench Example library ieee; use ieee.std_logic_1164.all; entity test_and_gate is -- no inputs or outputs end test_and gate; architecture stimulate of test_and_gate is component and_gate port(A, B : in std_logic; X : out std_logic); end component; constant CLK_PERIOD : time := 20 ns; signal A, B, X : std_logic; begin … end stimulate;
Simple Test Bench Example • Note that we have introduced CLK_PERIOD as a “constant” • its data type is time • time has a unit, in this case, ns or nanoseconds
Simple Test Bench Example … begin -- uut is “unit under test” uut : and_gate port map(A => A, B => B, X => X); process begin A <= 0; B <= 0; wait for CLK_PERIOD; assert (X = ‘0’) report “0,0 result incorrect!” severity ERROR; A <= 0; B <= 1; wait for CLK_PERIOD; assert (X = ‘0’) report “0,1 result incorrect!” severity ERROR; A <= 1; B <= 0; wait for CLK_PERIOD; assert (X = ‘0’) report “1,0 result incorrect!” severity ERROR; A <= 1; B <= 1; wait for CLK_PERIOD; assert (X = ‘1’) report “1,1 result incorrect!” severity ERROR; wait; end process; end stimulate;
Simple Test Bench Example • Instead of “wait until rising_edge(clk)” we are using “wait for CLK_PERIOD” • execution of that process pauses for given amount of time • Final “wait” statement will pause forever • “wait for …” is unsynthesizable • impossible to specify a specific amount of time in hardware • however, this is very useful for test benches
Clocking Test Benches • Often, the clock will be run independently of the input stimulus • Consider: process begin clk <= ‘0’; wait for CLK_PERIOD; clk <= ‘1’; wait for CLK_PERIOD; end process; … process begin wait until rising_edge(clk); [apply input stimulus to unit under test] wait until rising_edge(clk); [check output of unit under test for correctness] end process;
Clocking Test Benches • In this way, we can co-ordinate input stimulus across multiple units under test
More on Test Benches • Another useful test bench tool in VHDL is file input and output • obviously not synthesizable
Functions and Procedures • Functions and procedures in VHDL are useful for defining a block of functionality that can be re-used • similar to functions in C • not the same thing as processes • Due to time constraints, we won’t cover them in any further detail
Variables • Variables can be used to store intermediate values within a process • can also be used in functions and procedures • They are NOT the same thing as signals • use them wisely • Due to time constraints, we won’t cover them in any further detail