1 / 58

VHDL in digital circuit synthesis (tutorial)

VHDL in digital circuit synthesis (tutorial). dr inż. Miron Kłosowski EA 309 klosowsk@ue.eti.pg.gda.pl. Library declaration. library IEEE; use IEEE.std_logic_1164.all;. all - use all elements of the package. Obligatory IEEE library. std_logic_1164 package usage. Other IEEE packages:

shina
Télécharger la présentation

VHDL in digital circuit synthesis (tutorial)

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. VHDL in digital circuit synthesis (tutorial) dr inż. Miron KłosowskiEA 309 klosowsk@ue.eti.pg.gda.pl

  2. Library declaration library IEEE; use IEEE.std_logic_1164.all; all - use all elements of the package Obligatory IEEE library std_logic_1164 package usage Other IEEE packages: IEEE.std_logic_signed.all IEEE.std_logic_unsigned.all IEEE.std_logic_arith.all std.text_io.all IEEE.numeric_std.all; For example std_logic_vector adder For example: type conversion: integer to std_logic_vector For text file support (for simulation). For example: function std_match for vector compare. Package included by default: std.standard.all contains definitions of basic types like: boolean, bit, character, string, integer, real, natural, positive, bit_vector.

  3. Sample design library IEEE; use IEEE.std_logic_1164.all; entitymultiplexeris port ( signal s : in std_logic; signal x0,x1 : in std_logic_vector(7 downto 0); signal y : out std_logic_vector(7 downto 0) ); end entity multiplexer; architecture data_flow of multiplexer is begin y <= x1 when ( s = '1' ) else x0; end architecture data_flow;

  4. Design simulation – testbench (1) Testbench generates and tests all signals therefore port is not used. Sample TESTBENCH (template is usually generated automatically): LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.std_logic_unsigned.all; USE ieee.numeric_std.ALL; ENTITY fpgalab1_tb_vhd IS END fpgalab1_tb_vhd; ARCHITECTURE behavior OF fpgalab1_tb_vhd IS -- Component Declaration for the Unit Under Test (UUT) COMPONENT projekt1 PORT( clk : IN std_logic; reset : IN std_logic; sw0 : IN std_logic; sw1 : IN std_logic; sw2 : IN std_logic; sw3 : IN std_logic; an : OUT std_logic_vector(3 downto 0); seg : OUT std_logic_vector(7 downto 0); ld0 : OUT std_logic; ld1 : OUT std_logic ); END COMPONENT; Simulated Circuit (UUT) is connected using component declaration mechanism (described in details later). Here declaration of names, types and directions of tested signals is present (signals which would be visible at the pins of synthesized physical FPGA circuit).

  5. Design simulation – testbench (2) Definitions of signals used for component testing – signals are connected to the inputs of UUT and should be initialized. SIGNAL sw0 : std_logic := '0'; SIGNAL sw1 : std_logic := '0'; SIGNAL tst : std_logic := '1'; SIGNAL trx : std_logic := '1'; SIGNAL an : std_logic_vector(3 downto 0); SIGNAL seg : std_logic_vector(7 downto 0); SIGNAL ld0 : std_logic; SIGNAL ld1 : std_logic; signal clk : std_logic := '0'; signal clk_p : std_logic := '0'; signal clk_n : std_logic := '1'; constant PERIOD : time := 10 ns; constant DUTY_CYCLE : real := 0.25; signal reset : std_logic := '1'; BEGIN -- Instantiate the Unit Under Test (UUT) uut: projekt1 PORT MAP( clk => clk, reset => reset, sw0 => sw0, sw1 => sw1, sw2 => tst, sw3 => trx, an => an, seg => seg, ld0 => ld0, ld1 => ld1 ); Definitions of additional signals and constants needed for testing. Initialization of those signals is usually recommended. Real connection to UUT component is created here, PORT MAP describe connections between component signals and testbench signals.

  6. Design simulation – testbench (3) Simple clock generator. Differential clock generator. -- clk_simple <= not clk_simple after PERIOD/2; clk_p <= not clk_p after PERIOD/2; clk_n <= not clk_n after PERIOD/2; clk <= '1' after (PERIOD - (PERIOD * DUTY_CYCLE)) when clk = '0' else '0' after (PERIOD * DUTY_CYCLE); reset <= '0' after 5 ns; tb : PROCESS BEGIN -- Wait 10 ns for global reset to finish wait for 10 ns; -- Place stimulus here sw0 <= '1'; sw1 <= '0'; wait for 20 ns; sw0 <= '0'; wait for 10 ns; sw1 <= '1'; wait; -- will wait forever END PROCESS; Arbitrary duty cycle clock generator. Reset signal deassertion. Process – instructions inside the process are executed sequentailly. Signal values are sequentially modified. Delay. wait instruction without arguments waits forever (without it the process would start again).

  7. Design simulation – testbench (4) Infinite loop instruction tb1 : PROCESS variable x : integer; BEGIN wait for 10 ns; loop x := 1; while x < 11 loop tst <= not tst; wait for x*2 ns; x := x + 1; assert x /= 11 report „Last iteration finished" severity NOTE; end loop; wait until rising_edge(clk); end loop; END PROCESS; tb2 : PROCESS BEGIN wait on clk_p; trx <= transport clk_p after (PERIOD/2)+3 ns; END PROCESS; END; Conditional loop instruction Assert instruction – generates warning and error messages and stops a simulation ‘wait until’ instruction waits for a logic condition to be satisfied (in this example it waits for the rising edge of the clk signal) ‘wait on’ instruction waits for a signal change This assign instruction registers future change of the signal trx. This is an example of a transport delay.

  8. Design simulation – testbench (5)

  9. Signal assignment (concurrent) signal_1 <= signal_2; signal_2 <= signal_3; signal_2 <= signal_3; signal_1 <= signal_2; Sequence of assignments is irrelevant (architecture body is an concurrent instruction area). Is this a problem  ?Signal_1 <= Signal_2; Signal_1 <= Signal_3; Important !!! Resolution function is defined for type std_logic and std_logic_vector. Type std_ulogic is a logic type without resolution function. Using std_logic and std_logic_vector types is recommended. It can be solved using the resolution function  ! Signal_2 Signal_1 Signal_3

  10. Resolution function Resolution function for std_logic: U  X  0  1  Z  W  L  H  -  ---------------------------------   U U U U U U U U U | U |   U X X X X X X X X | X |   U X 0 X 0 0 0 0 X | 0 | U X X 1 1 1 1 1 X | 1 | U X 0 1 Z W L H X | Z | U X 0 1 W W W W X | W | U X 0 1 L W L W X | L | U X 0 1 H W W H X | H | U X X X X X X X X  | - | • Std_logic is a most frequently used logic type. It can be assigned 0 i 1 values and more: • Z high impedance state (for top level signals only); • - don't care (for example used by function std_match); • Other values are useful in simulation: • U uninitialized (at the beginning of simulation); • X undefined strong signal; W undefined weak signal; • L, H week 0 and 1 signals.

  11. Vectors (1) • Sample vector (one-dimensional array): • signal x: std_logic_vector(7 downto 0); • x <= "11001010"; • x(7) <= '1'; x(6) <= '1'; x(5) <= '0'; x(4) <= '0'; • x(3) <= '1'; x(2) <= '0'; x(1) <= '1'; x(0) <= '0'; • Vector with rising index:signal y: std_logic_vector(0 to 7); • y <= "11001010"; • y <= x; • Previous assignment automatically perform 8 one-bit assignments: • y(0) <= x(7); y(1) <= x(6); y(2) <= x(5); y(3) <= x(4); • y(4) <= x(3); y(5) <= x(2); y(6) <= x(1); y(7) <= x(0); • Vector assignment is possible when the number and type of vector’s elements is the same in RHS and LHS.

  12. Vectors (2) • Because many library functions use vectors with MSB on the left side it is recommended to use downto indexing (index 0 is a LSB)signal q: std_logic_vector(1 downto 0); • You can address smaller subvectors using parenthesis: • x(7 downto 6) <= q; • x(5 downto 3) <= y(2 to 4); • You cannot change index direction of the vector, assignment:x(5 downto 3) <= y(4 downto 2); is not correct!!! • You can create vectors from logic signals or smaller vectors using the concatenation operator &:signal s: std_logic; • x <= "10" & q & '1' & q & '0'; • vec_from_sig <= s & s & s & s & s & s & s & s;

  13. Vectors (3) • You can create vectors using aggregates: • x <= ('1', '0', q(1), q(0), '1', q(1), q(0), others => '0'); • x <= (6=>'0', 7=>'1', 4=>q(0), 5=>q(1), 0=>'0', 2=>q(1), 1=>q(0), others => '1'); • zero_vector <= ( others => '0'); • vec_from_sig <= ( others => s ); • vec_from_sig1 <= ( s1, s2, s3, s4, others => s ); • vec_from_sig2 <= ( 0=>'1', 6 downto 2 => s2, 7|1 => s1 ); Logical operations on vectors:signal temp: std_logic_vector(7 downto 0); • temp <= ( others => s ); • y <= ( temp and x1 ) or ( not temp and x0 ); • You can perform following logic operations: not, and, or, nand, nor, xor, xnor. • Logic operation is performed on bits taken from the same position of operand vectors. Result is placed in the same position in the LHS vector. • Vectors used for the operation must have the same length. Word ‘others’ can be used only at the end of the aggregate.

  14. Sample design (2) library IEEE; use IEEE.std_logic_1164.all; entitymultiplexeris port ( signal s : in std_logic; signal x0,x1 : in std_logic_vector(7 downto 0); signal y : out std_logic_vector(7 downto 0) ); end entity multiplexer; architecture logic of multiplexer is signal temp : std_logic_vector(7 downto 0); begin temp <= ( others => s ); y <= ( temp and x1 ) or ( not temp and x0 ); end architecture logic;

  15. Arithmetic operations on vectors • You can perform arithmetic operations not only on integer types. Std_logic_vector type can be also used for this task but only when one the following packages are used: • use IEEE.std_logic_unsigned.all; • use IEEE.std_logic_signed.all; • If in the same design entity signed and unsigned vectors are present you can use the signed and unsigned vector types defined in package IEEE.std_logic_arith • You can also used the IEEE.std_logic_signed.all package for all vectors but prefix the unsigned vectors with ‘0’ & to make them non negative. • Carry in and out synthesis (in addition and subtraction output vector length is equal to the longest input vector): • signal res, x, y: std_logic_vector(7 downto 0); • signal a: std_logic_vector(8 downto 0); • signal cin, cout : std_logic; • a <= ('0' & x) + ('0' & y) + cin; • res <= a(7 downto 0); • cout <= a(8);

  16. Type conversion (examples) • Frequently used type conversion functions: • Packages IEEE.std_logic_unsignedandIEEE.std_logic_signedcontain conversion function from type Std_logic_vector to type Integer: • CONV_INTEGER(ARG: STD_LOGIC_VECTOR) • Package IEEE.std_logic_arithcontains following conversion functions:- Integer to Std_logic_vector (you have to specify the size of the vector): CONV_STD_LOGIC_VECTOR(ARG: INTEGER; SIZE: INTEGER)- Integer to Unsigned/Signed: • CONV_UNSIGNED(ARG: INTEGER; SIZE: INTEGER) • CONV_SIGNED(ARG: INTEGER; SIZE: INTEGER) • - Unsigned/Signed to Integer: • CONV_INTEGER(ARG: UNSIGNED) • CONV_INTEGER(ARG: SIGNED) • - Std_logic_vector extension to length size: • EXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) • - Std_logic_vector signed extension to length size:SXT(ARG: STD_LOGIC_VECTOR; SIZE: INTEGER) • Package IEEE.std_logic_1164 contains conversion functions for Bit_Vector: • TO_BITVECTOR(S: STD_LOGIC_VECTOR) • TO_STDLOGICVECTOR(B: BIT_VECTOR)

  17. Processes • Processes are used for behavioral description of the hardware. Instructions inside the process are executed sequentially to calculate the values of signals assigned in the process. • architecture behavioral of multiplexer is • begin • mux: process (x0, x1, s) is • begin • if s = '1' then • y <= x1; • else • y <= x0; • end if; • end process mux; • end architecture behavioral; Sensitivity list Optional label

  18. Combinatorial processes (1) • In processes describing combinatorial logical circuits the body of the process (the algorithm) should be started only at the change of the signals present on the sensitivity list. • If the process has to describe the behavior of combinatorial circuit (i.e. Logic circuit without the latches or flip-flops) two conditions must be satisfied: • 1. All the input signals of the logic circuit must be present on the sensitivity list of the process. • 2. All the output signals of the logic circuit must be assigned a value at least once in every possible flow of the algorithm used in the body of the process. • Good process example: • mux: process (x0, x1, s) is • Begin • y <= x0; • if s = '1' then • y <= x1; • end if; • end process mux; Bad process example: mux: process (s) is begin if s = '1' then y <= x1; end if; end process mux;

  19. Combinatorial processes (2) • When there is a possibility that output signal is not assigned during the process run as the result of the synthesis a latch will be inferred – the process is no longer combinatorial. • You can use for example ‘else’ construct to avoid this. • Another method is to use default value for all output signals (see below): • mux: process (x0, x1, s) is • begin • y <= x0; • if s = '1' then • y <= x1; • end if; • end process mux; Signal assignment in the process is not performed at the same time when the <= instruction is found. This assignment is rather programmed to be performed later – when the process finishes the algorithm and stops waiting for signals change. Therefore if more than one assignment to the signal is found during the process run only the last assignment is valid. All the programmed assignments are finalized at the same time when the process stops. Read value of the signal cannot be changed during the process run – when the signal is read it always returns the same value (even when the new value has been asserted).

  20. Combinatorial processes (3) • It is possible that output signal of the process is used at the same time as input signal of the same process. It is of course not allowed to create the combinatorial loop in any way – but you can create the chain logic. • In this situation remember that output signals which are used as an input also should satisfy both conditions from the previous page (sensitivity list and obligatory assignment): • process(a, b, c, x, y) is • begin • x <= a and b; • y <= x or c; • z <= y xor a; • end process; • Delta cycles for process execution: • t=0 ns (a=0, b=1, c=0, x=0, y=0, z=0) • t=1 ns (a=1, b=1, c=0, x=0, y=0, z=0) • t=1 ns + 1d (a=1, b=1, c=0, x=1, y=0, z=1) • t=1 ns + 2d (a=1, b=1, c=0, x=1, y=1, z=1) • t=1 ns + 3d (a=1, b=1, c=0, x=1, y=1, z=0) • Sometimes process is started several times because the input signal has been changed during process execution (delta cycles). In this situation last assignment to the output signal along all the delta cycles is valid. • Interesting property: different signals can be assigned in any sequence in the process. • Remember that you cannot assign the same signal in different processes without activating the resolution function (which is usually prohibited during synthesis).

  21. Variables (1) • Signals are used to communicate between the process and the rest of the system (concurrent). But to create algorithms inside the process you will need variables. • Variables are defined at the beginning of the process (just before ‘begin’) and they are visible within the process only. • Variables preserve its value between process runs (they can model the memory). • Variables change at the same time when the variable assignment is found (they behave like you would expect in a software programming language). • process(a, b, c) is • variable x,y:std_logic_vector(7 downto 0); • begin • x := a and b; • y := x or c; • z <= y xor a; • end process; • Delta cycles for process execution: • t=0 ns (a=0, b=1, c=0, x=0, y=0, z=0) • t=1 ns (a=1, b=1, c=0, x=0, y=0, z=0) • t=1 ns + 1d (a=1, b=1, c=0, x=1, y=1, z=0) Contrary to signals, different variables must be assigned in the proper sequence – like in a software programming language. When you exchange the first line with the second the result will be different: (x=1, y=0, z=1)

  22. Variables (2) • You can assign the initial value to the variable: • variable x: std_logic_vector(7 downto 0) := "00100010"; • variable i: integer range 0 to 7 := 4; • The initial value is assigned to the variable only at the beginning of the synthesis or simulation. It means that if you want to assign the initial value every time the process is started you have to do it in the process body just after the ‘begin’ word. • Be careful – when you use the variable’s value before you assign the initial value to it you read the value from the previous process execution. This creates a memory element (usually latch).

  23. Sequential processes (1) • Processes can be used to describe sequential circuits if they use signals or variables as a memory. • signal memory – if signal assertion is not continuous but depends on input signals’ states (for example if you forgot about default value assertion like in the example below). • variable memory – if variable is not initialized at the beginning of the process and contents of the variable from previous process run is used. • Sequential processes use memory elements available in the target FPGA (FF, latches, etc.) – you cannot build them using gates. It is important to use strict design rules to achieve synthesizable sequential processes. • Example of sequential process (q is not asserted continuously): • latch: process (ena, d) is • begin • if ena = '1' then • q <= d; • end if; • end process latch; D-latch. When the ena signal is active q output is connected to the d input, when ena is inactivated q output is frozen.

  24. Sequential processes (2) • Latches are not used frequently, but they are available in most FPGAs. • Usually latch synthesis is caused by an error (for example: not asserting default value to the output signal in combinatorial process). Synthesizer software usually warns about latches: „Warning: latch inferred ... ” • Classic method to build sequential circuits is to use edge-triggered flip-flops. • Recall all the properties of the synchronous digital circuits, we will use this design paradigm in the VHDL and FPGAs. • Edge triggered D-type flip-flop: • dff: process (clk) is • begin • if clk = '1' and clk'event then • q <= d; • end if; • end process dff; D-type flip-flop (rising edge triggered). If clk logic value changes, value of the attribute ‘event of the clk signal is set to the ‘1’ for the moment. If clk changes to ‘1’ (i.e. rising edge occurred) the signal value from the d input is transferred to the q output, and q is frozen till the next clk edge. '0'for falling edge

  25. Sequential processes (3) ’event attribute detects every change of the signal, it is suggested to use rising_edge() or falling_edge() functions which detect only changes from ‘0’ to ‘1’ or ‘1’ to ‘0’ respectively. Those functions do not detect changes between other std_logic type’s values like ‘U’,’X’,’Z’, etc. dff: process (clk) is begin if rising_edge(clk) then q <= d; end if; end process dff; dff: process (clk) is begin if falling_edge(clk) then q <= d; end if; end process dff; Synchronous circuit clocked with rising / falling edge of the clock: circuit_name: process (clock) is begin if rising/falling_edge(clock) then .. –- Sequential description of .. –- the digital synchronous circuit, .. –- all signals assigned here are .. -- synthesized as D-type flip-flops’ .. -- outputs. .. –- All logic expressions, conditionals, .. -- etc. are synthesized as combinatorial .. -- logic driving D inputs of flip-flops. end if; end process circuit_name;

  26. Sequential processes (4) • Usually flip-flops in FPGAs are designed with asynchronous reset and set inputs. • drff: process (clk, rst) is • begin • if rst = '1' then • q <= '0'; • elsif rising_edge(clk) then • q <= d; • end if; • end process drff; • dsff: process (clk, set) is • begin • if set = '1' then • q <= '1'; • if rising_edge(clk) then • q <= d; • end if; • end process dsff; Synchronous circuit clocked with rising / falling edge of the clockwith asynchronous reset input: circuit_name: process (clock, reset) is begin if reset = '1' then -- or '0' sig1 <= "00110"; sig2 <= const; .. –- Values asserted to flip-flops .. –- when reset is active. .. –- Must be constant because .. –- asynchronous load of the signal .. –- is not usually supported. elsif rising/falling_edge(clock) then .. -- Sequential description of .. –- the digital synchronous circuit: sig1 <= ... sig2 <= ... end if; end process circuit_name;

  27. Sequential processes (5) • Global reset of entire system should be performed with disabled clock. When clock is running some flip-flops can miss a clock when the reset signal deassertion is delayed because of signal propagation. • Using the hardware reset input of the FPGA (PROG input in Xilinx) is recommended (use initial values of the signals). • Never drive asynchronous set/reset from combinatorial logic – it can contain hazards and therefore spikes are possible – use direct output of the flip-flops or use synchronous reset. • Avoid suggesting clock gating in process description (it is usually not supported), rather use synchronous clock enable: • -- clock gating process !!! • dceff: process (clk, rst) is • begin • if rst = '1' then • q <= '0'; • elsif clk_ena = '1' then • if rising_edge(clk) then • q <= d; • end if; • end if; • end process dceff; Synchronous reset and clock enable: circuit_name: process (clock) is begin if rising/falling_edge(clock) then if sync_reset=‘1’ then q <= ‘0’; elsif clock_enable=‘1’ then q <= ..... end if; end if; end process circuit_name;

  28. Initial values of signals • You can assign initial value to the signal: • signal x: std_logic_vector(7 downto 0) := "00100010"; • signal i: integer range 0 to 7 := 4; • When the signal with initial value is used as the output of the sequential process (i.e. it represents the flip-flop) the initial value will be assigned to the flip-flop during the configuration process of the FPGA. • Most FPGAs have got the flip-flop initialization during configuration functionality. • When the initial value is not defined the flip-flop will be set to ‘0’ (Xilinx FPGAs’ property).

  29. Conditional instruction (1) In processes conditional instruction execution is performed using following reserved words: if, then, elsif, else, end if. See example below: -- signal s:std_logic_vector(2 downto 0); -- signal y:std_logic_vector(1 downto 0); priority_encoder: process (s) is begin if s(2) = '1' then y <= "11"; elsif s(1) = '1' then y <= "10"; elsif s(0) = '1' then y <= "01"; else y <= "00"; end if; end process priority_encoder;

  30. Case instruction (1) Expression after the ‘case’ word is calculated and then instructions assigned to the calculated value are executed. All possible expression values must be enumerated. If it is impossible or difficult use word ‘others’ (especially needed for std_logic_vector type). -- signal s:std_logic_vector(2 downto 0); -- signal y:std_logic_vector(1 downto 0); priority_encoder: process (s) is begin case s is when "111" | "110" | "101" | "100" => y <= "11"; when "011" | "010" => y <= "10"; when "001" => y <= "01"; when others => y <= "00"; end case; end process priority_encoder;

  31. Case instruction (2) For scalar and enumeration types it is allowed to use ranges (to, downto). It is allowed to use many instructions in one choice but at least one instruction must be used (it may be null instruction). After ‘when’ only constants or constant expressions can be used. -- signal s:std_logic_vector(2 downto 0); -- signal y:std_logic_vector(1 downto 0); -- constant jeden:integer := 1; priority_encoder: process (s) is begin y <= "10"; case CONV_INTEGER(s) is when 7 downto 4 => y <= "11"; if s = 5 then z <= 123; end if; when 3 downto jeden + 1 => null; when jeden => y <= "01"; when others => y <= "00"; end case; end process priority_encoder; Null instruction

  32. Loop instruction (1) • Loop instruction is used for easy synthesis of many similar elements. • Synthesizable loop must have limited number of iterations. • While loop is executed when condition after ‘while’ word is true. • While and For loops can be broken using ‘exit’ instruction. • priority_encoder: process (s) is • variable i:integer; • begin • i := 2; • y <= "00"; • L1: while i >= 0 loop • if s(i) = '1' then • y <= CONV_STD_LOGIC_VECTOR(i+1, 2); • exit L1; • end if; • i := i - 1; • end loop L1; • end process priority_encoder;

  33. Loop instruction (2) • It is not obligatory to define the iteration variable in the For loop. • Synthesizable loop must have limited number of iterations. • You can use 'range attribute to define the loop iteration range. • bit_counter: process (s) is • variable num_bits:integer range 0 to s'length; • begin • num_bits := 0; • L1: for i in s'range loop • if s(i) = '1' then • num_bits := num_bits + 1; • end if; • end loop L1; • q <= num_bits; • end process bit_counter;

  34. Loop instruction (3) • Use the ‘next’ instruction to brake single iteration without exiting the loop – just next iteration is started. • Synthesizable loop must have limited number of iterations. • -- signal s:std_logic; • -- signal crc_in, crc_out:std_logic_vector(31 downto 0); • crc32_logic: process (s, crc_in) is • constant coef:std_logic_vector(31 downto 0) := "0000_0100_1100_0001_0001_1101_1011_0111"; • variable tmp:std_logic; • begin • for i in 0 to 31 loop • if i = 0 then • tmp := crc_in(31); • else • tmp := crc_in(i-1); • end if; • crc_out(i) <= tmp; • if coef(i) = '0' then • next; • end if; • crc_out(i) <= tmp xor s; • end loop; • end process crc32_logic; c(x) = 1 + x + x2 + x4 + x5 + x7 + x8 + x10 + x11 + x12 + x16 + x22 + x23 + x26 + x32

  35. Shift registers • Using sll, srl, sla, sra, rol, ror operators for shift registers synthesis is not recommended (those operators work for bit_vector type only). • Below a recommended method of shift register synthesis is presented (16-bit right and left shift registers with serial input/output and parallel load). Rotating registers can be synthesized in the same way. • shift_regs: process(clk, rst) • begin • if rst = '1' then • reg_l <= (others => '0'); • reg_r <= (others => '0'); • elsif rising_edge(clk) then • if load = '1' then • reg_l <= data_l; • reg_r <= data_r; • else • serial_data_out_l <= reg_l(15); • reg_l(15 downto 1) <= reg_l(14 downto 0); • reg_l(0) <= serial_data_in_l; • serial_data_out_r <= reg_r(0); • reg_r(14 downto 0) <= reg_r(15 downto 1); • reg_r(15) <= serial_data_in_r; • end if; • end if; • end process;

  36. Clocks in FPGA • Clocks in FPGAs have to be designed carefully: • Use one clock in the design if possible. • Use external clock or generate it using single divider. • When using divider remember to generate clock directly from FF output not from combinatorial logic! • If you need more clock domains use Digital Clock Managers to generate needed clocks and keep them synchronous. • Remember that clock resources are limited. • If you need clock domains from independent clock sources remember to carefully design the data transfer between those clock domains (use FF synchronizers, asynchronous FIFO, two-port memories etc.).

  37. State machines (1) • Moore and Mealy state machines can be easily implemented in VHDL. • Blue blocks are implemented using sequential synchronous processes. • Orange blocks are implemented using combinatorial processes. • Two orange blocks can be implemented in one combinatorial process.

  38. State machines (2) • To synthesize state variable enumerated type is usually used: • type StateType is (idle, operate, finish); • signal present_state, next_state : StateType; • It is possible to change the default state representation:- globally using synthesizer options, • locally using attributes of state variable (Xilinx example): • attribute fsm_encoding: string; • attribute fsm_encoding of present_state: signal is "compact"; • -- "{auto|one-hot|compact|gray|sequential|johnson|user}" • It is possible to use user defined state representation (for fsm_encoding = user):type statetype is (ST0, ST1, ST2, ST3); • attribute enum_encoding of statetype : type is "001 010 100 111"; • signal state1 : statetype; • signal state2 : statetype;

  39. State machines (3) comb: process (present_state, go, brk, cln, rdy) is begin case present_state is when idle => if (go = '1') then next_state <= operate; else next_state <= idle; end if; power <= '0'; direction <= '0'; when operate => if (brk = '1') then next_state <= idle; elsif (cln = '1') then next_state <= finish; else next_state <= operate; end if; power <= '1'; direction <= '0'; when finish => if (rdy = '1') then next_state <= idle; else next_state <= finish; end if; power <= '1'; direction <= '1'; end case; end process comb; -- Moore state machine -- example type StateType is (idle, operate, finish); signal present_state : StateType; signal next_state : StateType; seq: process (reset, clk) is begin if (reset = '1') then present_state <= idle; elsif rising_edge(clk) then present_state <= next_state; end if; end process seq;

  40. State machines (4) comb: process (present_state, go, brk, cln, rdy, emergency_off) is begin -- default value to avoid latches: next_state <= present_state; case present_state is when idle => if (go = '1') then next_state <= operate; end if; power <= '0'; direction <= '0'; when operate => if (brk = '1') then next_state <= idle; elsif (cln = '1') then next_state <= finish; end if; power <= not (emergency_off or brk); direction <= '0'; when finish => if (rdy = '1') then next_state <= idle; end if; power <= not emergency_off; direction <= '1'; end case; end process comb; -- Mealy state machine -- example type StateType is (idle, operate, finish); signal present_state : StateType; signal next_state : StateType; seq: process (reset, clk) is begin if (reset = '1') then present_state <= idle; elsif rising_edge(clk) then present_state <= next_state; end if; end process seq;

  41. State machines (5) • synchronous output Mealy state machine • Blue blocks are implemented using sequential synchronous processes. • Orange blocks are implemented using combinatorial processes. • It is possible to synthesize synchronous output Mealy machine in one sequential process because machine’s output is taken directly from the FF outputs.

  42. State machines (6) case fsm_state is when idle => if (go = '1') then fsm_state <= operate; power <= '1'; end if; when operate => if (brk = '1') then fsm_state <= idle; power <= '0'; elsif (cln = '1') then fsm_state <= finish; direction <= '1'; end if; when finish => if (rdy = '1') then fsm_state <= idle; power <= '0'; direction <= '0'; end if; end case; end process sync_mealy; -- synchronous output Mealy-- state machine example -- (coded in single process) type StateType is (idle, operate, finish); signal fsm_state : StateType; sync_mealy: process (reset, clk) is begin if reset = '1' then fsm_state <= idle; power <= '0'; direction <= '0'; elsif rising_edge(clk) then

  43. State machines (7) • Forbidden states • Usually state machines are not synthesized to automatically get out of forbidden states. For mission-critical systems it is possible to enable special option in synthesizer to enable safe machine synthesis (but usually that means much larger transition logic and slower clock). • Other methods for safe state machine synthesis: • 1. Use direct state encoding (use user defined states or use std_logic_vector for state definition) and specify behavior of the machine for all possible (valid and invalid) states. • 2. Add logic for detection of invalid states which triggers reset.

  44. State machines (8) -- Example of direct state encoding: signal present_state, next_state : std_logic_vector(2 downto 0); constant idle : std_logic_vector(2 downto 0) := "000"; constant prepare : std_logic_vector(2 downto 0) := "001"; constant operate : std_logic_vector(2 downto 0) := "010"; constant finish : std_logic_vector(2 downto 0) := "100"; constant failure : std_logic_vector(2 downto 0) := "111"; -- specify behavior for forbidden states: when others => next_state <= idle; -- you can easily revert to optimal (not safe) version of machine: when others => next_state <= "---";

  45. State machines (9) -- Detection of forbidden states -- for state machines with one-hot state encoding: idl <= state = idle; prepar <= state = prepare; operat <= state = operate; finis <= state = finish; failur <= state = failure; inv <= (idl and (prepar or operat or finis or failur)) or (prepar and (operat or finis or failur)) or (operat and (finis or failur)) or (finis or failur) or (not (idl or prepar or operat or finis or failur)); .... if (inv = '1') then state <= idle; else .... ....

  46. State machines (10) • How to avoid entering forbidden or wrong state ? • Most common causes of state machine failures: • Clock frequency is too high (reduce critical path delay or clock frequency). • Signals entering state machine are not synchronous to the machine’s clock (signals generated from external devices like pushbuttons, sensors, interrupt lines, busses are usually asynchronous). • Different propagation delays of signals inside the combination logic can cause the asynchronous signal change not to achieve all the FF inputs before active clock edge.

  47. State machines (11) How to avoid entering forbidden or wrong state ? To avoid wrong FF operation you have to synchronize the input signal with the local clock domain. To achieve that you have to send the asynchronous signal through a pipe of two FFs. One FF is not enough because the metastability event in FF can occur. If you send multibit (vector) signals in this way use Gray coding or use any other method for error checking.

  48. Constants and aliases • Constants can be defined inside entities, architectures, processes and packages: • constant x: std_logic_vector(7 downto 0) := "00100010"; • constant y: std_logic_vector(7 downto 0) := ( others => '1'); • constant i: integer := 4; • type state_type is (clear, initiate, run, stop); • constant state_stop: state_type := stop; • Constants are useful for design configuration. You can define the size of the busses, counters, etc. • Alias names can be assigned to a part of the vector to make a partial vector access easier: • signal iw: std_logic_vector(28 downto 0); • alias opcode: std_logic_vector(4 downto 0) is iw(28 downto 24); • alias src: std_logic_vector(7 downto 0) is iw(23 downto 16); • alias dst: std_logic_vector(7 downto 0) is iw(15 downto 8); • alias arg: std_logic_vector(3 downto 0) is iw(7 downto 4); • alias option: std_logic_vector(2 downto 0) is iw(3 downto 1); • alias reserved: std_logic_vector(3 downto 0) is iw(3 downto 0);

  49. Attributes • Attributes can be defined for entities, architectures, types and signals. • type cnt is integer range 0 to 127; • type state is (idle, start, stop, reset); • type word is array(15 downto 0) of std_logic; • Sample attributes predefined for types and signals: 'left 'right 'high 'low 'length • cnt'left = 0; state'left = idle; word'left = 15; • cnt'right = 127; state'right = reset; word'right = 0; • cnt'high = 127; state'high = reset; word'high = 15; • cnt'low = 0; state'low = idle; word'low = 0; • cnt'length = 128; state'length = 4; word'length = 16; • Sometimes the 'range attribute can be useful – it reveals the range and direction of the vector indexing, for example: word'range = 15 downto 0; • Another useful attribute 'event allows detection of a signal change. It can be used for synchronous circuits synthesis. • 'pos attribute returns the position the argument holds on the enumerated type list, for example: state'pos(start) = 1; character'pos('A') = 65; • 'val attribute is for the reverse operation, for example: state'val(2) = stop; character'val(66) = 'B'; • 'pos and 'val attributes can be used for character to ASCII code conversion and for reverse operation.

  50. 3-state buffers implementation 3-state buffers can be implemented on the external interface signals of the FPGA only. These buffers can be used for a bidirectional communication with external ICs.For 3-state buffers use a combinatorial process and a metalogic value ‘Z’: -- signal i,o,ena:std_logic; process (i,ena) is begin if ena = '1' then o <= i; else o <= 'Z'; end if; end process; You can also use a conditional assignment: -- signal i,o:std_logic_vector(127 downto 0); -- signal ena: std_logic; o <= i when ena = '1' else 'Z';

More Related