never executed always true always false
1 {-# LANGUAGE DuplicateRecordFields #-}
2 {-# LANGUAGE OverloadedStrings #-}
3 {-# LANGUAGE QuasiQuotes #-}
4 {-# LANGUAGE RecordWildCards #-}
5 {-# LANGUAGE StandaloneDeriving #-}
6 {-# LANGUAGE TypeFamilies #-}
7
8 {- |
9 Module : NITTA.Model.ProcessorUnits.Broken
10 Description : Process Unit for negative tests
11 Copyright : (c) Aleksandr Penskoi, 2020
12 License : BSD3
13 Maintainer : aleksandr.penskoi@gmail.com
14 Stability : experimental
15 -}
16 module NITTA.Model.ProcessorUnits.Broken (
17 Broken (..),
18 Ports (..),
19 IOPorts (..),
20 ) where
21
22 import Control.Monad
23 import Data.Default
24 import Data.List (find, (\\))
25 import Data.Set (elems, fromList, member)
26 import Data.String.Interpolate
27 import Data.String.ToString
28 import Data.Text qualified as T
29 import NITTA.Intermediate.Functions qualified as F
30 import NITTA.Intermediate.Types
31 import NITTA.Model.Problems
32 import NITTA.Model.ProcessorUnits.Types
33 import NITTA.Model.Time
34 import NITTA.Project
35 import NITTA.Utils
36 import NITTA.Utils.ProcessDescription
37 import Numeric.Interval.NonEmpty (sup, (...))
38 import Numeric.Interval.NonEmpty qualified as I
39 import Prettyprinter
40
41 data Broken v x t = Broken
42 { remain :: [F v x]
43 , targets :: [v]
44 , sources :: [v]
45 , doneAt :: Maybe t
46 , currentWork :: Maybe (t, F v x)
47 , currentWorkEndpoints :: [ProcessStepID]
48 , process_ :: Process t (StepInfo v x t)
49 , brokeVerilog :: Bool
50 -- ^ generate verilog code with syntax error
51 , wrongVerilogSimulationValue :: Bool
52 -- ^ use process unit HW implementation with error
53 , wrongControlOnPush :: Bool
54 -- ^ wrong control sequence for data push (receiving data to PU)
55 , wrongControlOnPull :: Bool
56 -- ^ wrong control sequence for data pull (sending data from PU)
57 , lostEndpointTarget :: Bool
58 -- ^ lost target endpoint due synthesis
59 , lostEndpointSource :: Bool
60 -- ^ lost source endpoint due synthesis
61 , wrongAttr :: Bool
62 , lostFunctionInVerticalRelation :: Bool
63 , lostEndpointInVerticalRelation :: Bool
64 , lostInstructionInVerticalRelation :: Bool
65 , unknownDataOut :: Bool
66 }
67
68 instance VarValTime v x t => Pretty (Broken v x t) where
69 pretty Broken{..} =
70 [__i|
71 Broken:
72 remain:#{ remain }
73 targets:#{ map toString targets }
74 sources:#{ map toString sources }
75 currentWork: #{ currentWork }
76 currentWorkEndpoints: #{ currentWorkEndpoints }
77 brokeVerilog: #{ brokeVerilog }
78 wrongVerilogSimulationValue: #{ wrongVerilogSimulationValue }
79 wrongControlOnPush: #{ wrongControlOnPush }
80 wrongControlOnPull: #{ wrongControlOnPull }
81 lostEndpointTarget: #{ lostEndpointTarget }
82 lostEndpointSource: #{ lostEndpointSource }
83 wrongAttr: #{ wrongAttr }
84 unknownDataOut: #{ unknownDataOut }
85 #{ indent 4 $ pretty $ process_ }
86 |]
87
88 instance Var v => Locks (Broken v x t) v where
89 locks Broken{remain, sources, targets} =
90 [ Lock{lockBy, locked}
91 | locked <- sources
92 , lockBy <- targets
93 ]
94 ++ [ Lock{lockBy, locked}
95 | locked <- concatMap (elems . variables) remain
96 , lockBy <- sources ++ targets
97 ]
98
99 instance BreakLoopProblem (Broken v x t) v x
100 instance ConstantFoldingProblem (Broken v x t) v x
101 instance OptimizeAccumProblem (Broken v x t) v x
102 instance ResolveDeadlockProblem (Broken v x t) v x
103
104 instance VarValTime v x t => ProcessorUnit (Broken v x t) v x t where
105 tryBind f pu@Broken{remain}
106 | Just F.BrokenBuffer{} <- castF f = Right pu{remain = f : remain}
107 | otherwise = Left $ "The function is unsupported by Broken: " ++ show f
108 process = process_
109
110 execution pu@Broken{targets = [], sources = [], remain, process_} f
111 | Just (F.BrokenBuffer (I x) (O y)) <- castF f =
112 pu
113 { targets = [x]
114 , sources = elems y
115 , currentWork = Just (nextTick process_, f)
116 , remain = remain \\ [f]
117 }
118 execution _ _ = error "Broken: internal execution error."
119
120 instance VarValTime v x t => EndpointProblem (Broken v x t) v t where
121 endpointOptions Broken{targets = [_], lostEndpointTarget = True} = []
122 endpointOptions pu@Broken{targets = [v]} =
123 let start = nextTick pu `withShift` 1 ... maxBound
124 dur = 1 ... maxBound
125 in [EndpointSt (Target v) $ TimeConstraint start dur]
126 endpointOptions Broken{doneAt = Just _, lostEndpointSource = True} = []
127 endpointOptions pu@Broken{sources, doneAt = Just at}
128 | not $ null sources =
129 let start = max at (nextTick pu + 1) ... maxBound
130 dur = 1 ... maxBound
131 in [EndpointSt (Source $ fromList sources) $ TimeConstraint start dur]
132 endpointOptions pu@Broken{remain, lostEndpointTarget = True}
133 | not $ null remain = concatMap (endpointOptions . execution pu) $ tail remain
134 endpointOptions pu@Broken{remain} = concatMap (endpointOptions . execution pu) remain
135
136 endpointDecision pu@Broken{targets = [v], currentWorkEndpoints, wrongControlOnPush} d@EndpointSt{epRole = Target v', epAt}
137 | v == v' =
138 let workAt = epAt + I.singleton (if wrongControlOnPush then 1 else 0)
139 (newEndpoints, process_') = runSchedule pu $ do
140 scheduleEndpoint d $ scheduleInstructionUnsafe workAt Load
141 in pu
142 { process_ = process_'
143 , targets = []
144 , currentWorkEndpoints = newEndpoints ++ currentWorkEndpoints
145 , doneAt = Just $ sup epAt + 3
146 }
147 endpointDecision
148 pu@Broken
149 { targets = [v]
150 , currentWorkEndpoints
151 , wrongControlOnPush
152 , lostEndpointInVerticalRelation
153 , lostInstructionInVerticalRelation
154 }
155 d@EndpointSt{epRole = Target v', epAt}
156 | v == v'
157 , let (newEndpoints, process_') = runSchedule pu $ do
158 let ins =
159 if lostInstructionInVerticalRelation
160 then return []
161 else scheduleInstructionUnsafe (shiftI (if wrongControlOnPush then 1 else 0) epAt) Load
162
163 if lostEndpointInVerticalRelation
164 then return []
165 else scheduleEndpoint d ins =
166 pu
167 { process_ = process_'
168 , targets = []
169 , currentWorkEndpoints = newEndpoints ++ currentWorkEndpoints
170 , doneAt = Just $ sup epAt + 3
171 }
172 endpointDecision
173 pu@Broken
174 { targets = []
175 , sources
176 , doneAt
177 , currentWork = Just (a, f)
178 , currentWorkEndpoints
179 , wrongControlOnPull
180 , lostFunctionInVerticalRelation
181 , lostEndpointInVerticalRelation
182 , lostInstructionInVerticalRelation
183 }
184 EndpointSt{epRole = epRole@(Source v), epAt}
185 | not $ null sources
186 , let sources' = sources \\ elems v
187 , sources' /= sources
188 , let (newEndpoints, process_') = runSchedule pu $ do
189 let doAt = shiftI (if wrongControlOnPull then 0 else -1) epAt
190 -- Inlined: endpoints <- scheduleEndpoint d $ scheduleInstructionUnsafe doAt Out
191 endpoints <- do
192 high <- scheduleStep epAt $ EndpointRoleStep epRole
193 low <- scheduleInstructionUnsafe doAt Out
194 establishVerticalRelations
195 (if lostEndpointInVerticalRelation then [] else high)
196 (if lostInstructionInVerticalRelation then [] else low)
197 return high
198 when (null sources') $ do
199 high <- scheduleFunction (a ... sup epAt) f
200 let low = endpoints ++ currentWorkEndpoints
201 establishVerticalRelations
202 (if lostFunctionInVerticalRelation then [] else high)
203 (if lostEndpointInVerticalRelation then [] else low)
204 return endpoints =
205 pu
206 { process_ = process_'
207 , sources = sources'
208 , doneAt = if null sources' then Nothing else doneAt
209 , currentWork = if null sources' then Nothing else Just (a, f)
210 , currentWorkEndpoints = if null sources' then [] else newEndpoints ++ currentWorkEndpoints
211 }
212 endpointDecision pu@Broken{targets = [], sources = [], remain} d
213 | let v = oneOf $ variables d
214 , Just f <- find (\f -> v `member` variables f) remain =
215 endpointDecision (execution pu f) d
216 endpointDecision pu d = error [i|incorrect decision #{ d } for #{ pretty pu }|]
217
218 instance Controllable (Broken v x t) where
219 data Instruction (Broken v x t)
220 = Load
221 | Out
222 deriving (Show)
223
224 data Microcode (Broken v x t) = Microcode
225 { wrSignal :: Bool
226 , oeSignal :: Bool
227 }
228 deriving (Show, Eq, Ord)
229
230 zipSignalTagsAndValues BrokenPorts{..} Microcode{..} =
231 [ (wr, Bool wrSignal)
232 , (oe, Bool oeSignal)
233 ]
234
235 usedPortTags BrokenPorts{wr, oe} = [wr, oe]
236
237 takePortTags (wr : oe : _) _ = BrokenPorts wr oe
238 takePortTags _ _ = error "can not take port tags, tags are over"
239
240 instance Default (Microcode (Broken v x t)) where
241 def =
242 Microcode
243 { wrSignal = False
244 , oeSignal = False
245 }
246
247 instance Time t => Default (Broken v x t) where
248 def =
249 Broken
250 { remain = []
251 , targets = []
252 , sources = []
253 , doneAt = Nothing
254 , currentWork = Nothing
255 , currentWorkEndpoints = []
256 , process_ = def
257 , brokeVerilog = False
258 , wrongVerilogSimulationValue = False
259 , wrongControlOnPush = False
260 , wrongControlOnPull = False
261 , lostEndpointTarget = False
262 , lostEndpointSource = False
263 , wrongAttr = False
264 , lostFunctionInVerticalRelation = False
265 , lostEndpointInVerticalRelation = False
266 , lostInstructionInVerticalRelation = False
267 , unknownDataOut = False
268 }
269
270 instance Default x => DefaultX (Broken v x t) x
271
272 instance UnambiguouslyDecode (Broken v x t) where
273 decodeInstruction Load = def{wrSignal = True}
274 decodeInstruction Out = def{oeSignal = True}
275
276 instance Connected (Broken v x t) where
277 data Ports (Broken v x t) = BrokenPorts
278 { wr :: SignalTag
279 , oe :: SignalTag
280 }
281 deriving (Show)
282
283 instance IOConnected (Broken v x t) where
284 data IOPorts (Broken v x t) = BrokenIO
285 deriving (Show)
286
287 instance VarValTime v x t => TargetSystemComponent (Broken v x t) where
288 moduleName _title _pu = "pu_broken"
289 software _ _ = Empty
290 hardware _tag _pu = Aggregate Nothing [FromLibrary "pu_broken.v"]
291
292 hardwareInstance
293 tag
294 pu@Broken{brokeVerilog, wrongVerilogSimulationValue, wrongAttr, unknownDataOut}
295 UnitEnv
296 { sigClk
297 , ctrlPorts = Just BrokenPorts{..}
298 , valueIn = Just (dataIn, attrIn)
299 , valueOut = Just (dataOut, attrOut)
300 } =
301 [__i|
302 /*
303 #{ pretty pu }
304 */
305 pu_broken \#
306 ( .DATA_WIDTH( #{ dataWidth (def :: x) } )
307 , .ATTR_WIDTH( #{ attrWidth (def :: x) } )
308 , .IS_BROKEN( #{ bool2verilog wrongVerilogSimulationValue } )
309 , .WRONG_ATTR( #{ bool2verilog wrongAttr } )
310 , .UNKNOWN_DATA_OUT( #{ bool2verilog unknownDataOut } )
311 ) #{ tag }
312 ( .clk( #{ sigClk } )
313
314 , .signal_wr( #{ wr } )
315 , .data_in( #{ dataIn } ), .attr_in( #{ attrIn } )
316
317 , .signal_oe( #{ oe } )
318 , .data_out( #{ dataOut } ), .attr_out( #{ attrOut } )
319 #{ if brokeVerilog then "WRONG VERILOG" else "" :: T.Text }
320 );
321 |]
322 hardwareInstance _title _pu _env = error "internal error"
323
324 instance IOTestBench (Broken v x t) v x
325
326 instance Ord t => WithFunctions (Broken v x t) (F v x) where
327 functions Broken{process_, remain, currentWork} =
328 functions process_
329 ++ remain
330 ++ case currentWork of
331 Just (_, f) -> [f]
332 Nothing -> []
333
334 instance VarValTime v x t => Testable (Broken v x t) v x where
335 testBenchImplementation prj@Project{pName, pUnit} =
336 Immediate (toString $ moduleName pName pUnit <> "_tb.v") $
337 snippetTestBench
338 prj
339 SnippetTestBenchConf
340 { tbcSignals = ["oe", "wr"]
341 , tbcPorts =
342 BrokenPorts
343 { oe = SignalTag "oe"
344 , wr = SignalTag "wr"
345 }
346 , tbcMC2verilogLiteral = \Microcode{oeSignal, wrSignal} ->
347 [i|oe <= #{ bool2verilog oeSignal }; wr <= #{ bool2verilog wrSignal };|]
348 }