--*********************************************************************** -- GLUE3: AMS GLUE -- FSMPKG3 -- Package with FSM's for GLUE3 -- Additionally implements TOPFSM3 which adapts the protocol -- to talk to the AMS: the modification is reflected in the -- double address register and the top architecture --- -- |*******************************************************************| -- | NOTA BENE: THROUGHOUT THE CODE THE LOWERCASE "n" SUFFIX DENOTATES | -- | A LOW ACTIVE SIGNAL. OTHERWISE ALL SIGNALS ARE HIGH ACTIVE. | -- |*******************************************************************| -- -- SB 25-03-1997 -- Adapt for Warp rel. 4.2 (remove unneeded pakages) -- Add comments, improve readibility -- SB 03-04-1997 -- write all FSM's using one-hot-one coding, state diagram constructs -- and parallel registered outputs. -- use Warp options to handle fanout limits, optimise for new FSM's, remove -- all unneeded signals -- SB 30-06-1997 -- modify DOWN FSM to account for synchronized DV_DWN_, DVIN is now delayed -- by one clock cycle. -- SB 03-07-1997 -- invert VME_DV in TOP_FSM before register since DV_TOP will be -- inverted again in output pad to make DV_TOPn --*********************************************************************** package fsmpkg3 is Component Reset3 port( CLK: in BIT; OPCODE_UP: in BIT_VECTOR (3 downto 0); FSM_RESET: out BIT ); end component; Component TopFsm3 port( CLK: in BIT; FSM_RESET: in BIT; DONE_TOP: in BIT; DONE_UP: out BIT; DV_UP: in BIT; DV_TOP: out BIT; AUP_CE: out BIT; TMODE: in BIT; VME_DV: in BIT ); end component; Component UpstreamFsm3 port( CLK: in BIT; FSM_RESET: in BIT; SEL_UP: in BIT; DONE_UP: in BIT; LATCH: in BIT; DV_UP: out BIT; FULL: out BIT; LA,LB: out BIT; EN_A,EN_B: out BIT ); end component; Component DownstreamFsm3 port( CLK: in BIT; FSM_RESET: in BIT; FULL: in BIT; DVIN: in BIT; LATCH: out BIT; DONE: out BIT ); end component; end fsmpkg3; -- Reset generation for FSM's -- All FSM's are synchronously reset whenever OPCODE_UP is different from -- OUTPUT. When the AMS sets the opcpde to OUTPUT this glue will start acting -- at the next clock cycle, while the output opcode is still propagating -- down the glue tree, all the dowstream glues will definitely be reset -- by then, as well as the bottom AM chips that are reset at each event -- by the REsetHandshake - ClearCounter - ClearHitRegister sequence. Entity Reset3 is port ( CLK: in BIT; OPCODE_UP: in BIT_VECTOR (3 downto 0); FSM_RESET: out BIT ); end Reset3; Architecture ArchReset3 of Reset3 is -- Relevant AM opcodes constant OPC_OUTPUT: BIT_VECTOR (3 downto 0) := "0010"; signal ARESET: bit; -- asynchronous RESET begin ARESET <= '1' when (OPCODE_UP /= OPC_OUTPUT) else '0'; sync: process(clk) begin if (CLK'event and CLK='1') then FSM_RESET <= ARESET; end if; end process sync; end ArchReset3; -- TOP FINITE STATE MACHINE (PECULIAR to AMSGLUE alias GLUE3) -- Two-state FSM to dialogue with the AMS -- the two states are FULL and EMPTY, they indicates the status of -- the ADDRESS_UP register. This register is handled as a data driven -- pipe with DV_TOP flag to signal the presence of valid new data in -- ADDRESS_UP. DV_TOP has the same timing as data bits in the register -- (i.e. it is the Q of a flip-flop whose D is the Address_UP clock_enable) -- and is the high active inverse of the output signal DV_TOPn. -- -- State diagram: -- ------------ -- | EMPTY | -- ------------ -- | ^ -- | /|\ -- DV_UP | | DONE_TOP -- \|/ | -- v | -- ------------ -- | FULL | -- ------------ -- -- The FSM outputs are DONE_UP, DV_TOP and AUP_CE. When Address_Up register -- is empty, the FSM is ready to load it and DONE_UP is asserted -- (so DONE_UP = EMPTY), and when the register is full DV_TOP is -- asserted (DV_TOP = FULL = NOT(EMPTY)). AUP_CE (AddressUP ClockEnable) is -- the clock enable for the address_up register, it is asserted at the same -- time the FSM makes the transition form empty to full, it lasts only one -- clock cycle to make sure only the valid data flagged by DV_UP are latched. -- -- One status bit (1=empty, 0=full) is enough, but we will use -- 2 bit with one-hot-one encoding for maximum speed, also this -- allows to identify the two status bits with the outputs, so to have -- them "in parallel output registers". -- Note that ONE-HOT-ONE is needed to force one flip-flop for each -- state, one-hot-one would result in only one flip-flop to be synthetised -- Entity TopFsm3 is port( CLK: in BIT; FSM_RESET: in BIT; DONE_TOP: in BIT; DONE_UP: out BIT; DV_UP: in BIT; DV_TOP: out BIT; AUP_CE: out BIT; TMODE: in BIT; VME_DV: in BIT ); end TopFsm3; Architecture ArchTopFsm3 of TopFsm3 is type top_states is (empty,full); attribute state_encoding of top_states:type is one_hot_one; signal StateTop,NextState: top_states; signal Next_DONE_UP: bit; signal Next_DV_TOP: bit; begin state_diagram: process (StateTop, FSM_RESET, DV_UP, DONE_TOP) begin if (FSM_RESET='1') then NextState <= empty; else case StateTop is when empty => if (DV_UP='1') then NextState <= full; else NextState <= empty; end if; when full => if (DONE_TOP='1') then NextState <= empty; else NextState <= full; end if; end case; end if; end process state_diagram; outputs: process (NextState,TMODE,VME_DV) begin IF (TMODE='0') then if (NextState=empty) then Next_DONE_UP <= '1'; else Next_DONE_UP <= '0'; end if; if (NextState=full) then Next_DV_TOP <= '1'; else Next_DV_TOP <= '0'; end if; ELSE Next_DV_TOP <= not VME_DV; Next_DONE_UP <= '0'; END IF; end process outputs; sync: process(clk) begin if(CLK'event and CLK='1') then StateTop <= NextState; DONE_UP <= Next_DONE_UP; DV_TOP <= Next_DV_TOP; end if; end process sync; AUP_CE <= '1' when (StateTop=empty and DV_UP='1') else '0'; end ArchTopFsm3; -- -- UPSTREAM FINITE STATE MACHINE -- This fsm is to keep register A and B full with good data from the -- down side and send the proper one to address_up register via the -- address multiplexer. The multiplexer is implemented by enabling the one -- between A and B who got loaded first, in order to preserve the order -- in which data have been read from the down side. -- The priority between A and B is fixed: register A is always filled first. -- Writing into the A and B registers is controlled via the two clock -- enables LA and LB. The decision of which register's data go to the -- up side is via the two output enables EN_A and EN_B. -- The up fsm is controlled by inputs LATCH from the down fsm and DONE_UP -- from the top fsm. The down fsm asserts LATCH when there is a new -- valid addres on the address_down bus. The top fsm asserts DONE_UP when -- it is ready for the next address. As in all GLUE protocols, valid data -- are always registered and presented to the next stage as soon as they -- appear, without waiting for a first DONE. -- In general in the GLUE tree the DONE signal must be validated by -- the SEL_, since DONE is common to all the GLUEs at the same level. -- Here this may not be necessary (see following comments in the code). -- The up fsm answers to top and down fsm's via the two signals DV_UP -- and FULL: DV_UP tells the top fsm that there are valid data in output -- to be latched in the address_up register, FULL is a halt flag to the -- down fsm to signal that both A and B registers are full and no more -- data can be accepted. -- -- The top fsm has 5 states that correspond to the various possible -- combination of "fullness" of the address registers A and B: -- empty: both registers empty, no data have been laoded yet -- FA: regA is full, reg B is empty -- FB: regB is full, reg A is empty -- FAB: both registers full, A was loaded first -- FBA: both registers full, B was loaded first -- -- The state diagram is (LATCH fills one register, DONE_UP frees one) -- -- --------- --------- -- | | | | -- | FAB | | FBA | -- | | | | -- --------- --------- -- ^ \ DONE_UP/ ^ -- /|\ \ DONE_UP / /|\ -- | \------\ /------/ | -- | X | -- | / \ | LATCH -- | /------- --------\ | -- | | | | -- LATCH | \|/ \|/ | -- | v v | -- --------- --------- -- | | LATCH & DONE_UP | | -- | FA |<--------------->| FB | -- | |<-----\ | | -- --------- | --------- -- | | | -- DONE_UP | | LATCH | -- | | | DONE_UP -- | --------- | -- | | | | -- \--------->| empty |<-----/ -- | | -- --------- -- -- One-hot-one encoding is chosen again for maximum speed. Outputs are -- placed in parallel registers for speed and fanout whenever posssible. -- Entity UpstreamFsm3 is port( CLK: in BIT; FSM_RESET: in BIT; SEL_UP: in BIT; DONE_UP: in BIT; LATCH: in BIT; DV_UP: out BIT; FULL: out BIT; LA,LB: out BIT; EN_A,EN_B: out BIT ); end UpstreamFsm3; Architecture Upfsm3 of UpstreamFsm3 is type up_states is (empty,FA,FB,FAB,FBA); attribute state_encoding of up_states:type is one_hot_one; signal StateUp,NextState: up_states; signal NextFull: bit; signal NextDV_UP: bit; signal NextEN_A: bit; signal NextEN_B: bit; signal S: bit; -- Use hierarchical ineheritacne of the buffer_gen attribute to make sure that -- even signals created by the synthetiser are buf_reigstered if possible, -- (e.g. fsm state bit registers) even if we do not know their name yet. attribute buffer_gen of Upfsm3:architecture is buf_register; begin -- DONE_UP must be validate by SEL_UP to make sure that this glue -- is really the one the above level wants to talk with. Indeed in the -- AMS there is only one GLUE, so SEL_UP could probably be removed everywere, -- we keep it temporarely in case it results that is needed for the -- the protocol. One change at a time. S <= DONE_UP and SEL_UP; -- In GLUE3 the reset status of Upstream fsm is entered whenever -- OPC is not "output". Whenever the FSM_RESET signal is true (high) the -- FSM goes into the empty state at the next clock cycle. state_diagram: process (StateUp, FSM_RESET, LATCH, S) begin if (FSM_RESET='1') then NextState <= empty; else case StateUp is when empty => if (LATCH='1') then NextState <= FA; else NextState <= empty; end if; when FA => if (LATCH='1') then if (S='1') then NextState <= FB; else NextState <= FAB; end if; else if (S='1') then NextState <= empty; else NextState <= FA; end if; end if; when FB => if (LATCH='1') then if (S='1') then NextState <= FA; else NextState <= FBA; end if; else if (S='1') then NextState <= empty; else NextState <= FB; end if; end if; when FAB => if (S='1') then NextState <= FB; else NextState <= FAB; end if; when FBA => if (S='1') then NextState <= FA; else NextState <= FBA; end if; end case; end if; end process state_diagram; -- now the registered outputs outputs: process (NextState) begin if (NextState /=empty) then NextDV_UP <= '1'; else NextDV_UP <= '0'; end if; if (NextState=FAB or NextState=FBA) then NextFULL <= '1'; else NextFULL <= '0'; end if; if (NextState=FA or NextState=FAB) then NextEN_A <= '1'; else NextEN_A <= '0'; end if; if (NextState=FB or NextState=FBA) then NextEN_B <= '1'; else NextEN_B <= '0'; end if; end process outputs; -- here is the register instantiation sync: process(clk) begin if(CLK'event and CLK='1') then StateUp <= NextState; DV_UP <= NextDV_UP; FULL <= NextFULL; EN_A <= NextEN_A; EN_B <= NextEN_B; end if; end process sync; -- now the combinatorial outputs, these are functions of both state and -- inputs, so can not be registered -- EN_A <= '1' when ((StateUp=FA or StateUp=FAB) ) -- else '0'; -- EN_B <= '1' when ((StateUp=FB or StateUp=FBA) ) -- else '0'; LA <= '1' when ((StateUp=empty or StateUp=FB) and LATCH='1') else '0'; LB <= '1' when ((StateUp=FA) and LATCH='1') else '0'; end upfsm3; -- DOWNSTREAM FINITE STATE MACHINE -- No mode, machine goes into HALT status whenever the general FSM_RESET -- signal is valid and once it is removed the fsm stays there until there -- are valid data on the down side (DVIN true) and the UP FSM is ready -- for data (FULL false). -- There are 3 states only in this machine, which are cycled through one -- at each clock cycle in a regular way. Once the FSM is started by DVIN -- it goes through the full state sequence automatically: -- State_0: is the HALT state, stay here until DVIN is true and FULL is false. -- then go to State_1 at first clock edge. Note that DVIN is delayed -- by one clock cycle with respect to DV_DWN_ (is built from the -- synchronised version of DV_DWN_), so the priority encoder is -- already done when DVIN is detected and address will be ready for -- latch right now.-- At next clock cycle moves to State_0 and checks again for DVIN. -- State_1: now receives address from the down side: assert DONE_ and -- LATCH, at next clock edge the address_down will be latched in -- address_A or address_B by the UP FSM and the address_down will -- be incremented by the GLUE2. Also at next clock edge moves -- automatically State_2 to let GLUE2 acknowledge DONE. -- State_2: it is just "to wait" for the downstream GLUE to receive DONE and -- for the corresponding new state of DV_DWN_ to make it through the -- synchronising logic, so get DVIN up to date. -- -- State diagram: -- -- ----- DVIN & ----- ----- -- | 0 | ------------------> | 1 | ---> | 2 | -->| -- ----- notFULL ----- ----- | -- ^ | -- /|\ | -- |--------------------------------------------| -- -- Output controls are DONE and LATCH: they are true only in State_1 -- -- One-hot-one encoding is chosen again for maximum speed. Outputs are -- placed in parallel registers for speed and fanout. Entity DownstreamFsm3 is port( CLK: in BIT; FSM_RESET: in BIT; FULL: in BIT; DVIN: in BIT; LATCH: out BIT; DONE: out BIT ); end DownStreamFsm3; Architecture Downfsm3 of DownstreamFsm3 is type down_states is (s0, s1, s2); attribute state_encoding of down_states:type is one_hot_one; signal StateDown,NextState: down_states; signal NextDONE: bit; signal NextLATCH: bit; begin state_diagram: process (StateDown, FSM_RESET, DVIN, FULL) begin if (FSM_RESET='1') then NextState <= s0; else case StateDown is when s0 => if (DVIN='1' and FULL='0') then NextState <= s1; else NextState <= s0; end if; when s1 => NextState <= s2; when s2 => NextState <= s0; end case; end if; end process state_diagram; outputs: process (NextState) begin if (NextState=s1) then NextDONE <= '1'; NextLATCH <= '1'; else NextDONE <= '0'; NextLATCH <= '0'; end if; end process outputs; sync: process(clk) begin if(CLK'event and CLK='1') then StateDown <= NextState; DONE <= NextDONE; LATCH <= NextLATCH; end if; end process sync; end DownFsm3;