asic 120: digital systems and standard-cell asic design tutorial 3: intermediate vhdl november 9,...
DESCRIPTION
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, loopsTRANSCRIPT
ASIC 120: Digital Systems and Standard-Cell ASIC Design
Tutorial 3: Intermediate VHDLNovember 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 ValuesValue 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
std_logic_1164 Resolution Table
U X 0 1 Z W L H -U U U U U U U U U UX U X X X X X X X X0 U X 0 X 0 0 0 0 X1 U X X 1 1 1 1 1 XZ U X 0 1 Z W L H XW U X 0 1 W W W W XL U X 0 1 L W L W XH U X 0 1 H W W H X- U X X X X X X X X
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:
case Sel is when “00” => X <= B; when “10” => X <= A; when “1-” => X <= D; when others => X <= C; end case;
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
case Sel is when “00” => X <= B; when “10” => X <= A; when others => X <= C; end case;
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’) thenif (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 Exampleentity 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 isbegin
signal data_q : std_ulogic_vector(data_in’range);process(clk)begin
if (clk’event and clk = ‘1’) thenfor i in data_in’range loop
if (data_in’left = ‘0’) then -- resetdata_q(i) <= ‘0’;
elsif (load(i) = ‘1’) then -- load datadata_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_regsport( 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-- positionaleight_regs1 : eight_regs port map ( clock, data_in(15 downto 8),
load(15 downto 8), data_out(15 downto 8));-- namedeight_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 Exampleentity 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 isbegin
signal data_q : std_ulogic_vector(data_in’range);process(clk)begin
if (clk’event and clk = ‘1’) thenfor i in data_in’range loop
if (data_in’left = ‘0’) then -- resetdata_q(i) <= ‘0’;
elsif (load(i) = ‘1’) then -- load datadata_q(i) <= data_in(i);
end if;end loop;
end if;end process;data_out <= data_q;
end behavioural;
Generics Exampleentity 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 isbegin
signal data_q : std_ulogic_vector(data_in’range);process(clk)begin
if (clk’event and clk = ‘1’) thenfor i in data_in’range loop
if (data_in’left = ‘0’) then -- resetdata_q(i) <= ‘0’;
elsif (load(i) = ‘1’) then -- load datadata_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_regsgeneric(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;
begineight_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_statesbegin
processbegin
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 Examplelibrary ieee;use ieee_std_logic_1164.all;
entity variable_shift_reg isgeneric( 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 Examplearchitecture structural of variable_shift_reg is
component single_register_Aport(clk, reset : in std_logic;
data_in : in std_logic;data_out : out std_logic
);end component;
component single_register_Bport(clk, reset, reset2 : in std_logic;
data_in : in std_logic;data_out : out std_logic
);end component;
begin…
if…, for… generate Examplearchitecture 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);
beginwidth_gen : for i in width-1 downto 0 generate
-- connect inputsdata_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 generatesr_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 outputsdata_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 Examplelibrary 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_gateport(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);
processbegin
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:
processbegin
clk <= ‘0’;wait for CLK_PERIOD;clk <= ‘1’;wait for CLK_PERIOD;
end process;
…
processbegin
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
What I’ve Skipped• Blocks, Libraries/Packages
– other modularity features– we’ve had a taste of libraries and packages:
library ieee; …• Configurations
– way to select among multiple architectures• Constants
– like generics, but within one file• File access
– useful for test benches, not synthesizable• Functions, procedures, variables
Preview of Next Tutorial
• Digital Systems Concepts– The FPGA: LEs, buffers and routing, other
resources– Bus interfaces– Register files– Other FPGA resources: clocks, memories,
memory interfaces, multipliers, etc.– Soft- and hard-processors in FPGAs
Summary• 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.
UW ASIC Design Team• www.asic.uwaterloo.ca• reference material
– Accolade VHDL reference (excellent!):http://www.acc-eda.com/vhdlref/
• many of today’s examples came from here– Bryce Leung’s tutorials (UW ASIC website)– Mike Goldsmith’s tutorials (UW ASIC website)– your course notes
• my contact info:Jeff Wentworth, [email protected]