package ActionSeq( actionSeq, ActionSeq(..), ActionList, ActionJoin(..), aJoin, actionSeqBreak, mkActionSeq, SeqList, seqOfActionSeq) where import List import Vector infixr 15 |> --@ \subsubsection{ActionSeq} --@ -- {\te{ActionSeq}} is an interface type with a field called -- {\te{start}} of type {\te{Action}}. --@ --@ {\te{ActionSeq}} allows you to simplify the description of a state --@ machine. For example, suppose you had a module with an interface to --@ load some data and, after loading, you simply wanted to sequence --@ through 5 actions. Instead of explicitly coding the state and writing --@ the (boring) rules to transition from one state to the next, you could --@ simply define the following in your module: --@ --@ \BBS --@ s :: ActionSeq --@ s <- actionSeq ( {\rm\emph{action$_1$}} |> $\cdots$ |> {\rm\emph{action$_n$}} ) --@ \EBS --@ \index{"|>@{\verb'"|>'} (\te{ActionSeq} interface method)|textbf} --@ --@ and then call {\te{s.start}} to kick off the state sequence. The --@ compiler will work out all the states for you and prevent --@ {\te{s.start}} from being called until it has sequenced through all --@ the actions. The {\qbs{|>}} operator combines actions into a suitable --@ list of actions for {\te{actionSeq}}. --@ --@ \index{ActionList@\te{ActionList} (\te{ActionSeq} type)|textbf} --@ The argument to \te{actionSeq} is an \te{ActionList}, which is simply --@ a list of actions. --@ \begin{libverbatim} --@ typedef Vector#(n, Action) ActionList #(type n); --@ \end{libverbatim} type ActionList n = Vector n Action -- A special "cons" operation that can be used without nil. class ActionJoin a c | a -> c where (|>) :: Action -> a -> c instance ActionJoin Action (ActionList 2) where (|>) x y = cons x (cons y nil) instance (Add 1 n m) => ActionJoin (ActionList n) (ActionList m) where (|>) x xs = cons x xs aJoin :: (ActionJoin a c) => Action -> a -> c aJoin = (|>) --@ \index{ActionSeq@\te{ActionSeq} (interface type)|textbf} --@ \index{start@\te{start} (\te{ActionSeq} interface method)} --@ \index{start@\te{done} (\te{ActionSeq} interface method)} --@ The \te{ActionSeq} interface can be used to start the sequence --@ and to test if it is done. --@ \begin{libverbatim} --@ interface ActionSeq; --@ method Action start(); --@ method Bool done(); --@ endinterface: ActionSeq --@ \end{libverbatim} interface ActionSeq = start :: Action done :: Bool checkDone :: Action type RegB k = Reg (Bit k) --@ \index{actionSeq@\te{actionSeq} (\te{ActionSeq} function)} --@ The \te{actionSeq} function converts a list of actions to --@ an \te{ActionSeq}. --@ \begin{libverbatim} --@ module actionSeq#(ActionList#(n) as)(ActionSeq) --@ provisos (Add#(n, 1, i), Log#(i, k)); --@ \end{libverbatim} actionSeq :: (IsModule m c, Add n 1 i, Log i k) => ActionList n -> m ActionSeq actionSeq as = liftModule $ module letseq bn = fromInteger (valueOf n) var :: RegB k var <- mkReg bn addRules $ mkRules True var as interface start = var := 0 when var == bn done = (var == bn) checkDone = noAction when var == bn -- ActionSeq wrapper with a phantom type for the counter size interface (ActionSeqN :: # -> *) n = _actionSeq :: ActionSeq mkActionSeq :: (IsModule m c) => List Action -> m ActionSeq mkActionSeq a = module _asN :: ActionSeqN 1 <- mkActionSeqN a (length a) return $ _asN._actionSeq mkActionSeqN :: (IsModule m c, Add n 1 n1) => List Action -> Integer -> m (ActionSeqN n) mkActionSeqN a ln = module if ln < 2 ** (valueOf n) then do let bn = fromInteger ln r :: Reg (Bit n) <- mkReg bn aS2 a ln (asReg r) else do _asN1 :: ActionSeqN n1 <- mkActionSeqN a ln return $ interface ActionSeqN _actionSeq = _asN1._actionSeq aS2 :: (IsModule m c) => List Action -> Integer -> Reg (Bit a) -> m (ActionSeqN n) aS2 as n var = liftModule $ module letseq bn = fromInteger n addRules $ mR2 True var as interface ActionSeqN _actionSeq = interface ActionSeq start = var := 0 when var == bn done = (var == bn) checkDone = noAction when var == bn --@ \index{actionSeqBreak@\te{actionSeqBreak} (\te{ActionSeq} function)} --@ The function \te{actionSeqBreak} is similar to \te{actionSeq}, but it --@ allows the sequence of actions to be stopped before it reaches --@ the end. It is stopped by calling the argument supplied to --@ the action list. E.g., --@ \BBS --@ s :: ActionSeq --@ s <- actionSeqBreak ( \BSL break -> $\cdots$ |> \{ if cond then break else $\cdots$ \} |> $\cdots$ ) --@ \EBS --@ \begin{libverbatim} --@ module actionSeqBreak#(function ActionList#(n) as(Action x1))(ActionSeq) --@ provisos (Add#(n, 1, i), Log#(i, k)); --@ \end{libverbatim} actionSeqBreak :: (IsModule m c, Add n 1 i, Log i k) => (Action -> ActionList n) -> m ActionSeq actionSeqBreak as = liftModule $ module var :: RegB k var <- mkRegU go :: Reg Bool go <- mkReg False letseq bn = fromInteger (valueOf n) rdy = not go || var == bn addRules $ mkRules go var (as (go := False)) interface start = action { go := True; var := 0 } when rdy done = rdy checkDone = noAction when rdy mkRules :: Bool -> RegB k -> ActionList n -> Rules mkRules cond var l = foldr (step cond var) (rules { }) (zip genList l) mR2 :: Bool -> RegB k -> (List Action) -> Rules mR2 cond var l = List.foldr (step cond var) (rules { }) (List.zip (upto 0 ((length l)-1)) l) step :: Bool -> RegB k -> (Integer, Action) -> Rules -> Rules step cond var (i, a) r = rules ("actionSeq step " +++ integerToString i): when cond && var == fromInteger i ==> action { var := fromInteger i + 1; a } <+> r --@ \index{SeqList@\te{SeqList} (\te{ActionSeq} type)|textbf} --@ A \te{SeqList} is simply a list of action sequences. --@ \begin{libverbatim} --@ typedef Vector#(n, ActionSeq) SeqList #(type n); --@ \end{libverbatim} type SeqList n = Vector n ActionSeq --@ \index{seqOfActionSeq@\te{seqOfActionSeq} (\te{ActionSeq} function)} --@ The function \te{seqOfActionSeq} ``glues'' a number of action --@ sequences together into a single action sequence. --@ \begin{libverbatim} --@ module seqOfActionSeq#(SeqList#(n) xs)(ActionSeq) --@ provisos (Add#(n, 1, j), Add#(1, n, j), Add#(j, 1, i), Log#(i, k)); --@ \end{libverbatim} seqOfActionSeq :: (IsModule m c, Add n 1 j, Add j 1 i, Log i k) => SeqList n -> m ActionSeq seqOfActionSeq xs = liftModule $ module letseq bn = fromInteger (valueOf j) var :: RegB k var <- mkReg bn addRules $ mkSeqRules var xs interface start = var := 0 when var == bn done = (var == bn) checkDone = noAction when var == bn mkSeqRules :: (Add n 1 j) => RegB k -> SeqList n -> Rules mkSeqRules var l = letseq emptyIfc = interface ActionSeq { done = True; start = noAction; checkDone = noAction } l_shifted = cons emptyIfc l l_extended = append l (cons emptyIfc nil) zip3 = zipWith3 (\x y z -> (x,y,z)) in foldr (seqStep var) (rules { }) (zip3 genList l_extended l_shifted) seqStep :: RegB k -> (Integer, ActionSeq, ActionSeq) -> Rules -> Rules seqStep var (i, a1, a2) r = rules ("actionSeq step " +++ integerToString i): when var == fromInteger i, a2.done ==> action { var := fromInteger i + 1; a1.start } <+> r