0

我正在尝试掌握单子的窍门。我认为与 state monad 一起玩是个好习惯。

使用CLaSH的 UART Rx :

-- 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

我将如何将when逻辑转移到他们自己的功能中?我一直在玩这个,但镜头似乎引起了问题。

Could not deduce Control.Monad.State.Class.MonadState from .=

我认为这里有一个功能

我失踪了。

我想做类似的事情

newFun = when (not _rx_busy && _rx_d2 == 0) $ do
         rx_busy       .= True
         rx_sample_cnt .= 1
         rx_cnt        .= 0

我认为会有一个execState我需要的功能。

所以我的问题是,

  • 我应该使用什么?
  • 该功能做了什么才能使其与其他功能组合在一起?
  • 如果单子只是组成,为什么我不能when在没有 execState 类型函数的函数中使用?
  • 我可以通过哪些其他方式来增加此代码的模块化?
4

1 回答 1

5

在你的定义中newFun

newFun = when (not _rx_busy && _rx_d2 == 0) $ do
         rx_busy       .= True
         rx_sample_cnt .= 1
         rx_cnt        .= 0

您正在尝试引用_rx_busyand _rx_d2,它们是类型的记录字段RxReg。在uartRX中,第一个参数是RxReg,并且 RecordWildCards 语言扩展用于通过将参数与模式匹配来绑定所有字段名称RxReg{..}。所以你要么需要传递r自己,要么至少需要_rx_busyand _rx_d2, from uartRXto newFun; 即要么有

newFun busy d2 = when (not busy && d2 == 0) $ do
    ...

或者

newFun RxReg{..} = when (not _rx_busy && _rx_d2 == 0) $ do
    ...
于 2016-10-31T02:42:41.113 回答