-- $Source: /evtfs/home/tres/vhdl/ref_design/RCS/rise_count.vhd,v $ -- $Revision: 1.20 $ $Date: 2007/05/02 19:47:06 $ -- Synthesis Template Example, Counting 0,1 sequences on Input Port -- Mike Treseler updated Wed Dec 21 14:32:51 2005 ------------------------------------------------------------------------------- -- Combinational Node = UPDATE the variable first. -- Registered Node = USE the variable first. ------------------------------------------------------------------------------- -- See http://home.comcast.net/~mike_treseler/rise_count.vhd for this -- file. See http://home.comcast.net/~mike_treseler/rise_count.pdf -- for the synthesis results. This example illustrates the design and -- use of procedural components. These "components" consist of a type -- declaration used to "instance" the variable and a procedure to -- update it. ------------------------------------------------------------------------------- -- This tutorial design includes input synchronization, a 0,1 sequence -- detector that enables a roll-over counter. See the single process -- template at the very end of this file. This template calls the top -- procedures: init_regs, update_regs, and update_ports. ------------------------------------------------------------------------------- -- Wed May 2 12:45:11 2007 removed unused use statement library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; ------------------------------------------------------------------------------- entity rise_count is generic (w : positive := 3); port (clock : in std_ulogic; reset : in std_ulogic; watch : in std_ulogic; -- watch for '0', '1' strobe_tp : out std_ulogic; -- detector testpoint retime_tp : out std_ulogic; -- Synchronized input testpoint count : out std_logic_vector(w-1 downto 0) -- number of edges ); end entity rise_count; ------------------------------------------------------------------------------- architecture synth of rise_count is -- no signals required begin one : process(reset, clock) is ------------------------------------------------------------------------------- -- Process declarations for the Template Procedures -- These could be packaged, shown here as a tutorial function now_high (std_arg : std_ulogic) return boolean is -- convert active high bit to boolean begin if std_arg = '1' then return true; else return false; end if; end function now_high; ------------------------------------------------------------------------------- -- RETIME is a four node procedural component for input -- synchronization. It is a variable of type retime_t that is UPDATED -- by the procedure retime declared below. -- USAGE: Declare a variable of the type retime_t for each instance. -- Output options(sequence constraints): -- Registered Node = USE the variable.f3 first -- required in this case -- Unregistered Node = UPDATE the variable first -- would drop a sync stage type retime_t is record f1 : std_ulogic; -- .f1 output covers races only f2 : std_ulogic; -- .f2 output node covers metastable events also f3 : std_ulogic; -- .f3 output covers synthesis register duplication end record; procedure retime (arg_in : in std_ulogic; -- input value update : inout retime_t -- 3 bit shifter ) is begin update.f3 := update.f2; -- f2[DQ]f3 -- \__ -- \ update.f2 := update.f1; -- f1[DQ]f2 -- \__ -- \ update.f1 := arg_in; -- in[DQ]f1 -- Note that reversing the order the statements above would make -- wires instead of registers. end procedure retime; ------------------------------------------------------------------------------- -- RISING is a three node procedural component for edge detection. -- It is a variable of type ck_rise_t that is UPDATED -- by the procedure rising declared below. -- USAGE: Declare a variable of the type retime_t for each instance. -- Output options (sequence constraints): -- Registered Internal Node = USE the .strobe first -- Unregistered Internal Node = UPDATE the variable first -- that is call rising, then use .strobe -- Instructions: Use a variable of the type ck_rise_t as a synchronized -- output. Call the procedure rising *after* such usage to specify -- the input port "arg_in" and the rising variable structure "update". ------------------------------------------------------------------------------- type ck_rise_t is record -- two bit object for edge detection history : std_ulogic; -- history register (private) strobe : std_ulogic; -- output node end record; procedure rising ( arg_in : in std_ulogic; update : inout ck_rise_t ) is -- A three node procedural component for rising edge detection -- Unregistered Internal Node = Call rising, then use .strobe -- .history ___ -- arg_in >--------.--o|>--[DQ]------------------|AND\__ .strobe -- \____________________________|___/ -- purpose: first cut with extra register begin update.strobe := arg_in and update.history; -- history USED first update.history := not arg_in; -- Note that the internal node .history is always registered -- as it is USED first. -- Note that if the two assignments above cannot be reversed. -- If they were reversed, the register would drop out leaving: -- .strobe := (arg_in and not arg_in); -- .strobe := ('0'); -- No gates, no flops! end procedure rising; ------------------------------------------------------------------------------ -- Procedural "Component" Instances variable count_v : unsigned(count'range); -- counter is enabled by a variable rising_v : ck_rise_t; -- 0,1 sequence detector strobe that watches variable retime_v : retime_t; -- a retimed input ------------------------------------------------------------------------------- -- Template Procedures: Always same three names. Contents varies. ------------------------------------------------------------------------------- procedure init_regs is -- init of register variables only -- "regs" may end up as registers or wires (like verilog) begin retime_v := (others => '0'); rising_v := (others => '0'); count_v := (others => '0'); end procedure init_regs; ------------------------------------------------------------------------------- procedure update_regs is begin -- Procedural Block Diagram: -- Write this first, then fill in the declarations above. -- Lets say some procedure rising watches the third stage of -- of an input synchronizer, say retime_v.f3 for a 0,1 sequence: rising (arg_in => retime_v.f3, -- USE the variable retime_v.f3 update => rising_v -- UPDATE the variable rising_v ); -- Say we have a counter, count_v enabled by some detector output, -- say rising_v.strobe: cnt_enable : if now_high(rising_v.strobe) -- USE rising_v then count_v := count_v+1; -- USED then UPDATED on same line end if cnt_enable; -- Finally, a retime procedure to run a three bit shifter named -- retime_v in front of the detector: retime( arg_in => watch, -- entity port value update => retime_v -- UPDATE the variable retime_v ); end procedure update_regs; ------------------------------------------------------------------------------- procedure update_ports is -- wire register variables out to port -- This procedure runs for all clock and reset events. Simple -- assignements from process variables to port are allowed for -- synthesis. Process variables must be intitialized in the -- init_regs procedure above. -- Note that these signal assignments infer a register *only* if -- the variable on the right is combinational, like rising_v.strobe. -- If the variable is already registered, like count_v or -- retime_v.f3, just a wire is inferred to connect the variable -- to the output port. This template style does not allow -- unregistered port outputs. However, variables representing -- combinational nets and may be used anywhere inside the -- process. begin retime_tp <= retime_v.f3; -- let's bring out some testpoints: strobe_tp <= rising_v.strobe; count <= std_logic_vector(count_v); -- wire counter register to port end procedure update_ports; ------------------------------------------------------------------------------- -- Top Process Template -- Always exactly the same: ------------------------------------------------------------------------------- begin -- process template if reset = '1' then init_regs; -- no port init required elsif rising_edge(clock) then update_regs; end if; update_ports; -- will synth port wires ok for reset or clk end process one; end architecture synth; -------------------------------------------------------------------------------