-----------------------------------------------------------------------------
-- |
-- Module  :  ForSyDe.Shallow.SynchronousProcessLib
-- Copyright   :  (c) SAM Group, KTH/ICT/ECS 2007-2008
-- License     :  BSD-style (see the file LICENSE)
-- 
-- Maintainer  :  forsyde-dev@ict.kth.se
-- Stability   :  experimental
-- Portability :  portable
--
-- The synchronous process library defines processes for the
-- synchronous computational model. It is based on the synchronous
-- library "ForSyDe.Shallow.SynchronousLib".
-----------------------------------------------------------------------------
module ForSyDe.Shallow.SynchronousProcessLib(
           fifoDelaySY, finiteFifoDelaySY,
           memorySY, mergeSY, groupSY, counterSY
             ) where

import ForSyDe.Shallow.SynchronousLib
import ForSyDe.Shallow.CoreLib
import ForSyDe.Shallow.Queue
import ForSyDe.Shallow.Memory

-- | The process 'fifoDelaySY' implements a synchronous model of a
-- FIFO with infinite size. The FIFOs take a list of values at each
-- event cycle and output one value. There is a delay of one cycle.
fifoDelaySY     :: Signal [a] -> Signal (AbstExt a)

-- | The process 'finiteFifoDelaySY' implements a FIFO with finite
-- size. The FIFOs take a list of values at each event cycle and
-- output one value. There is a delay of one cycle.
finiteFifoDelaySY   :: Int -> Signal [a] -> Signal (AbstExt a)

-- | The process 'memorySY' implements a synchronous memory. It uses
-- access functions of the type 'Read adr' and 'Write adr value'.
memorySY        :: Int -> Signal (Access a) -> Signal (AbstExt a) 

-- | The process 'mergeSY' merges two input signals into a single
-- signal. The process has an internal buffer in order to prevent loss
-- of data. The process is deterministic and outputs events according
-- to their time tag. If there are two valid values at on both
-- signals. The value of the first signal is output first.
mergeSY         :: Signal (AbstExt a) -> Signal (AbstExt a) 
           -> Signal (AbstExt a)

-- | The process 'counterSY' implements a counter, that counts from
--   min to max. The process 'counterSY' has no input and its output is
--   an infinite signal.
counterSY       :: (Enum a, Ord a) => a -> a -> Signal a

-- | The function 'groupSY' groups values into a vector of size n,
-- which takes n cycles. While the grouping takes place the output
-- from this process consists of absent values.
groupSY :: Int -> Signal a -> Signal (AbstExt (Vector a))

fifoDelaySY xs      =  mooreSY fifoState fifoOutput (queue []) xs

fifoState       :: Queue a -> [a] -> Queue a
fifoState (Q []) xs     =  (Q xs)
fifoState q xs      =  fst (popQ (pushListQ q xs))

fifoOutput      :: Queue a -> AbstExt a
fifoOutput (Q [])   =  Abst
fifoOutput (Q (x:_))    =  Prst x

finiteFifoDelaySY n xs  
   = mooreSY fifoStateFQ fifoOutputFQ (finiteQueue n []) xs

fifoStateFQ :: FiniteQueue a -> [a] -> FiniteQueue a
fifoStateFQ (FQ n []) xs =  (FQ n xs)
fifoStateFQ q xs     =  fst (popFQ (pushListFQ q xs))

fifoOutputFQ :: FiniteQueue a -> AbstExt a
fifoOutputFQ (FQ _ [])    =  Abst
fifoOutputFQ (FQ _ (x:_)) =  Prst x

memorySY size xs    =  mealySY ns o (newMem size) xs
  where 
     ns mem (Read x)    =  memState mem (Read x)
     ns mem (Write x v)     =  memState mem (Write x v)
     o mem (Read x)     =  memOutput mem (Read x)
     o mem (Write x v)  =  memOutput mem (Write x v)


mergeSY xs ys       =  moore2SY mergeState mergeOutput [] xs ys
   where 
     mergeState []  Abst     Abst    = []
     mergeState []  Abst    (Prst y) = [y]
     mergeState []     (Prst x)  Abst    = [x]
     mergeState []     (Prst x) (Prst y) = [x, y]
     mergeState (_:us)  Abst     Abst    = us
     mergeState (_:us)  Abst    (Prst y) = us ++ [y]
     mergeState (_:us) (Prst x)  Abst    = us ++ [x]
     mergeState (_:us) (Prst x) (Prst y) = us ++ [x, y]

     mergeOutput []     = Abst
     mergeOutput (u:_) = Prst u     

groupSY k = mealySY f g s0 
  where
    s0 = NullV
    f v x | (lengthV v) == 0 = unitV x
      | (lengthV v) == k = unitV x 
      | otherwise    = v <: x
    g v _ | (lengthV v) == 0   = Abst
    g v x | (lengthV v) == k-1 = Prst (v<:x)
    g _ _ | otherwise      = Abst
  
counterSY m n = sourceSY f m
  where 
    f x | x >= n    = m
        | otherwise = succ x