I am trying to get the hang of monads. I figured it would be good practice to play with the state monad.
Using the UART Rx from CLaSH:
-- UART RX Logic
data RxReg
= RxReg
{ _rx_reg :: BitVector 8
, _rx_data :: BitVector 8
, _rx_sample_cnt :: Unsigned 4
, _rx_cnt :: Unsigned 4
, _rx_frame_err :: Bool
, _rx_over_run :: Bool
, _rx_empty :: Bool
, _rx_d1 :: Bit
, _rx_d2 :: Bit
, _rx_busy :: Bool
}
makeLenses ''RxReg
uartRX r@(RxReg {..}) rx_in uld_rx_data rx_enable = flip execState r $ do
-- Synchronise the async signal
rx_d1 .= rx_in
rx_d2 .= _rx_d1
-- Uload the rx data
when uld_rx_data $ do
rx_data .= _rx_reg
rx_empty .= True
-- Receive data only when rx is enabled
if rx_enable then do
-- Check if just received start of frame
when (not _rx_busy && _rx_d2 == 0) $ do
rx_busy .= True
rx_sample_cnt .= 1
rx_cnt .= 0
-- Star of frame detected, Proceed with rest of data
when _rx_busy $ do
rx_sample_cnt += 1
-- Logic to sample at middle of data
when (_rx_sample_cnt == 7) $ do
if _rx_d1 == 1 && _rx_cnt == 0 then
rx_busy .= False
else do
rx_cnt += 1
-- start storing the rx data
when (_rx_cnt > 0 && _rx_cnt < 9) $ do
rx_reg %= replaceBit (_rx_cnt - 1) _rx_d2
when (_rx_cnt == 9) $ do
rx_busy .= False
-- Check if End of frame received correctly
if _rx_d2 == 0 then
rx_frame_err .= True
else do
rx_empty .= False
rx_frame_err .= False
-- Check if last rx data was not unloaded
rx_over_run .= not _rx_empty
else do
rx_busy .= False
How would I go about moving the when
logic to their own functions? I have been playing with this for a little bit, but the lenses seem to be causing issues.
Could not deduce Control.Monad.State.Class.MonadState from .=
I am think there is a function here
That I am missing.
I would want to do something like
newFun = when (not _rx_busy && _rx_d2 == 0) $ do
rx_busy .= True
rx_sample_cnt .= 1
rx_cnt .= 0
I would think there would be a function like execState
that I need.
So my questions are,
when
in a function without an execState type function?In your definition of newFun
newFun = when (not _rx_busy && _rx_d2 == 0) $ do
rx_busy .= True
rx_sample_cnt .= 1
rx_cnt .= 0
you are trying to refer to _rx_busy
and _rx_d2
, which are record fields of the type RxReg
. In uartRX
, the first argument is an RxReg
, and the RecordWildCards language extension is used to bind all the field names by matching the argument with the pattern RxReg{..}
. So you will either need to pass r
itself, or at least _rx_busy
and _rx_d2
, from uartRX
to newFun
; i.e. either have
newFun busy d2 = when (not busy && d2 == 0) $ do
...
or
newFun RxReg{..} = when (not _rx_busy && _rx_d2 == 0) $ do
...