diff --git a/nitta.cabal b/nitta.cabal index a0da87320..8f2a40598 100644 --- a/nitta.cabal +++ b/nitta.cabal @@ -59,6 +59,7 @@ library NITTA.Model.Problems.Refactor.OptimizeAccum NITTA.Model.Problems.Refactor.ResolveDeadlock NITTA.Model.Problems.ViewHelper + NITTA.Model.ProcessIntegrity NITTA.Model.ProcessorUnits NITTA.Model.ProcessorUnits.Accum NITTA.Model.ProcessorUnits.Broken diff --git a/src/NITTA/Model/Networks/Bus.hs b/src/NITTA/Model/Networks/Bus.hs index 0831eeb3e..32510676b 100644 --- a/src/NITTA/Model/Networks/Bus.hs +++ b/src/NITTA/Model/Networks/Bus.hs @@ -25,6 +25,7 @@ For creating BusNetwork see 'NITTA.Model.Microarchitecture.Builder'. -} module NITTA.Model.Networks.Bus ( BusNetwork (..), + Instruction (..), Ports (..), IOPorts (..), bindedFunctions, @@ -193,8 +194,8 @@ instance (UnitTag tag, VarValTime v x t) => ProcessorUnit (BusNetwork tag v x t) let v2transportStepKey = M.fromList [ (v, pID) - | Step{pID, pDesc} <- steps bnProcess - , isInstruction pDesc + | step@Step{pID, pDesc} <- steps bnProcess + , isInstruction step , v <- case pDesc of (InstructionStep ins) | Just (Transport var _ _) <- castInstruction net ins -> [var] _ -> [] @@ -216,7 +217,7 @@ instance (UnitTag tag, VarValTime v x t) => ProcessorUnit (BusNetwork tag v x t) mapM_ ( \(epKey, v) -> when (v `M.member` v2transportStepKey) $ - establishVerticalRelation (v2transportStepKey M.! v) epKey + establishVerticalRelations [v2transportStepKey M.! v] [epKey] ) enpointStepKeyVars @@ -226,7 +227,7 @@ instance (UnitTag tag, VarValTime v x t) => ProcessorUnit (BusNetwork tag v x t) mapM_ ( \v -> when (v `M.member` v2transportStepKey) $ - establishVerticalRelation pID (v2transportStepKey M.! v) + establishVerticalRelations [pID] [v2transportStepKey M.! v] ) $ variables f ) @@ -243,7 +244,12 @@ instance (UnitTag tag, VarValTime v x t) => ProcessorUnit (BusNetwork tag v x t) return (pID, pID') ) steps - mapM_ (\(Vertical h l) -> establishVerticalRelation (pu2netKey M.! h) (pu2netKey M.! l)) relations + mapM_ + ( \case + (Vertical h l) -> establishVerticalRelations [pu2netKey M.! h] [pu2netKey M.! l] + (Horizontal h l) -> establishHorizontalRelations [pu2netKey M.! h] [pu2netKey M.! l] + ) + relations instance Controllable (BusNetwork tag v x t) where data Instruction (BusNetwork tag v x t) diff --git a/src/NITTA/Model/Problems/Dataflow.hs b/src/NITTA/Model/Problems/Dataflow.hs index 62e05b1ec..b942d5089 100644 --- a/src/NITTA/Model/Problems/Dataflow.hs +++ b/src/NITTA/Model/Problems/Dataflow.hs @@ -27,7 +27,7 @@ import GHC.Generics import NITTA.Intermediate.Variable import NITTA.Model.Problems.Endpoint import NITTA.Model.Time -import NITTA.Utils +import NITTA.Utils.Base import Numeric.Interval.NonEmpty {- |Dataflow option (@tp ~ TimeConstraint t@) or decision (@tp Z Interval t@) diff --git a/src/NITTA/Model/ProcessIntegrity.hs b/src/NITTA/Model/ProcessIntegrity.hs new file mode 100644 index 000000000..bc79e62b1 --- /dev/null +++ b/src/NITTA/Model/ProcessIntegrity.hs @@ -0,0 +1,96 @@ +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE PartialTypeSignatures #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE UndecidableInstances #-} + +{- | +Module : NITTA.Model.ProcessIntegrity +Description : Checking the target process integrity +Copyright : (c) Artyom Kostyuchik, Aleksandr Penskoi, 2022 +License : BSD3 +Maintainer : aleksandr.penskoi@gmail.com +Stability : experimental +-} +module NITTA.Model.ProcessIntegrity ( + ProcessIntegrity (checkProcessIntegrity), + isProcessIntegrity, +) where + +import Data.Either +import qualified Data.List as L +import qualified Data.Map.Strict as M +import Data.Maybe +import qualified Data.Set as S +import qualified Data.String.Utils as S +import NITTA.Model.ProcessorUnits +import NITTA.Utils + +class ProcessIntegrity u where + checkProcessIntegrity :: u -> Either String () + +isProcessIntegrity u = isRight $ checkProcessIntegrity u + +instance (ProcessorUnit (pu v x t) v x t) => ProcessIntegrity (pu v x t) where + checkProcessIntegrity pu = + collectChecks + [ checkVerticalRelations (up2down pu) (pid2intermediate pu) (pid2endpoint pu) "intermediate not related to endpoint" + , checkVerticalRelations (down2up pu) (pid2endpoint pu) (pid2intermediate pu) "endpoint not related to intermediate" + , checkVerticalRelations (up2down pu) (pid2endpoint pu) (pid2instruction pu) "endpoint not related to instruction" + , checkVerticalRelations (down2up pu) (pid2instruction pu) (pid2endpoint pu) "instruction not related to endpoint" + ] + +checkVerticalRelations f dom codom errmsg = + collectChecks $ + map + ( \x -> + let ys = M.findWithDefault S.empty x f + in if any (`M.member` codom) $ S.elems ys + then Right () + else Left $ errmsg <> ": " <> show (dom M.! x) + ) + $ M.keys dom + +-- TODO: #205 Divider: missing vertical relation between Do instruction and Endpoint +skipIntegrityErrors = ["instruction not related to endpoint: Instruction: Do"] + +collectChecks checks = case lefts checks of + [] -> Right () + errs -> case filter (`L.notElem` skipIntegrityErrors) errs of + [] -> Right () + errs' -> Left $ S.join "; " errs' + +relationsMap pairs = M.fromList $ map merge $ L.groupBy (\a b -> fst a == fst b) $ L.sortOn fst pairs + where + merge xs@((a, _) : _) = (a, S.fromList $ map snd xs) + merge _ = error "internal error" + +up2down pu = relationsMap $ mapMaybe get $ relations $ process pu + where + get Vertical{vUp, vDown} = Just (vUp, vDown) + get _ = Nothing + +down2up pu = relationsMap $ mapMaybe get $ relations $ process pu + where + get Vertical{vUp, vDown} = Just (vDown, vUp) + get _ = Nothing + +pid2intermediate pu = M.fromList $ mapMaybe get $ steps $ process pu + where + get s@Step{pID} + | Just f <- getFunction s = Just (pID, f) + | otherwise = Nothing + +pid2endpoint pu = M.fromList $ mapMaybe get $ steps $ process pu + where + get s@Step{pID} + | Just ep <- getEndpoint s = Just (pID, ep) + | otherwise = Nothing + +pid2instruction pu = M.fromList $ mapMaybe get $ steps $ process pu + where + get s@Step{pID} + | Just instr <- getInstruction s = Just (pID, instr) + | otherwise = Nothing diff --git a/src/NITTA/Model/ProcessorUnits/Broken.hs b/src/NITTA/Model/ProcessorUnits/Broken.hs index 9c93b2a47..da53161bb 100644 --- a/src/NITTA/Model/ProcessorUnits/Broken.hs +++ b/src/NITTA/Model/ProcessorUnits/Broken.hs @@ -26,7 +26,7 @@ module NITTA.Model.ProcessorUnits.Broken ( IOPorts (..), ) where -import Control.Monad (when) +import Control.Monad import Data.Default import Data.List (find, (\\)) import Data.Set (elems, fromList, member) @@ -66,6 +66,9 @@ data Broken v x t = Broken , -- |lost source endpoint due synthesis lostEndpointSource :: Bool , wrongAttr :: Bool + , lostFunctionInVerticalRelation :: Bool + , lostEndpointInVerticalRelation :: Bool + , lostInstructionInVerticalRelation :: Bool , unknownDataOut :: Bool } @@ -149,17 +152,62 @@ instance (VarValTime v x t) => EndpointProblem (Broken v x t) v t where , doneAt = Just $ sup epAt + 3 } endpointDecision - pu@Broken{targets = [], sources, doneAt, currentWork = Just (a, f), currentWorkEndpoints, wrongControlOnPull} - d@EndpointSt{epRole = Source v, epAt} + pu@Broken + { targets = [v] + , currentWorkEndpoints + , wrongControlOnPush + , lostEndpointInVerticalRelation + , lostInstructionInVerticalRelation + } + d@EndpointSt{epRole = Target v', epAt} + | v == v' + , let (newEndpoints, process_') = runSchedule pu $ do + let ins = + if lostInstructionInVerticalRelation + then return [] + else scheduleInstructionUnsafe (shiftI (if wrongControlOnPush then 1 else 0) epAt) Load + + if lostEndpointInVerticalRelation + then return [] + else scheduleEndpoint d ins = + pu + { process_ = process_' + , targets = [] + , currentWorkEndpoints = newEndpoints ++ currentWorkEndpoints + , doneAt = Just $ sup epAt + 3 + } + endpointDecision + pu@Broken + { targets = [] + , sources + , doneAt + , currentWork = Just (a, f) + , currentWorkEndpoints + , wrongControlOnPull + , lostFunctionInVerticalRelation + , lostEndpointInVerticalRelation + , lostInstructionInVerticalRelation + } + EndpointSt{epRole = epRole@(Source v), epAt} | not $ null sources , let sources' = sources \\ elems v , sources' /= sources , let (newEndpoints, process_') = runSchedule pu $ do - endpoints <- scheduleEndpoint d $ scheduleInstructionUnsafe (shiftI (if wrongControlOnPull then 0 else -1) epAt) Out + let doAt = shiftI (if wrongControlOnPull then 0 else -1) epAt + -- Inlined: endpoints <- scheduleEndpoint d $ scheduleInstructionUnsafe doAt Out + endpoints <- do + high <- scheduleStep epAt $ EndpointRoleStep epRole + low <- scheduleInstructionUnsafe doAt Out + establishVerticalRelations + (if lostEndpointInVerticalRelation then [] else high) + (if lostInstructionInVerticalRelation then [] else low) + return high when (null sources') $ do high <- scheduleFunction (a ... sup epAt) f let low = endpoints ++ currentWorkEndpoints - establishVerticalRelations high low + establishVerticalRelations + (if lostFunctionInVerticalRelation then [] else high) + (if lostEndpointInVerticalRelation then [] else low) return endpoints = pu { process_ = process_' @@ -220,6 +268,9 @@ instance (Time t) => Default (Broken v x t) where , lostEndpointTarget = False , lostEndpointSource = False , wrongAttr = False + , lostFunctionInVerticalRelation = False + , lostEndpointInVerticalRelation = False + , lostInstructionInVerticalRelation = False , unknownDataOut = False } diff --git a/src/NITTA/Model/ProcessorUnits/Divider.hs b/src/NITTA/Model/ProcessorUnits/Divider.hs index 67ae7edca..3a6421cc8 100644 --- a/src/NITTA/Model/ProcessorUnits/Divider.hs +++ b/src/NITTA/Model/ProcessorUnits/Divider.hs @@ -25,6 +25,7 @@ module NITTA.Model.ProcessorUnits.Divider ( IOPorts (..), ) where +import Control.Monad import Data.Default import Data.List (partition) import qualified Data.List as L @@ -217,7 +218,7 @@ instance (VarValTime v x t) => EndpointProblem (Divider v x t) v t where scheduleEndpoint_ d $ scheduleInstructionUnsafe epAt $ Load tag } endpointDecision pu@Divider{jobs} d@EndpointSt{epRole = Source vs, epAt} - | ([job@WaitResults{results}], jobs') <- partition ((vs `S.isSubsetOf`) . variables) jobs = + | ([job@WaitResults{results, function}], jobs') <- partition ((vs `S.isSubsetOf`) . variables) jobs = let ([(tag, allVs)], results') = partition ((vs `S.isSubsetOf`) . snd) results allVs' = allVs S.\\ vs results'' = filterEmptyResults $ (tag, allVs') : results' @@ -229,6 +230,8 @@ instance (VarValTime v x t) => EndpointProblem (Divider v x t) v t where { jobs = jobs'' , process_ = execSchedule pu $ do scheduleEndpoint_ d $ scheduleInstructionUnsafe epAt $ Out tag + when (null jobs') $ do + scheduleFunctionFinish_ [] function $ 0 ... sup epAt } endpointDecision _pu d = error [i|incorrect decision #{ d } for Divider|] diff --git a/src/NITTA/Model/ProcessorUnits/Fram.hs b/src/NITTA/Model/ProcessorUnits/Fram.hs index 49a03c4fe..28b5b9d3f 100644 --- a/src/NITTA/Model/ProcessorUnits/Fram.hs +++ b/src/NITTA/Model/ProcessorUnits/Fram.hs @@ -104,7 +104,7 @@ data Cell v x t = Cell data Job v x t = Job { function :: F v x , startAt :: Maybe t - , binds, endpoints :: [ProcessStepID] + , binds :: [ProcessStepID] } deriving (Show, Eq) @@ -113,7 +113,6 @@ defJob f = { function = f , startAt = Nothing , binds = [] - , endpoints = [] } instance WithFunctions (Cell v x t) (F v x) where @@ -323,7 +322,7 @@ instance (VarValTime v x t) => EndpointProblem (Fram v x t) v t where -- Constant endpointDecision fram@Fram{memory} d@EndpointSt{epRole = Source vs, epAt} - | Just (addr, cell@Cell{state = DoConstant vs', job = Just Job{function, binds, endpoints}}) <- + | Just (addr, cell@Cell{state = DoConstant vs', job = Just Job{function, binds}}) <- L.find ( \case (_, Cell{state = DoConstant vs'}) -> (vs' L.\\ S.elems vs) /= vs' @@ -332,11 +331,9 @@ instance (VarValTime v x t) => EndpointProblem (Fram v x t) v t where $ A.assocs memory = let vsRemain = vs' L.\\ S.elems vs process_' = execSchedule fram $ do - endpoints' <- scheduleEndpoint d $ scheduleInstructionUnsafe (shiftI (-1) epAt) $ PrepareRead addr - when (null vsRemain) $ do - fPID <- scheduleFunction (0 ... sup epAt) function - establishVerticalRelations binds fPID - establishVerticalRelations fPID (endpoints ++ endpoints') + void $ scheduleEndpoint d $ scheduleInstructionUnsafe (shiftI (-1) epAt) $ PrepareRead addr + when (null vsRemain) $ + scheduleFunctionFinish_ binds function $ 0 ... sup epAt cell' = case vsRemain of [] -> cell @@ -353,7 +350,7 @@ instance (VarValTime v x t) => EndpointProblem (Fram v x t) v t where } -- Loop endpointDecision fram@Fram{memory} d@EndpointSt{epRole = Source vs, epAt} - | Just (addr, cell@Cell{state = DoLoopSource vs' oJob, job = Just job@Job{binds, function, startAt, endpoints}}) <- + | Just (addr, cell@Cell{state = DoLoopSource vs' oJob, job = Just job@Job{binds, function, startAt}}) <- L.find ( \case (_, Cell{state = DoLoopSource vs' _}) -> (vs' L.\\ S.elems vs) /= vs' @@ -361,18 +358,16 @@ instance (VarValTime v x t) => EndpointProblem (Fram v x t) v t where ) $ A.assocs memory = let vsRemain = vs' L.\\ S.elems vs - (endpoints', process_) = runSchedule fram $ do + process_ = execSchedule fram $ do eps <- scheduleEndpoint d $ scheduleInstructionUnsafe (shiftI (-1) epAt) $ PrepareRead addr - when (null vsRemain) $ do - fPID <- scheduleFunction (0 ... sup epAt) function - establishVerticalRelations binds fPID - establishVerticalRelations fPID $ eps ++ endpoints + when (null vsRemain) $ + scheduleFunctionFinish_ binds function $ 0 ... sup epAt return eps cell' = if not $ null vsRemain then cell - { job = Just job{startAt = startAt <|> Just (inf epAt - 1), endpoints = endpoints' ++ endpoints} + { job = Just job{startAt = startAt <|> Just (inf epAt - 1)} , state = DoLoopSource vsRemain oJob } else @@ -382,13 +377,11 @@ instance (VarValTime v x t) => EndpointProblem (Fram v x t) v t where } in fram{process_, memory = memory A.// [(addr, cell')]} endpointDecision fram@Fram{memory} d@EndpointSt{epRole = Target v, epAt} - | Just (addr, cell@Cell{job = Just Job{function, binds, endpoints}}) <- + | Just (addr, cell@Cell{job = Just Job{function, binds}}) <- L.find (\case (_, Cell{state = DoLoopTarget v'}) -> v == v'; _ -> False) $ A.assocs memory = let process_ = execSchedule fram $ do - endpoints' <- scheduleEndpoint d $ scheduleInstructionUnsafe epAt $ Write addr - fPID <- scheduleFunction epAt function - establishVerticalRelations binds fPID - establishVerticalRelations fPID (endpoints ++ endpoints') + void $ scheduleEndpoint d $ scheduleInstructionUnsafe epAt $ Write addr + scheduleFunctionFinish binds function epAt cell' = cell { job = Nothing @@ -402,11 +395,11 @@ instance (VarValTime v x t) => EndpointProblem (Fram v x t) v t where endpointDecision fram@Fram{memory, remainBuffers} d@EndpointSt{epRole = Target v, epAt} | Just (addr, cell@Cell{history}) <- findForBufferCell fram , ([(Buffer (I _) (O vs), j@Job{function})], remainBuffers') <- L.partition (\(Buffer (I v') (O _), _) -> v' == v) remainBuffers = - let (endpoints, process_) = runSchedule fram $ do + let process_ = execSchedule fram $ do scheduleEndpoint d $ scheduleInstructionUnsafe epAt $ Write addr cell' = cell - { job = Just j{startAt = Just $ inf epAt, endpoints} + { job = Just j{startAt = Just $ inf epAt} , state = DoBuffer $ S.elems vs , lastWrite = Just $ sup epAt , history = function : history @@ -417,7 +410,7 @@ instance (VarValTime v x t) => EndpointProblem (Fram v x t) v t where , process_ } endpointDecision fram@Fram{memory} d@EndpointSt{epRole = Source vs, epAt} - | Just (addr, cell@Cell{state = DoBuffer vs', job = Just Job{function, startAt = Just fBegin, binds, endpoints}}) <- + | Just (addr, cell@Cell{state = DoBuffer vs', job = Just Job{function, startAt = Just fBegin, binds}}) <- L.find ( \case (_, Cell{state = DoBuffer vs'}) -> (vs' L.\\ S.elems vs) /= vs' @@ -426,11 +419,9 @@ instance (VarValTime v x t) => EndpointProblem (Fram v x t) v t where $ A.assocs memory = let vsRemain = vs' L.\\ S.elems vs process_ = execSchedule fram $ do - endpoints' <- scheduleEndpoint d $ scheduleInstructionUnsafe (shiftI (-1) epAt) $ PrepareRead addr - when (null vsRemain) $ do - fPID <- scheduleFunction (fBegin ... sup epAt) function - establishVerticalRelations binds fPID - establishVerticalRelations fPID (endpoints ++ endpoints') + void $ scheduleEndpoint d $ scheduleInstructionUnsafe (shiftI (-1) epAt) $ PrepareRead addr + when (null vsRemain) $ + scheduleFunctionFinish_ binds function $ fBegin ... sup epAt cell' = case vsRemain of [] -> cell diff --git a/src/NITTA/Model/ProcessorUnits/Multiplier.hs b/src/NITTA/Model/ProcessorUnits/Multiplier.hs index cdd0d1183..d9650aa3e 100644 --- a/src/NITTA/Model/ProcessorUnits/Multiplier.hs +++ b/src/NITTA/Model/ProcessorUnits/Multiplier.hs @@ -230,7 +230,7 @@ Multiplier: 0) Step {pID = 0, pInterval = 0 ... 2, pDesc = Endpoint: Target a} 1) Step {pID = 1, pInterval = 0 ... 2, pDesc = Instruction: Load A} relations: - 0) Vertical 0 1 + 0) Vertical {vUp = 0, vDown = 1} nextTick: 3 nextUid: 2 >>> mapM_ print $ endpointOptions st2 @@ -250,8 +250,8 @@ Multiplier: 2) Step {pID = 2, pInterval = 3 ... 3, pDesc = Endpoint: Target b} 3) Step {pID = 3, pInterval = 3 ... 3, pDesc = Instruction: Load B} relations: - 0) Vertical 2 3 - 1) Vertical 0 1 + 0) Vertical {vUp = 2, vDown = 3} + 1) Vertical {vUp = 0, vDown = 1} nextTick: 4 nextUid: 4 >>> mapM_ print $ endpointOptions st3 @@ -279,9 +279,9 @@ Multiplier: 4) Step {pID = 4, pInterval = 6 ... 6, pDesc = Endpoint: Source c} 5) Step {pID = 5, pInterval = 6 ... 6, pDesc = Instruction: Out} relations: - 0) Vertical 4 5 - 1) Vertical 2 3 - 2) Vertical 0 1 + 0) Vertical {vUp = 4, vDown = 5} + 1) Vertical {vUp = 2, vDown = 3} + 2) Vertical {vUp = 0, vDown = 1} nextTick: 7 nextUid: 6 >>> mapM_ print $ endpointOptions st4 @@ -306,14 +306,14 @@ Multiplier: 7) Step {pID = 7, pInterval = 7 ... 7, pDesc = Instruction: Out} 8) Step {pID = 8, pInterval = 0 ... 7, pDesc = Intermediate: a * b = c = d} relations: - 0) Vertical 8 6 - 1) Vertical 8 4 - 2) Vertical 8 2 - 3) Vertical 8 0 - 4) Vertical 6 7 - 5) Vertical 4 5 - 6) Vertical 2 3 - 7) Vertical 0 1 + 0) Vertical {vUp = 8, vDown = 6} + 1) Vertical {vUp = 8, vDown = 4} + 2) Vertical {vUp = 8, vDown = 2} + 3) Vertical {vUp = 8, vDown = 0} + 4) Vertical {vUp = 6, vDown = 7} + 5) Vertical {vUp = 4, vDown = 5} + 6) Vertical {vUp = 2, vDown = 3} + 7) Vertical {vUp = 0, vDown = 1} nextTick: 8 nextUid: 9 >>> endpointOptions st5 @@ -565,11 +565,12 @@ instance (VarValTime v x t) => EndpointProblem (Multiplier v x t) v t where let process_' = execSchedule pu $ do endpoints <- scheduleEndpoint d $ scheduleInstructionUnsafe epAt Out when (null sources') $ do - high <- scheduleFunction (a ... sup epAt) f - let low = endpoints ++ map pID (relatedEndpoints process_ $ variables f) -- Set up the vertical relantions between functional unit -- and related to that data sending. - establishVerticalRelations high low + + -- FIXME: here ([]) you can see the source of error. + -- Function don't connected to bind step. It should be fixed. + scheduleFunctionFinish_ [] f $ a ... sup epAt -- this is needed to correct work of automatically generated tests -- that takes time about time from Process return endpoints = diff --git a/src/NITTA/Model/ProcessorUnits/Shift.hs b/src/NITTA/Model/ProcessorUnits/Shift.hs index de91d8cf7..e023fbb2e 100644 --- a/src/NITTA/Model/ProcessorUnits/Shift.hs +++ b/src/NITTA/Model/ProcessorUnits/Shift.hs @@ -189,9 +189,10 @@ instance (VarValTime v x t) => EndpointProblem (Shift v x t) v t where let process_' = execSchedule pu $ do endpoints <- scheduleEndpoint d $ scheduleInstructionUnsafe (shiftI (-1) epAt) Out when (null sources') $ do - high <- scheduleFunction (a ... sup epAt) f - let low = endpoints ++ map pID (relatedEndpoints process_ $ variables f) - establishVerticalRelations high low + -- FIXME: here ([]) you can see the source of error. + -- Function don't connected to bind step. It should be fixed. + scheduleFunctionFinish_ [] f $ a ... sup epAt + return endpoints in pu { process_ = process_' , sources = sources' diff --git a/src/NITTA/Model/ProcessorUnits/Types.hs b/src/NITTA/Model/ProcessorUnits/Types.hs index fa3c5878c..a1283a6ca 100644 --- a/src/NITTA/Model/ProcessorUnits/Types.hs +++ b/src/NITTA/Model/ProcessorUnits/Types.hs @@ -34,6 +34,8 @@ module NITTA.Model.ProcessorUnits.Types ( Step (..), StepInfo (..), Relation (..), + isVertical, + isHorizontal, descent, whatsHappen, extractInstructionAt, @@ -189,6 +191,7 @@ data StepInfo v x t where -- |Apply refactoring RefactorStep :: (Typeable ref, Show ref, Eq ref) => ref -> StepInfo v x t -- |intermidiate level step (function execution) + -- FIXME: rename to IntermediateStep FStep :: F v x -> StepInfo v x t -- |endpoint level step (source or target) EndpointRoleStep :: EndpointRole v -> StepInfo v x t @@ -225,8 +228,18 @@ data Relation = -- |Vertical relationships (up and down). For example, the intermediate -- step (function execution) can be translated to a sequence of endpoint -- steps (receiving and sending variable), and process unit instructions. - Vertical ProcessStepID ProcessStepID - deriving (Show, Eq, Generic) + Vertical {vUp, vDown :: ProcessStepID} + | -- |Horizontal relationships (on one level). For example, we bind the + -- function and apply the refactoring. The binding step should be + -- connected to refactoring steps, including new binding steps. + Horizontal {hPrev, hNext :: ProcessStepID} + deriving (Show, Generic, Ord, Eq) + +isVertical Vertical{} = True +isVertical _ = False + +isHorizontal Horizontal{} = True +isHorizontal _ = False instance ToJSON Relation diff --git a/src/NITTA/Utils.hs b/src/NITTA/Utils.hs index 9bca3d63f..4c7a904be 100644 --- a/src/NITTA/Utils.hs +++ b/src/NITTA/Utils.hs @@ -29,6 +29,10 @@ module NITTA.Utils ( -- *Process inspection endpointAt, + getEndpoint, + getFunction, + getInstruction, + getCad, getEndpoints, transferred, inputsPushedAt, @@ -36,6 +40,7 @@ module NITTA.Utils ( relatedEndpoints, isFB, getFBs, + isEndpoint, isInstruction, module NITTA.Utils.Base, @@ -51,12 +56,12 @@ import Data.Bits (setBit, testBit) import qualified Data.HashMap.Strict as HM import Data.List (sortOn) import Data.Maybe -import qualified Data.Set as S import qualified Data.String.Utils as S import qualified Data.Text as T import NITTA.Intermediate.Types import NITTA.Model.ProcessorUnits.Types import NITTA.Utils.Base +import NITTA.Utils.ProcessDescription import Numeric (readInt, showHex) import Numeric.Interval.NonEmpty (inf, sup, (...)) import qualified Numeric.Interval.NonEmpty as I @@ -114,6 +119,9 @@ endpointAt t p = [] -> Nothing eps -> error $ "endpoints collision at: " ++ show t ++ " " ++ show eps +getCad Step{pDesc} | CADStep cad <- descent pDesc = Just cad +getCad _ = Nothing + isFB s = isJust $ getFB s getFB Step{pDesc} | FStep fb <- descent pDesc = Just fb @@ -121,9 +129,19 @@ getFB _ = Nothing getFBs p = mapMaybe getFB $ sortOn stepStart $ steps p +getFunction Step{pDesc} | FStep role <- descent pDesc = Just role +getFunction _ = Nothing + +isEndpoint ep = isJust $ getEndpoint ep + getEndpoint Step{pDesc} | EndpointRoleStep role <- descent pDesc = Just role getEndpoint _ = Nothing +isInstruction instr = isJust $ getInstruction instr + +getInstruction Step{pDesc} | instr@(InstructionStep _) <- descent pDesc = Just instr +getInstruction _ = Nothing + getEndpoints p = mapMaybe getEndpoint $ sortOn stepStart $ steps p transferred pu = unionsMap variables $ getEndpoints $ process pu @@ -134,17 +152,6 @@ stepsInterval ss = b = maximum $ map (sup . pInterval) ss in a ... b -relatedEndpoints process_ vs = - filter - ( \case - Step{pDesc = EndpointRoleStep role} -> not $ null (variables role `S.intersection` vs) - _ -> False - ) - $ steps process_ - -isInstruction (InstructionStep _) = True -isInstruction _ = False - stepStart Step{pInterval} = I.inf pInterval getToml text = either (error . show) id $ parseTomlDoc "parse error: " text diff --git a/src/NITTA/Utils/ProcessDescription.hs b/src/NITTA/Utils/ProcessDescription.hs index eeaeaff5b..a35d7dde1 100644 --- a/src/NITTA/Utils/ProcessDescription.hs +++ b/src/NITTA/Utils/ProcessDescription.hs @@ -1,5 +1,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NamedFieldPuns #-} @@ -22,24 +23,30 @@ module NITTA.Utils.ProcessDescription ( runSchedule, execSchedule, execScheduleWithProcess, + scheduleStep, scheduleEndpoint, scheduleEndpoint_, scheduleFunctionBind, scheduleFunctionRevoke, scheduleFunction, + scheduleFunctionFinish, + scheduleFunctionFinish_, scheduleRefactoring, scheduleInstructionUnsafe, scheduleInstructionUnsafe_, scheduleNestedStep, establishVerticalRelations, - establishVerticalRelation, + establishHorizontalRelations, getProcessSlice, + relatedEndpoints, castInstruction, ) where import Control.Monad.State import Data.Proxy (asProxyTypeOf) +import qualified Data.Set as S import Data.Typeable +import NITTA.Intermediate.Types import NITTA.Model.Problems import NITTA.Model.ProcessorUnits.Types import Numeric.Interval.NonEmpty (singleton, sup) @@ -107,7 +114,7 @@ scheduleStep' mkStep = do return [nextUid] {- |Add to the process description information about vertical relations, which are defined by the - Cartesian product of high and low lists. +Cartesian product of high and low lists. -} establishVerticalRelations high low = do sch@Schedule{schProcess = p@Process{relations}} <- get @@ -119,14 +126,16 @@ establishVerticalRelations high low = do } } --- |Add to the process description information about vertical relation. -establishVerticalRelation h l = do +{- |Add to the process description information about horizontal relations (inside +level), which are defined by the Cartesian product of high and low lists. +-} +establishHorizontalRelations high low = do sch@Schedule{schProcess = p@Process{relations}} <- get put sch { schProcess = p - { relations = Vertical h l : relations + { relations = [Horizontal h l | h <- high, l <- low] ++ relations } } @@ -143,6 +152,19 @@ scheduleFunction ti f = scheduleStep ti $ FStep f scheduleRefactoring ti ref = scheduleStep ti $ RefactorStep ref +{- |Schedule function and establish vertical relations between bind step, +function step, and all related endpoints. +-} +scheduleFunctionFinish bPID function at = do + fPID <- scheduleFunction at function + establishVerticalRelations bPID fPID + process_ <- getProcessSlice + let low = map pID $ relatedEndpoints process_ $ variables function + establishVerticalRelations fPID low + return fPID + +scheduleFunctionFinish_ bPID function at = void $ scheduleFunctionFinish bPID function at + {- |Add to the process description information about endpoint behaviour, and it's low-level implementation (on instruction level). Vertical relations connect endpoint level and instruction level steps. @@ -188,6 +210,14 @@ getProcessSlice = do Schedule{schProcess} <- get return schProcess +relatedEndpoints process_ vs = + filter + ( \case + Step{pDesc = EndpointRoleStep role} -> not $ null (variables role `S.intersection` vs) + _ -> False + ) + $ steps process_ + -- |Helper for instruction extraction from a rigid type variable. castInstruction :: (Typeable a, Typeable pu) => pu -> a -> Maybe (Instruction pu) castInstruction _pu i = cast i diff --git a/test/NITTA/Model/ProcessorUnits/Broken/Tests.hs b/test/NITTA/Model/ProcessorUnits/Broken/Tests.hs index 628212c55..13cf5bb6e 100644 --- a/test/NITTA/Model/ProcessorUnits/Broken/Tests.hs +++ b/test/NITTA/Model/ProcessorUnits/Broken/Tests.hs @@ -135,6 +135,26 @@ tests = , expectFail $ nittaCoSimTestCase "nittaCoSimTestCase lost source endpoint" (maBroken u{lostEndpointSource = True}) alg , expectFail $ typedLuaTestCase (maBroken def{lostEndpointSource = True}) pInt "typedLuaTestCase lost source endpoint" lua ] + , testGroup + "broken relations integrity check positive" + [ nittaCoSimTestCase "nittaCoSimTestCase positive test" (maBroken u) alg + , typedLuaTestCase (maBroken def) pInt "typedLuaTestCase positive test" lua + , puCoSimTestCase "puCoSimTestCase positive test" u [("a", 42)] [brokenBuffer "a" ["b"]] + , finitePUSynthesisProp "finitePUSynthesisProp relation positive test" u fsGen + , puCoSimProp "puCoSimProp relation positive test" u fsGen + ] + , testGroup + "process integrity of PU negative" + [ expectFail $ finitePUSynthesisProp "finitePUSynthesisProp lostFunctionInVerticalRelation" u{lostFunctionInVerticalRelation = True} fsGen + , expectFail $ finitePUSynthesisProp "finitePUSynthesisProp lostEndpointInVerticalRelation" u{lostEndpointInVerticalRelation = True} fsGen + , expectFail $ finitePUSynthesisProp "finitePUSynthesisProp lostInstructionInVerticalRelation" u{lostInstructionInVerticalRelation = True} fsGen + , expectFail $ puCoSimProp "puCoSimProp lostFunctionInVerticalRelation" u{lostFunctionInVerticalRelation = True} fsGen + , expectFail $ puCoSimProp "puCoSimProp lostEndpointInVerticalRelation" u{lostEndpointInVerticalRelation = True} fsGen + , expectFail $ puCoSimProp "puCoSimProp lostInstructionInVerticalRelation" u{lostInstructionInVerticalRelation = True} fsGen + , expectFail $ puCoSimTestCase "puCoSimTestCase lostFunctionInVerticalRelation" u{lostFunctionInVerticalRelation = True} [("a", 42)] [brokenBuffer "a" ["b"]] + , expectFail $ puCoSimTestCase "puCoSimTestCase lostEndpointInVerticalRelation" u{lostEndpointInVerticalRelation = True} [("a", 42)] [brokenBuffer "a" ["b"]] + , expectFail $ puCoSimTestCase "puCoSimTestCase lostInstructionInVerticalRelation" u{lostInstructionInVerticalRelation = True} [("a", 42)] [brokenBuffer "a" ["b"]] + ] ] where u = def :: Broken T.Text Int Int diff --git a/test/NITTA/Model/ProcessorUnits/Tests/DSL.hs b/test/NITTA/Model/ProcessorUnits/Tests/DSL.hs index 0c69f66e2..a42908061 100644 --- a/test/NITTA/Model/ProcessorUnits/Tests/DSL.hs +++ b/test/NITTA/Model/ProcessorUnits/Tests/DSL.hs @@ -129,6 +129,7 @@ import NITTA.LuaFrontend import NITTA.Model.Networks.Bus import NITTA.Model.Networks.Types (PUClasses) import NITTA.Model.Problems +import NITTA.Model.ProcessIntegrity import NITTA.Model.ProcessorUnits import NITTA.Model.ProcessorUnits.Tests.Utils import NITTA.Model.TargetSystem @@ -165,12 +166,12 @@ data UnitTestState u v x = UnitTestState type Statement u v x r = HasCallStack => StateT (UnitTestState u v x) IO r type PUStatement pu v x t r = - (ProcessorUnit pu v x t, EndpointProblem pu v t) => + (HasCallStack, ProcessorUnit pu v x t, ProcessIntegrity pu, BreakLoopProblem pu v x, EndpointProblem pu v t) => StateT (UnitTestState pu v x) IO r type TSStatement x r = forall tag v t. - (tag ~ T.Text, v ~ T.Text, t ~ Int, Val x) => + (HasCallStack, tag ~ T.Text, v ~ T.Text, t ~ Int, Val x) => Statement (TargetSystem (BusNetwork tag v x t) tag v x t) v x r unitTestCase :: @@ -327,8 +328,14 @@ assertLocks expectLocks = do assertSynthesisDone :: PUStatement pu v x t () assertSynthesisDone = do UnitTestState{unit, functs, testName} <- get - unless (isProcessComplete unit functs && null (endpointOptions unit)) $ - lift $ assertFailure $ testName <> " Process is not done: " <> incompleteProcessMsg unit functs + unless (null $ endpointOptions unit) $ + lift $ assertFailure $ "In ''" <> testName <> "'' process still has endpoint options:\n" <> show (pretty $ process unit) + unless (isProcessComplete unit functs) $ + lift $ assertFailure $ "In ''" <> testName <> "'' process is incomplete.\nAlgorithm: " <> show functs <> "\nProcess:\n" <> show (pretty $ process unit) + + case checkProcessIntegrity unit of + Left err -> lift $ assertFailure $ testName <> " broken process: " <> err + Right () -> return () assertPUCoSimulation :: ( PUClasses pu v x Int @@ -338,22 +345,24 @@ assertPUCoSimulation :: , Var v ) => PUStatement pu v x Int () -assertPUCoSimulation = - let checkInputVars pu fs cntx = - S.union - (unionsMap inputs $ functions pu) - (unionsMap inputs fs) - == S.fromList (map fst cntx) - in do - UnitTestState{unit, functs, testName, cntxCycle} <- get - unless (checkInputVars unit functs cntxCycle) $ - lift $ assertFailure "you forgot to set initial values before coSimulation." - - report@TestbenchReport{tbStatus} <- - lift $ puCoSim testName unit cntxCycle functs False - - unless tbStatus $ - lift $ assertFailure $ "coSimulation failed: \n" <> show report +assertPUCoSimulation = do + UnitTestState{unit, functs, testName, cntxCycle} <- get + unless (checkInputVars unit functs cntxCycle) $ + lift $ assertFailure "you forgot to set initial values before coSimulation." + + report@TestbenchReport{tbStatus} <- + lift $ puCoSim testName unit cntxCycle functs False + + unless tbStatus $ + lift $ assertFailure $ "coSimulation failed: \n" <> show report + where + checkInputVars pu fs cntx = + let requiredVars = + S.union + (unionsMap inputs $ functions pu) + (unionsMap inputs fs) + initialCntx = S.fromList (map fst cntx) + in requiredVars == initialCntx assignLua :: T.Text -> TSStatement x () assignLua src = do diff --git a/test/NITTA/Model/ProcessorUnits/Tests/Providers.hs b/test/NITTA/Model/ProcessorUnits/Tests/Providers.hs index 6de390c2f..beecab224 100644 --- a/test/NITTA/Model/ProcessorUnits/Tests/Providers.hs +++ b/test/NITTA/Model/ProcessorUnits/Tests/Providers.hs @@ -40,6 +40,7 @@ import NITTA.Intermediate.Tests.Functions () import NITTA.Intermediate.Types import NITTA.Model.Networks.Types import NITTA.Model.Problems hiding (Bind, BreakLoop) +import NITTA.Model.ProcessIntegrity import NITTA.Model.ProcessorUnits import NITTA.Model.ProcessorUnits.Tests.DSL import NITTA.Model.ProcessorUnits.Tests.Utils @@ -74,6 +75,7 @@ puCoSimTestCase name u cntxCycle alg = unitTestCase name u $ do mapM_ (assignNaive cntxCycle) alg decideNaiveSynthesis + assertSynthesisDone assertPUCoSimulation -- *Properties @@ -82,9 +84,12 @@ puCoSimTestCase name u cntxCycle alg = finitePUSynthesisProp name pu0 fsGen = testProperty name $ do (pu, fs) <- processAlgOnEndpointGen pu0 fsGen - return $ - isProcessComplete pu fs - && null (endpointOptions pu) + case checkProcessIntegrity pu of + Left msg -> error msg + Right _ -> + return $ + isProcessComplete pu fs + && null (endpointOptions pu) {- |A computational process of functional (Haskell) and logical (Verilog) simulation should be identical for any correct algorithm. @@ -99,6 +104,9 @@ puCoSimProp name pu0 fsGen = uniqueName <- uniqTestPath name unless (isProcessComplete pu fs) $ error $ "process is not complete: " <> incompleteProcessMsg pu fs + case checkProcessIntegrity pu of + Left e -> error e + Right _ -> return () pwd <- getCurrentDirectory let pTargetProjectPath = "gen" toModuleName uniqueName pInProjectNittaPath = "." @@ -116,5 +124,5 @@ puCoSimProp name pu0 fsGen = , pTemplates = ["templates/Icarus"] } writeProject prj - res <- runTestbench prj - unless (tbStatus res) $ error $ "Fail CoSim in: " <> pTargetProjectPath + report <- runTestbench prj + unless (tbStatus report) $ error $ "Fail CoSim in: " <> pTargetProjectPath diff --git a/test/NITTA/Model/ProcessorUnits/Tests/Utils.hs b/test/NITTA/Model/ProcessorUnits/Tests/Utils.hs index 34bfb4bfc..81a2351ad 100644 --- a/test/NITTA/Model/ProcessorUnits/Tests/Utils.hs +++ b/test/NITTA/Model/ProcessorUnits/Tests/Utils.hs @@ -95,8 +95,10 @@ decisions. naiveSynthesis alg u0 = naiveSynthesis' $ foldl (flip bind) u0 alg where naiveSynthesis' u - | opt : _ <- endpointOptions u = - naiveSynthesis' $ endpointDecision u $ endpointOptionToDecision opt + | ref : _ <- breakLoopOptions u = + naiveSynthesis' $ breakLoopDecision u ref + | ep : _ <- endpointOptions u = + naiveSynthesis' $ endpointDecision u $ endpointOptionToDecision ep | otherwise = u isProcessComplete pu fs = unionsMap variables fs == processedVars pu @@ -137,7 +139,7 @@ processAlgOnEndpointGen pu0 algGen' = do algSynthesisGen alg [] pu0 -- FIXME: support new synthesis/refactor style -data PUSynthesisTask r f e = BreakLoop r | Bind f | Transport e +data PUSynthesisTask r f e = BreakLoop r | Bind f | Endpoint e algSynthesisGen fRemain fPassed pu = select tasksList where @@ -145,7 +147,7 @@ algSynthesisGen fRemain fPassed pu = select tasksList concat [ map BreakLoop $ breakLoopOptions pu , map Bind fRemain - , map Transport $ endpointOptions pu + , map Endpoint $ endpointOptions pu ] select [] = return (pu, fPassed) @@ -157,7 +159,7 @@ algSynthesisGen fRemain fPassed pu = select tasksList (Left _err) -> algSynthesisGen fRemain' fPassed pu where fRemain' = delete f fRemain - taskPattern (Transport e) = do + taskPattern (Endpoint e) = do d <- endpointOptionToDecision <$> endpointGen e let pu' = endpointDecision pu d algSynthesisGen fRemain fPassed pu' diff --git a/web/src/components/ProcessView.tsx b/web/src/components/ProcessView.tsx index 6629f33fc..86e932422 100644 --- a/web/src/components/ProcessView.tsx +++ b/web/src/components/ProcessView.tsx @@ -50,14 +50,12 @@ function renderProcessViewDot(process: ProcessData): string { }); process.relations.forEach((relation: RelationData) => { - // FIXME: replace by commented code after source code update - lines.push(` ${relation[0]} -> ${relation[1]};`); - /* if (relation.tag === "Vertical") { - * lines.push(` ${relation.vUp} -> ${relation.vDown};`); - * } - * if (relation.tag === "Horizontal") { - * lines.push(` ${relation.hPrev} -> ${relation.hNext}[style=dashed];`); - * } */ + if (relation.tag === "Vertical") { + lines.push(` ${relation.vUp} -> ${relation.vDown};`); + } + if (relation.tag === "Horizontal") { + lines.push(` ${relation.hPrev} -> ${relation.hNext}[style=dashed];`); + } }); lines.push("}"); return lines.join("\n");