clash-prelude-0.99: src/Clash/Explicit/Moore.hs
{-|
Copyright : (C) 2013-2016, University of Twente,
2017 , Google Inc.
License : BSD2 (see the file LICENSE)
Maintainer : Christiaan Baaij <christiaan.baaij@gmail.com>
Whereas the output of a Mealy machine depends on /current transition/, the
output of a Moore machine depends on the /previous state/.
Moore machines are strictly less expressive, but may impose laxer timing
requirements.
-}
{-# LANGUAGE Safe #-}
module Clash.Explicit.Moore
( -- * Moore machines with explicit clock and reset ports
moore
, mooreB
, medvedev
, medvedevB
)
where
import Clash.Explicit.Signal (Bundle (..), Clock, Reset, Signal, register)
{- $setup
>>> :set -XDataKinds -XTypeApplications
>>> import Clash.Explicit.Prelude
>>> let macT s (x,y) = x * y + s
>>> let mac clk rst = moore clk rst macT id 0
-}
-- | Create a synchronous function from a combinational function describing
-- a moore machine
--
-- @
-- macT
-- :: Int -- Current state
-- -> (Int,Int) -- Input
-- -> (Int,Int) -- Updated state
-- macT s (x,y) = x * y + s
--
-- mac
-- :: 'Clock' mac Source
-- -> 'Reset' mac Asynchronous
-- -> 'Signal' mac (Int, Int)
-- -> 'Signal' mac Int
-- mac clk rst = 'moore' clk rst macT id 0
-- @
--
-- >>> simulate (mac systemClockGen systemResetGen) [(1,1),(2,2),(3,3),(4,4)]
-- [0,1,5,14...
-- ...
--
-- Synchronous sequential functions can be composed just like their
-- combinational counterpart:
--
-- @
-- dualMac
-- :: Clock domain gated
-- -> Reset domain synchronous
-- -> ('Signal' domain Int, 'Signal' domain Int)
-- -> ('Signal' domain Int, 'Signal' domain Int)
-- -> 'Signal' domain Int
-- dualMac clk rst (a,b) (x,y) = s1 + s2
-- where
-- s1 = 'moore' clk rst mac id 0 ('bundle' (a,x))
-- s2 = 'moore' clk rst mac id 0 ('bundle' (b,y))
-- @
moore
:: Clock domain gated -- ^ 'Clock' to synchronize to
-> Reset domain synchronous
-> (s -> i -> s) -- ^ Transfer function in moore machine form:
-- @state -> input -> newstate@
-> (s -> o) -- ^ Output function in moore machine form:
-- @state -> output@
-> s -- ^ Initial state
-> (Signal domain i -> Signal domain o)
-- ^ Synchronous sequential function with input and output matching that
-- of the moore machine
moore clk rst ft fo iS =
\i -> let s' = ft <$> s <*> i
s = register clk rst iS s'
in fo <$> s
{-# INLINABLE moore #-}
-- | Create a synchronous function from a combinational function describing
-- a moore machine without any output logic
medvedev
:: Clock domain gated
-> Reset domain synchronous
-> (s -> i -> s)
-> s
-> (Signal domain i -> Signal domain s)
medvedev clk rst tr st = moore clk rst tr id st
{-# INLINE medvedev #-}
-- | A version of 'moore' that does automatic 'Bundle'ing
--
-- Given a functions @t@ and @o@ of types:
--
-- @
-- __t__ :: Int -> (Bool, Int) -> Int
-- __o__ :: Int -> (Int, Bool)
-- @
--
-- When we want to make compositions of @t@ and @o@ in @g@ using 'moore'', we have to
-- write:
--
-- @
-- g clk rst a b c = (b1,b2,i2)
-- where
-- (i1,b1) = 'unbundle' (moore clk rst t o 0 ('bundle' (a,b)))
-- (i2,b2) = 'unbundle' (moore clk rst t o 3 ('bundle' (i1,c)))
-- @
--
-- Using 'mooreB'' however we can write:
--
-- @
-- g clk rst a b c = (b1,b2,i2)
-- where
-- (i1,b1) = 'mooreB' clk rst t o 0 (a,b)
-- (i2,b2) = 'mooreB' clk rst t o 3 (i1,c)
-- @
mooreB
:: (Bundle i, Bundle o)
=> Clock domain gated
-> Reset domain synchronous
-> (s -> i -> s) -- ^ Transfer function in moore machine form:
-- @state -> input -> newstate@
-> (s -> o) -- ^ Output function in moore machine form:
-- @state -> output@
-> s -- ^ Initial state
-> (Unbundled domain i -> Unbundled domain o)
-- ^ Synchronous sequential function with input and output matching that
-- of the moore machine
mooreB clk rst ft fo iS i = unbundle (moore clk rst ft fo iS (bundle i))
{-# INLINE mooreB #-}
-- | A version of 'medvedev' that does automatic 'Bundle'ing
medvedevB
:: (Bundle i, Bundle s)
=> Clock domain gated
-> Reset domain synchronous
-> (s -> i -> s)
-> s
-> (Unbundled domain i -> Unbundled domain s)
medvedevB clk rst tr st = mooreB clk rst tr id st
{-# INLINE medvedevB #-}