Nanosistemų programavimo kalbos 5 paskaita Sekvencinių schemų projektavimas
Terminai Combinational circuit kombinacinė schema (be atminties elementų) Sequential circuit nuosekli (trigerinė, sekvencinė) schema (su atminties elementais) Latch latch'as, fiksatorius Flip-flop trigeris Clock signal taktinis signalas Hazard nekorektiškas schemos veikimas dėl signalų vėlinimo įtakos Timing sinchronizavimas
Sequential Circuit Design: Principle Outline: Overview of sequential circuits Synchronous circuits Danger of synthesizing asynchronous circuit Inference of basic memory elements Simple design examples Timing analysis Alternative one-segment coding style Use of variable for sequential circuit Overview of sequential circuit Combinational vs sequential circuit Sequential circuit: output is a function of current input and state (memory) Basic memory elements o D latch o D FF (Flip-Flop) o RAM (not possible to derive a portable, device-independent VHDL code to infer a RAM module)
D Latch D latch is a level sensitive memory element, while the D flip-flop (FF) is an edge sensitive memory element Note that for the D latch, next state q* is d when the control signal c (often clock) is high, while q* is q when c is low
D Latch Timing diagram for D-latch -- note that d is sampled and stored on falling edge of c. Since the latch is "transparent" when c is asserted, it may cause racing if a loop exists in the circuit Cannot be used to swap data because of loop Not often used in synthesis because of this
D Flip Flop (FF) The D FF is only activated when the clk signal changes from 0 to 1. Activation implies it samples the value on its d input, stores the value in its memory and propagates the value to its output q
D Flip Flop (FF) D FF has advantages glitches on d do not affect the state of the memory The is no race condition swap circuits actually work D FF disadvantages About twice as large as a D latch Timing behavior of a D FF: T hold T cq T setup Clock-to-q delay (T cq ): Delay required for sampled d value to show up on q
D Flip Flop (FF) Setup time (T setup ): time interval that d must be stable for before the rising edge of clock Hold time (T hold ): time interval that d must be stable for after the rising edge. T hold T cq T setup T cq is corresponds to the propagation delay of a combinational circuit, while T setup and T hold are timing constraints d must be stable for a time interval around clk If d changes during this interval, a setup time or hold time violation occurs and the D FF may enter a metastable state (q is neither a 0 or 1)
The Clock Signal The clock signal plays a key role in sequential circuit design. Systems can be classified according to the clock signal arrangement: Globally synchronous circuit All memory elements (D FFs) are controlled (synchronized) by a common global clock signal (most popular) Globally asynchronous but locally synchronous circuit (GALS) Used in cases in which the components of the design are spread too far apart to allow a single synchronous clock a globally asynchronous circuit results However, the smaller subsystems use a synchronous clock internally Special interface circuits needed between subsystems to ensure proper operation Globally asynchronous circuits No clock is used to coordinate the memory
The Clock Signal Globally asynchronous circuits There are two categories Systems that do not use the clock in a disciplined manner, for example, a ripple counter: clock port of an FF is connected to the q output of previous FF Poor design and not recommended Systems that contain clockless memory components such as the latch or a combinational circuit with feedback loops (asynchronous circuit) Proper design is entirely different to synchronous circuits not recommended for HDL synthesis either Synchronous circuit State registers (state_reg) represent the memory elements Next state logic represent the combinational circuit that determines state_next
Synchronous Circuits Operation is as follows: At the rising edge of the clock, state_next is sampled and stored into the register (and becomes the new value of state_reg) The external inputs and state_reg signals propagate through next-state and output logic to determines the new values of the state_next and output signals At the rising edge of the clock, the new value of state_next is sampled and stored and the process repeats Note that the clock period needs to be large enough to accommodate the propagation delay of the next-state logic, the clock-to-q delay and the setup time of the FFs Advantages of synchronous design A single global clock makes the task of satisfying the timing constraints of a design with of thousands of FFs manageable and doable The synchronous model separates the combinational components from the memory elements, making it possible to treat the combinational part by itself Propagation delay anomalies such as hazards can be dealt with easily by focusing on the worst case timing behavior
Synchronous Circuits Therefore, the synchronous model reduces a complex sequential circuit to a single closed feedback loop and greatly simplifies the design process Types of synchronous circuits Regular sequential circuit State representation, transitions and next-state logic have a simple, regular pattern, i.e. incrementor or shift register Random sequential circuit (FSM) More complicated state transitions and no special relationship between states and their binary representations next-state logic is random Combined sequential circuit Combines regular sequential circuit and an FSM, with FSM acting as control for the sequential circuit Danger of Synthesizing an Asynchronous Circuit Consider the D Latch described earlier We can write VHDL code as follows to represent it
Danger of Synthesizing an Asynchronous Circuit library ieee; use ieee.std_logic_1164.all; entity dlatch is port( ); end dlatch; architecture c: in std_logic; d: in std_logic; q: out std_logic demo_arch signal q_latch: std_logic; of dlatch is
Danger of Synthesizing an Asynchronous Circuit process(c, d, q_latch) if( c= 1 ) then q_latch <= d; else q_latch <= q_latch; end if; end process; q <= q_latch; end demo_arch; Synthesis software will recognize this as the code for a D latch and should infer a predesigned D-latch from the cell library But what if we try to synthesize it from scratch, using simple gates?
Danger of Synthesizing an Asynchronous Circuit Here we see the implementation is combinational except for that the output is looped around as an input Unfortunately, there is a serious timing problem with this circuit Assume all gates have a propagation delay of T and c, d and q are initially 1 What happens when c changes from 1 to 0 at time t 0? From the function table, q should be latched to the value of d ( 1 ) Therefore, output q oscillates at period of 2T 1) At t 0, c changes to 0 2) At t 1, (after delay T), dc and cn change 3) At t 2, (after delay 2T), qcn changes (due to cn) and q changes (due to dc) 4) At t 3, (after delay 3T), q changes (due to qcn) and qcn changes (due to q)
Inference of Basic Memory Elements You should use the following templates to create latches and FFs, so that the predesigned library cells are inferred by the synthesis tools. D Latch Eliminate the else branch to create a latch library ieee; use ieee.std_logic_1164.all; entity dlatch is port( c: d: q: in std_logic; in std_logic; out std_logic
Inference of Basic Memory Elements ); end dlatch; architecture arch of dlatch is -- c and d in sens. list b/c process sens. to both process(c, d) if (c= 1 ) then q <= d; end if; end process; end arch; Positive Edge-Triggered D FF No else branch -- NOTE sensitivity list library ieee; use ieee.std_logic_1164.all;
Inference of Basic Memory Elements entity dff is port( ); end dff; clk: in std_logic; d: in std_logic; q: out std_logic architecture arch of dff is process(clk) -- d not needed b/c process does nothing -- when d changes (unlike latch)
Inference of Basic Memory Elements -- event is true when clk changes, clk= 1 is true when -- NEW value of clk if (clk event q <= d; end if; end process; end arch; Negative Edge-Triggered D FF is 1 -- together means rising edge and clk= 1 ) then -- can also use -- rising_edge(clk) -- if std_logic_1164 incl.... if (clk event and... clk= 0 ) then -- can also use -- falling_edge(clk)
Inference of Basic Memory Elements D FF with Asynchronous Reset No else branch -- NOTE sensitivity list library ieee; use ieee.std_logic_1164.all; entity dffr is port( ); end dffr; clk: in std_logic; reset: in std_logic; d: in std_logic; q: out std_logic
Inference of Basic Memory Elements Architecture arch of dffr is process(clk, reset) if (reset= 1 ) then q<= 0 ; elsif rising_edge(clk) then q <= d; end if; end process; end arch; Register Multiple D FFs with same clock and reset library ieee; use ieee.std_logic_1164.all;
Inference of Basic Memory Elements entity reg8 is port( ); end reg8; clk, reset: in std_logic; d: in std_logic_vector(7 downto 0); q: out std_logic_vector(7 downto 0) architecture arch of reg8 is process(clk, reset) if (reset= 1 ) then q <= (others=> 0 ); elsif (clk event and clk= 1 ) then q <= d; end if; end process; end arch;
Easiest way to create a sequential circuit is to follow the block diagram Build the register Code the next-state and output logic (combinational circuits) D FF with Sync Enable Note that the en is sampled on rising edge of clock If en is 0, or is changing from 0 to 1, FF keeps q If en is 1, or is changing from 1 to 0, FF stores q_next
library ieee; use ieee.std_logic_1164.all; entity dff_en is port( clk: in std_logic; reset: in std_logic; en: in std_logic; d: in std_logic; q: out std_logic ); end dff_en; architecture two_seg_arch of dff_en is signal q_reg: std_logic; signal q_next: std_logic;
-- D FF process(clk, reset) if (reset= 1 ) then q_reg <= 0 ; elsif (clk event and clk= 1 ) then q_reg <= q_next; end if; end process; -- next-state logic q_next <= d when en = 1 else q_reg; -- output logic q <= q_reg; end two_seg_arch;
Toggle (T) FF -- t is sampled at rising edge library ieee; use ieee.std_logic_1164.all; entity tff is port( clk: in std_logic; reset: in std_logic; t: in std_logic; q: out std_logic ); end tff;
architecture two_seg_arch of signal q_reg: std_logic; signal q_next: std_logic; tff is -- D FF process(clk, reset) if (reset= 1 ) then q_reg <= 0 ; elsif (clk event and q_reg <= q_next; end if; end process; clk= 1 ) then -- next-state logic q_next <= q_reg when t= 0 else not(q_reg);
-- output logic q <= q_reg; end two_seg_arch; Free-Running Shift Register (no control signals) Can be used to carry out parallel-to-serial conversion Conceptually, we can re-arrange the FFs into a column and treat them as a single memory block (see below)
Combinational logic Collapse into memory block
library ieee; use ieee.std_logic_1164.all; entity shift_right_register port( is clk, reset: in std_logic; d: in std_logic; q: out std_logic ); end shift_right_register; architecture two_seg_arch of shift_right_register signal r_reg: std_logic_vector(3 downto 0); signal r_next: std_logic_vector(3 downto 0); is -- register process(clk, reset)
if (reset= 1 ) then r_reg <= (others=> 0 ); elsif (clk event and clk= 1 ) r_reg <= r_next; end if; end process; then -- next-state r_next <= d & logic (shift right r_reg(3 downto 1); 1 bit) -- output q <= r_reg(0); end two_seg_arch;
Universal Shift Register Designed to implement 4 ops: parallel load, shift right, shift left, pause library ieee; use ieee.std_logic_1164.all; entity shift_register is port( clk, reset: in std_logic;
ctrl: in std_logic_vector(1 downto 0); d: in std_logic_vector(3 downto 0); q: out std_logic_vector(3 downto 0) ); end shift_register; architecture two_seg_arch of shift_register is signal r_reg: std_logic_vector(3 downto 0); signal r_next: std_logic_vector(3 downto 0); -- register process(clk, reset) if (reset= 1 ) then r_reg <= (others=> 0 ); elsif (clk event and clk= 1 ) then r_reg <= r_next;
end if; end process; -- next-state logic with ctrl select r_next <= r_reg when "00", -- no op r_reg(2 downto 0) & d(0) when "01", -- sft left d(3) & r_reg(3 downto 1) when "10", -- sft rght d when others; -- output q <= r_reg; end two_seg_arch;
Arbitrary Sequence Counter library ieee; use ieee.std_logic_1164.all; entity arbi_seq_counter4 port( is clk, reset: in std_logic; q: out std_logic_vector(2 ); end arbi_seq_counter4; downto 0)
architecture two_seg_arch of arbi_seq_counter4 is signal r_reg: std_logic_vector(2 downto 0); signal r_next: std_logic_vector(2 downto 0); -- register process(clk, reset) if (reset= 1 ) then r_reg <= (others=> 0 ); elsif (clk event and clk= 1 ) r_reg <= r_next; end if; end process; then
-- next-state logic r_next <= "011" when "110" -- output logic q <= r_reg; end two_seg_arch; when "101" when "111" when "000"; -- r_reg="000" r_reg="011" r_reg="110" r_reg="101" r_reg="111" else else else else Free-Running Binary Counter With a max_pulse output: asserted when counter is all library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
entity binary_counter4_pulse is port( clk, reset: in std_logic; max_pulse: out std_logic; q: out std_logic_vector(3 downto 0) ); end binary_counter4_pulse; architecture two_seg_arch of binary_counter4_pulse signal r_reg: unsigned(3 downto 0); signal r_next: unsigned(3 downto 0); is -- register process(clk, reset) if (reset= 1 ) then r_reg <= (others=> 0 );
elsif (clk event and r_reg <= r_next; end if; end process; clk= 1 ) then -- next-state logic r_next <= r_reg + 1; -- output logic q <= std_logic_vector(r_reg); max_pulse <= 1 when (r_reg="1111") 0 ; end two_seg_arch; else Note that it wraps automatically Poor practice may confuse some synthesis tools b/c mod op is not synthesizable: r_next <= (r_reg + 1) mod 16;
RTL schematic of free running binary counter Binary Counter Bells & whistles
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity binary_counter4_feature is port( clk, reset: in std_logic; syn_clr, en, load: in std_logic; d: in std_logic_vector(3 downto 0); q: out std_logic_vector(3 downto 0) ); end binary_counter4_feature; architecture two_seg_arch of binary_counter4_feature signal r_reg: unsigned(3 downto 0); signal r_next: unsigned(3 downto 0); is
-- register process(clk, reset) if (reset= 1 ) then r_reg <= (others=> 0 ); elsif (clk event and clk= 1 ) then r_reg <= r_next; end if; end process; -- next-state logic r_next <= (others=> 0 ) unsigned(d) r_reg + 1 when when when r_reg; -- output logic q <= std_logic_vector(r_reg); end two_seg_arch; syn_clr= 1 else load= 1 else en = 1 else
Decade (mod-10) Counter library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity mod10_counter is port( clk, reset: in std_logic; q: out std_logic_vector(3 ); end mod10_counter; downto 0) architecture two_seg_arch of mod10_counter constant TEN: integer := 10; signal r_reg: unsigned(3 downto 0); signal r_next: unsigned(3 downto 0); -- register is
process(clk, reset) if (reset= 1 ) then r_reg <= (others=> 0 ); elsif (clk event and clk= 1 ) then r_reg <= r_next; end if; end process; -- next-state logic r_next <= (others=> 0 ) r_reg + 1; when r_reg=(ten-1) else -- output logic q <= std_logic_vector(r_reg); end two_seg_arch;
RTL schematic Programmable mod-m Counter Can be modified to use a constant m between "0010" and "1111" library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity prog_counter is port( clk, reset: in std_logic; m: in std_logic_vector(3 downto 0);
q: out std_logic_vector(3 downto 0) ); end prog_counter; architecture two_seg_clear_arch of prog_counter signal r_reg: unsigned(3 downto 0); signal r_next: unsigned(3 downto 0); is -- register process(clk, reset) if (reset= 1 ) then r_reg <= (others=> 0 ); elsif (clk event and clk= 1 ) r_reg <= r_next; end if; end process; then
-- next-state logic r_next <= (others=> 0 ) when r_reg=(unsigned(m)-1) r_reg + 1; else -- output logic q <= std_logic_vector(r_reg); end two_seg_clear_arch; Contains a incrementor, a decrementor and comparator but note that the statement r_reg = (unsigned(m) - 1); can be written as (r_reg + 1) = unsigned(m) architecture two_seg_effi_arch signal r_reg: unsigned(3 downto 0); of prog_counter is signal r_next, r_inc: unsigned(3 downto 0);
-- register process(clk, reset) if (reset= 1 ) then r_reg <= (others=> 0 ); elsif (clk event and clk= 1 ) then r_reg <= r_next; end if; end process; -- next-state logic r_inc <= r_reg + 1; r_next <= (others=> 0 ) when r_inc=unsigned(m) else r_inc; -- output logic q <= std_logic_vector(r_reg); end two_seg_effi_arch;
RTL schematics
Pabaiga Šaltiniai: J. Plusquellic paskaitos Hardware Design with VHDL. Douglas L. Perry. VHDL: Programming by Example, Fourth Edition. V. Jusas, E. Bareiša, R. Šeinauskas. Skaitmeninių sistemų projektavimas VHDL kalba.