module FIFO_CTR title 'fifo controller' " " FIFO CONTROLLER FOR AMS HIT FIFO ----- FAST VERSION " " Stefano Belforte - INFN Pisa " revision history: " 16 Jan 1998 - AND EF1 and EF2. Use HFEF_ to disable HFREN_ " to avoid reading a full fifo in case only one chip is " empty " " Last modify: January 1998 by Stefano Belforte "--------------------------------------------------------------------------- " This FIFO ConTRoller is designed to work with synchronous FIFO CYC4255 " or IDT72215 or compatible. " It controls data flow from the FIFO to the FIFO REGISTER. " The CLOCK signal used here is the same that is sent to the FIFO as RCLK. " This is a 4 state FSM. Two status bits represent the " two posssible situations for the machine task (IDLE or READ=NOT(IDLE)) " and for the FIFO output word (READY or NOT(READY)). " The FSM starts as IDLE and goes into READ status upon POP and " stays there until EE bit is detected in the input word. " At any time the FSM must know (via the READY bit) wether there is " a word ready at the output of the FIFO (resulting from a previous " read operation) waiting to be transferred to the fifo register, or not. " The FSM generates the signal to store the fifo data into the fifo register " FREGE (Fifo REGister Enable) and to read the fifo (HFREN_) as appropriate. " No explicit handshake is sent in answer to the POP request, but the Fifo " Register clock enable (FREGE) can be latched like an additional fifo bit " to signal the presence of new valid data at the fifo register output. " The FIFO empty flag EF_ is used to decide on REN_ assertion on the " next clock cycle. So that all FSM outputs (REN_ and FREGE) " are registerd outputs which are avilable in outputs with the minimum " delay : clock-to-register-output. " We use EF_ as the D to a register whose output is called FULL, then " the equations for REN_ is a function of the FSM status register and of FULL. " REN_ is asserted while the FSM is active (NOT(IDLE)) and FULL is true. " FREGE is a funciont of the FSM status only, and is asserted when " the FSM is READY and in read mode (NOT(IDLE)). " In this way we avoid to use HFEF_ to change HFREN_ during the same clock " cycle, and thus use one clock cycle for each signal passing: one cycle for " EF_ from FIFO to FIFO_CTR inside the INPUT XELD, one cycle for HFREN_ from " the XEPLD to the FIFO. " The FSM state diagram is (note that the output signal REN_ is NOT(REN)):: " " IDLE NOT IDLE (read) " " |--------| |--------| " idle | | POP | S0 | ~idle " ~ready | S2 | --------------> | | ~ready NOT READY " | | |REN=FULL| " |________| |________| " " ^ | ^ " /|\ | /|\ " \ | | " \ FULL| | " EE & NOT(EF_) | |NOT(EF_) " \ | | " \ | | " \ | | " \ | | " \ | | " \ \|/ | " \ v | " " idle |--------| POP |--------| ~idle " ready | | ---------------> | S1 | ready READY " | S3 | |REN=FULL| " | | <--------------- | FREGE | " |________| EE & EF_ |________| " " " Status bits are: [b1,b0] = [IDLE, READY] " with b1=1 meaning IDLE and b1=0 meaning READ " Upon reset the FSM is in state S2=[1,0] " " "-------------------------------------------------------------- "INPUTS CLOCK pin ; "System clock RESET pin ; "INPUT XELD reset (INIT or Power on) TMOD pin ; "Test Mode flag HFEF1_ pin ; "Empty Flag from Hit FIFO1 HFEF2_ pin ; "Empty Flag from Hit FIFO2 "OUTPUT HFQ22 pin ; "End Event bit on Hit FIFO Q bus (bit 22) HPOP pin ; "Hit POP from microsequencer HREVME pin ; "Hit FIFO REad request from VME "OUTPUTS HFREN_ pin ; "Read ENable to FIFO FREGE pin ; "Fifo REGister Enable, clock enable to Fifo Register FSMB0 pin ; "FSM state bit 0 FSMB1 pin ; "FSM state bit 1 "NODES IDLE node; "status register IDLE bit READY node; "status register READY bit FSMINIT node; "FSM initialization NIDLE, NREADY node; "Next status register bits LHREVME node; "latched HREVME FULL NODE; "latched inverted HFEF_ IHFREN_ node; "internal (registered) HFREN_ "Assignements SREG = [IDLE , READY] ; "FSM current status NEXT_S = [NIDLE, NREADY] ; "FSM status in the next clock cycle "Macros "Empty Flag from 2 Hit FIFOS (FIFO's are considered EMPTY if " at least one of the two EF_ is asserted) HFEF_ macro {(HFEF1_ & HFEF2_)}; " "-------------------------------------------------------------- EQUATIONS "------------- combinatorial signal definition ---------------- " state bits for the external world FSMB0 = READY; FSMB1 = IDLE ; " FSM reset FSMINIT = RESET # TMOD ; "------------------------ state machine ------------------------ FULL := HFEF_; FULL.clk = CLOCK; " " the following implements the state machine. It is used in instead of the ABEL " STATE_DIAGRAM construct since in this way we can define the NEXT_S " set which contains the status register for the next clock cycle and can thus " can be used to prepare the D for the REN_ and FREGE flip-flops " WHEN ((SREG==2) & HPOP ) THEN NEXT_S = 0; ELSE WHEN ((SREG==0) & FULL ) THEN NEXT_S = 1; ELSE WHEN ((SREG==3) & HPOP ) THEN NEXT_S = 1; ELSE WHEN ((SREG==1) & !HFEF_ & !HFQ22) THEN NEXT_S = 0; ELSE WHEN ((SREG==1) & !HFEF_ & HFQ22) THEN NEXT_S = 2; ELSE WHEN ((SREG==1) & HFEF_ & HFQ22) THEN NEXT_S = 3; ELSE NEXT_S = SREG; SREG := NEXT_S; " FSM asynch. reset and clock IDLE.pr = FSMINIT ; " starts as idle READY.ar = FSMINIT ; " starts as not ready SREG.clk = CLOCK ; " "-------------------------------------------------------------- " Fast OUTPUT signal to external blocks " REN_ is generated in status READ (states 0 or 1) when the fifo is not FULL, " or whenever VME sends a read request. It is inverted to be low active. IHFREN_ := !( ( ((NEXT_S==0)#(NEXT_S==1)) & HFEF_ ) # ( TMOD & HREVME ) ); IHFREN_.clk = CLOCK; " REN_ is low active, so its reset does a set to 1 !! IHFREN_.pr = RESET; "output HFREN_ to FIFO's is disabled (set to 1) whenever HFEF_ is low HFREN_ = IHFREN_ # !HFEF_ ; " A word is written in fifo register when status is READ and there are " data at the fifo output (READY), state READ.and.READY is state S3, " or whenever VME sends a read request, in which case it has to be one " clock cycle after HFREN_, so we use a latched version of HREVME LHREVME := (HREVME & TMOD); LHREVME.clk = CLOCK; LHREVME.ar = RESET; FREGE := ( (NEXT_S==1) # LHREVME ); FREGE.clk = CLOCK; FREGE.ar = RESET; END