never executed always true always false
    1 {-# LANGUAGE DuplicateRecordFields #-}
    2 {-# LANGUAGE OverloadedStrings #-}
    3 {-# LANGUAGE QuasiQuotes #-}
    4 {-# LANGUAGE RecordWildCards #-}
    5 {-# LANGUAGE TypeFamilies #-}
    6 
    7 {- |
    8 Module      : NITTA.Model.ProcessorUnits.IO.SimpleIO
    9 Description :
   10 Copyright   : (c) Aleksandr Penskoi, 2019
   11 License     : BSD3
   12 Maintainer  : aleksandr.penskoi@gmail.com
   13 Stability   : experimental
   14 -}
   15 module NITTA.Model.ProcessorUnits.IO.SimpleIO (
   16     SimpleIOInterface,
   17     SimpleIO (..),
   18     Ports (..),
   19     protocolDescription,
   20 ) where
   21 
   22 import Control.Monad
   23 import Data.Aeson (ToJSON (toJSON))
   24 import Data.Aeson.Encode.Pretty
   25 import Data.Default
   26 import Data.List qualified as L
   27 import Data.Maybe
   28 import Data.Set qualified as S
   29 import Data.String.Interpolate
   30 import Data.String.ToString
   31 import Data.Text qualified as T
   32 import Data.Text.Lazy (toStrict)
   33 import Data.Text.Lazy.Builder
   34 import Data.Typeable
   35 import GHC.Generics (Generic)
   36 import NITTA.Intermediate.Functions qualified as F
   37 import NITTA.Intermediate.Types
   38 import NITTA.Model.Problems
   39 import NITTA.Model.ProcessorUnits.Types
   40 import NITTA.Model.Time
   41 import NITTA.Project.Types (Implementation (Immediate))
   42 import NITTA.Utils
   43 import NITTA.Utils.ProcessDescription
   44 import Numeric.Interval.NonEmpty ((...))
   45 import Numeric.Interval.NonEmpty qualified as I
   46 import Prettyprinter
   47 
   48 class Typeable i => SimpleIOInterface i
   49 
   50 data SimpleIO i v x t = SimpleIO
   51     { bounceFilter :: Int
   52     , bufferSize :: Maybe Int
   53     -- ^ if 'Nothing' then size should defined by algorithm
   54     , receiveQueue :: [Q v x]
   55     , receiveN :: Int
   56     , isReceiveOver :: Bool
   57     -- ^ set if send buffer overlap receive buffer
   58     , sendQueue :: [Q v x]
   59     , sendN :: Int
   60     , process_ :: Process t (StepInfo v x t)
   61     }
   62 
   63 instance (VarValTime v x t, SimpleIOInterface i) => Pretty (SimpleIO i v x t) where
   64     pretty io =
   65         [__i|
   66             SimpleIO:
   67                 bounceFilter: #{ bounceFilter io }
   68                 bufferSize: #{ bufferSize io }
   69                 receiveQueue: #{ receiveQueue io }
   70                 receiveN: #{ receiveN io }
   71                 isReceiveOver: #{ isReceiveOver io }
   72                 sendQueue: #{ sendQueue io }
   73                 sendN: #{ sendN io }
   74                 #{ indent 4 $ pretty $ process_ io }
   75             |]
   76 
   77 data Q v x = Q {vars :: [v], function :: F v x, cads :: [ProcessStepID]}
   78 
   79 instance (Var v, Val x) => Show (Q v x) where
   80     show Q{vars, function, cads} =
   81         concat
   82             [ "Q{"
   83             , "vars: " <> concatMap toString vars <> ","
   84             , "function: " <> show function <> ","
   85             , "cads : " <> show cads <> "}"
   86             ]
   87 
   88 instance
   89     (VarValTime v x t, SimpleIOInterface i) =>
   90     ProcessorUnit (SimpleIO i v x t) v x t
   91     where
   92     tryBind f sio@SimpleIO{sendQueue, receiveQueue, receiveN, sendN, bufferSize}
   93         | Just F.Receive{} <- castF f
   94         , fromMaybe maxBound bufferSize == receiveN =
   95             Left "IO process unit to small buffer size"
   96         | Just F.Send{} <- castF f
   97         , fromMaybe maxBound bufferSize == sendN =
   98             Left "IO process unit to small buffer size"
   99         | Just (F.Receive (O vs)) <- castF f
  100         , let (cads, process_) = runSchedule sio $ scheduleFunctionBind f =
  101             Right
  102                 sio
  103                     { receiveQueue = Q{vars = S.elems vs, function = f, cads} : receiveQueue
  104                     , receiveN = receiveN + 1
  105                     , process_
  106                     }
  107         | Just (F.Send (I v)) <- castF f
  108         , let (cads, process_) = runSchedule sio $ scheduleFunctionBind f =
  109             Right
  110                 sio
  111                     { sendQueue = Q{vars = [v], function = f, cads} : sendQueue
  112                     , sendN = sendN + 1
  113                     , process_
  114                     }
  115         | otherwise = Left $ "IO processor unit do not support: " ++ show f
  116 
  117     process = process_
  118 
  119 instance BreakLoopProblem (SimpleIO i v x t) v x
  120 instance ConstantFoldingProblem (SimpleIO i v x t) v x
  121 instance OptimizeAccumProblem (SimpleIO i v x t) v x
  122 instance OptimizeLogicalUnitProblem (SimpleIO i v x t) v x
  123 instance ResolveDeadlockProblem (SimpleIO i v x t) v x
  124 
  125 instance
  126     (VarValTime v x t, SimpleIOInterface i) =>
  127     EndpointProblem (SimpleIO i v x t) v t
  128     where
  129     endpointOptions pu@SimpleIO{receiveQueue, sendQueue} =
  130         let source vs = EndpointSt (Source $ S.fromList vs) $ TimeConstraint (nextTick pu + 1 ... maxBound) (1 ... maxBound)
  131             receiveOpts = map (source . vars) receiveQueue
  132 
  133             target v = EndpointSt (Target v) $ TimeConstraint (nextTick pu ... maxBound) (I.singleton 1)
  134             sendOpts = map (target . head . vars) sendQueue
  135          in receiveOpts ++ sendOpts
  136 
  137     endpointDecision sio@SimpleIO{receiveQueue} d@EndpointSt{epRole = Source vs, epAt}
  138         | ([q@Q{function, vars = allVars}], receiveQueue') <-
  139             L.partition ((vs `S.isSubsetOf`) . S.fromList . vars) receiveQueue
  140         , let remainVars = allVars L.\\ S.elems vs
  141               process_ = execSchedule sio $ do
  142                 void $ scheduleEndpoint d $ scheduleInstructionUnsafe epAt $ Receiving $ null remainVars
  143                 when (null remainVars) $ void $ scheduleFunction epAt function
  144               receiveQueue'' =
  145                 if null remainVars
  146                     then receiveQueue'
  147                     else q{vars = remainVars} : receiveQueue' =
  148             sio{receiveQueue = receiveQueue'', process_}
  149     endpointDecision sio@SimpleIO{sendQueue, sendN, receiveQueue, receiveN} d@EndpointSt{epRole = Target v, epAt}
  150         | ([Q{function}], sendQueue') <- L.partition ((v ==) . head . vars) sendQueue
  151         , let process_ = execSchedule sio $ do
  152                 void $ scheduleEndpoint d $ scheduleInstructionUnsafe epAt Sending
  153                 scheduleFunction epAt function =
  154             sio
  155                 { sendQueue = sendQueue'
  156                 , isReceiveOver = (sendN - length sendQueue) >= (receiveN - length receiveQueue)
  157                 , process_
  158                 }
  159     endpointDecision pu d = error [i|incorrect decision #{ d } for #{ pretty pu }|]
  160 
  161 {- | Access to received data buffer was implemented like a queue. OE signal read
  162 received value multiple times __without changing__ "pointer" to the next value.
  163 OE and WR signals simultaneously read received value and __increment__ "pointer"
  164 to the next value. We do that for the reduced number of signal lines.
  165 
  166 Example:
  167 
  168 1. Nop - do nothing;
  169 
  170 2. Send (WR signal) - read a value from data_bus to send buffer[0], pointer
  171    increments automatically.
  172 
  173 3. Send (WR signal) - read a value from data_bus to send buffer[1], pointer
  174    increments automatically.
  175 
  176 4. Nop - do nothing.
  177 
  178 5. Receive False (OE signal) - write a value to data_bus from receive buffer[0]
  179    without pointer changing.
  180 
  181 6. Receive True (OE and WR signal) - write a value to data_bus from receive
  182    buffer[0] with pointer increment.
  183 -}
  184 instance Controllable (SimpleIO i v x t) where
  185     data Instruction (SimpleIO i v x t)
  186         = Receiving Bool
  187         | Sending
  188         deriving (Show)
  189 
  190     data Microcode (SimpleIO i v x t) = Microcode
  191         { wrSignal :: Bool
  192         , oeSignal :: Bool
  193         }
  194         deriving (Show, Eq, Ord)
  195 
  196     zipSignalTagsAndValues SimpleIOPorts{..} Microcode{..} =
  197         [ (wr, Bool wrSignal)
  198         , (oe, Bool oeSignal)
  199         ]
  200 
  201     usedPortTags SimpleIOPorts{wr, oe} = [wr, oe]
  202 
  203     takePortTags (wr : oe : _) _ = SimpleIOPorts wr oe "stop"
  204     takePortTags _ _ = error "can not take port tags, tags are over"
  205 
  206 instance Default (Microcode (SimpleIO i v x t)) where
  207     def =
  208         Microcode
  209             { wrSignal = False
  210             , oeSignal = False
  211             }
  212 
  213 instance UnambiguouslyDecode (SimpleIO i v x t) where
  214     decodeInstruction Sending = def{wrSignal = True}
  215     decodeInstruction (Receiving next) = def{oeSignal = True, wrSignal = next}
  216 
  217 instance Connected (SimpleIO i v x t) where
  218     data Ports (SimpleIO i v x t) = SimpleIOPorts
  219         { wr, oe :: SignalTag
  220         , -- \|this flag which indicates an end of the data transaction
  221           -- requires for stop computational process while data transferring
  222           -- to avoid loses
  223           stop :: String
  224         }
  225         deriving (Show)
  226 
  227 instance Var v => Locks (SimpleIO i v x t) v where
  228     locks SimpleIO{} = []
  229 
  230 data ProtocolDescription v = ProtocolDescription
  231     { description :: T.Text
  232     , interface :: T.Text
  233     , dataType :: T.Text
  234     , toNitta :: [v]
  235     , fromNitta :: [v]
  236     }
  237     deriving (Generic)
  238 
  239 instance ToJSON v => ToJSON (ProtocolDescription v)
  240 
  241 protocolDescription ::
  242     forall i v x t.
  243     (VarValTime v x t, SimpleIOInterface i, ToJSON v) =>
  244     T.Text ->
  245     SimpleIO i v x t ->
  246     T.Text ->
  247     Implementation
  248 protocolDescription tag io d
  249     | not $ null $ endpointOptions io = error "EndpointProblem is not completed"
  250     | otherwise =
  251         let impFile = toString $ tag <> ".json"
  252             fbs = getIntermediates $ process_ io
  253          in Immediate impFile $
  254                 toStrict $
  255                     toLazyText $
  256                         encodePrettyToTextBuilder $
  257                             toJSON
  258                                 ProtocolDescription
  259                                     { description = d
  260                                     , interface = showText $ typeRep (Proxy :: Proxy i)
  261                                     , dataType = showText $ typeRep (Proxy :: Proxy x)
  262                                     , toNitta = map (oneOf . outputs) $ filter isReceive fbs
  263                                     , fromNitta = map (oneOf . inputs) $ filter isSend fbs
  264                                     }
  265 
  266 isReceive :: (Typeable v, Typeable x) => F v x -> Bool
  267 isReceive f
  268     | Just F.Receive{} <- castF f = True
  269     | otherwise = False
  270 
  271 isSend :: (Typeable v, Typeable x) => F v x -> Bool
  272 isSend f
  273     | Just F.Send{} <- castF f = True
  274     | otherwise = False