Cleaned up genFoldlCall.
[matthijs/master-project/cλash.git] / Generate.hs
1 module Generate where
2
3 -- Standard modules
4 import qualified Control.Monad as Monad
5 import qualified Data.Map as Map
6 import qualified Maybe
7 import Data.Accessor
8
9 -- ForSyDe
10 import qualified ForSyDe.Backend.VHDL.AST as AST
11
12 -- GHC API
13 import CoreSyn
14 import Type
15 import qualified Var
16
17 -- Local imports
18 import Constants
19 import VHDLTypes
20 import VHDLTools
21 import CoreTools
22
23 -- | Generate a binary operator application. The first argument should be a
24 -- constructor from the AST.Expr type, e.g. AST.And.
25 genExprOp2 :: (AST.Expr -> AST.Expr -> AST.Expr) -> CoreSyn.CoreBndr -> [AST.Expr] -> VHDLSession AST.Expr
26 genExprOp2 op res [arg1, arg2] = return $ op arg1 arg2
27
28 -- | Generate a unary operator application
29 genExprOp1 :: (AST.Expr -> AST.Expr) -> CoreSyn.CoreBndr -> [AST.Expr] -> VHDLSession AST.Expr
30 genExprOp1 op res [arg] = return $ op arg
31
32 -- | Generate a function call from the destination binder, function name and a
33 -- list of expressions (its arguments)
34 genExprFCall :: String -> CoreSyn.CoreBndr -> [AST.Expr] -> VHDLSession AST.Expr
35 genExprFCall fname res args = do
36   let el_ty = (tfvec_elem . Var.varType) res
37   id <- vectorFunId el_ty fname
38   return $ AST.PrimFCall $ AST.FCall (AST.NSimple id)  $
39              map (\exp -> Nothing AST.:=>: AST.ADExpr exp) args
40
41 -- | Generate a generate statement for the builtin function "map"
42 genMapCall :: 
43   Entity -- | The entity to map
44   -> [CoreSyn.CoreBndr] -- | The vectors
45   -> VHDLSession AST.ConcSm -- | The resulting generate statement
46 genMapCall entity [arg, res] = return $ genSm
47   where
48     -- Setup the generate scheme
49     len         = (tfvec_len . Var.varType) res
50     label       = mkVHDLExtId ("mapVector" ++ (varToString res))
51     nPar        = AST.unsafeVHDLBasicId "n"
52     range       = AST.ToRange (AST.PrimLit "0") (AST.PrimLit $ show (len-1))
53     genScheme   = AST.ForGn nPar range
54     -- Get the entity name and port names
55     entity_id   = ent_id entity
56     argports   = map (Monad.liftM fst) (ent_args entity)
57     resport     = (Monad.liftM fst) (ent_res entity)
58     -- Assign the ports
59     inport      = mkAssocElemIndexed (argports!!0) (varToVHDLId arg) nPar
60     outport     = mkAssocElemIndexed resport (varToVHDLId res) nPar
61     portassigns = Maybe.catMaybes [inport,outport]
62     -- Generate the portmap
63     mapLabel    = "map" ++ (AST.fromVHDLId entity_id)
64     compins     = mkComponentInst mapLabel entity_id portassigns
65     -- Return the generate functions
66     genSm       = AST.CSGSm $ AST.GenerateSm label genScheme [] [compins]
67     
68 genZipWithCall ::
69   Entity
70   -> [CoreSyn.CoreBndr]
71   -> VHDLSession AST.ConcSm
72 genZipWithCall entity [arg1, arg2, res] = return $ genSm
73   where
74     -- Setup the generate scheme
75     len         = (tfvec_len . Var.varType) res
76     label       = mkVHDLExtId ("zipWithVector" ++ (varToString res))
77     nPar        = AST.unsafeVHDLBasicId "n"
78     range       = AST.ToRange (AST.PrimLit "0") (AST.PrimLit $ show (len-1))
79     genScheme   = AST.ForGn nPar range
80     -- Get the entity name and port names
81     entity_id   = ent_id entity
82     argports    = map (Monad.liftM fst) (ent_args entity)
83     resport     = (Monad.liftM fst) (ent_res entity)
84     -- Assign the ports
85     inport1     = mkAssocElemIndexed (argports!!0) (varToVHDLId arg1) nPar
86     inport2     = mkAssocElemIndexed (argports!!1) (varToVHDLId arg2) nPar 
87     outport     = mkAssocElemIndexed resport (varToVHDLId res) nPar
88     portassigns = Maybe.catMaybes [inport1,inport2,outport]
89     -- Generate the portmap
90     mapLabel    = "zipWith" ++ (AST.fromVHDLId entity_id)
91     compins     = mkComponentInst mapLabel entity_id portassigns
92     -- Return the generate functions
93     genSm       = AST.CSGSm $ AST.GenerateSm label genScheme [] [compins]
94
95 genFoldlCall ::
96   Entity
97   -> [CoreSyn.CoreBndr]
98   -> VHDLSession AST.ConcSm
99 genFoldlCall entity [startVal, inVec, resVal] = do
100   let (vec, _) = splitAppTy (Var.varType inVec)
101   let vecty = Type.mkAppTy vec (Var.varType startVal)
102   vecType <- vhdl_ty vecty
103   -- Setup the generate scheme
104   let  len         = (tfvec_len . Var.varType) inVec
105   let  genlabel       = mkVHDLExtId ("foldlVector" ++ (varToString inVec))
106   let  blockLabel  = mkVHDLExtId ("foldlVector" ++ (varToString startVal))
107   let  range       = AST.ToRange (AST.PrimLit "0") (AST.PrimLit $ show (len-1))
108   let  genScheme   = AST.ForGn (AST.unsafeVHDLBasicId "n") range
109   -- Make the intermediate vector
110   let  tmpVec      = AST.BDISD $ AST.SigDec (mkVHDLExtId "tmp") vecType Nothing
111   -- Get the entity name and port names
112   let entity_id   = ent_id entity
113   let argports    = map (Monad.liftM fst) (ent_args entity)
114   let resport     = (Monad.liftM fst) (ent_res entity)
115     -- Return the generate functions
116   let genSm       = AST.GenerateSm genlabel genScheme [] 
117                       [ AST.CSGSm (genFirstCell (entity_id, argports, resport) 
118                                     [startVal, inVec, resVal])
119                       , AST.CSGSm (genOtherCell (entity_id, argports, resport) 
120                                     [startVal, inVec, resVal])
121                       , AST.CSGSm (genLastCell (entity_id, argports, resport) 
122                                     [startVal, inVec, resVal])
123                       ]
124   return $ AST.CSBSm $ AST.BlockSm blockLabel [] (AST.PMapAspect []) [tmpVec] [AST.CSGSm genSm]
125   where
126     genFirstCell (entity_id, argports, resport) [startVal, inVec, resVal] = cellGn
127       where
128         cellLabel    = mkVHDLExtId "firstcell"
129         cellGenScheme = AST.IfGn ((AST.PrimName $ AST.NSimple nPar)  AST.:=: (AST.PrimLit "0"))
130         tmpId       = mkVHDLExtId "tmp"
131         nPar        = AST.unsafeVHDLBasicId "n"
132         -- Assign the ports
133         inport1     = mkAssocElem (argports!!0) (varToString startVal)
134         inport2     = mkAssocElemIndexed (argports!!1) (varToVHDLId inVec) nPar 
135         outport     = mkAssocElemIndexed resport tmpId nPar
136         portassigns = Maybe.catMaybes [inport1,inport2,outport]
137         -- Generate the portmap
138         mapLabel    = "cell" ++ (AST.fromVHDLId entity_id)
139         compins     = mkComponentInst mapLabel entity_id portassigns
140         -- Return the generate functions
141         cellGn       = AST.GenerateSm cellLabel cellGenScheme [] [compins]
142     genOtherCell (entity_id, argports, resport) [startVal, inVec, resVal] = cellGn
143       where
144         len         = (tfvec_len . Var.varType) inVec
145         cellLabel    = mkVHDLExtId "othercell"
146         cellGenScheme = AST.IfGn $ AST.And ((AST.PrimName $ AST.NSimple nPar)  AST.:>: (AST.PrimLit "0"))
147                                 ((AST.PrimName $ AST.NSimple nPar)  AST.:<: (AST.PrimLit $ show (len-1)))
148         tmpId       = mkVHDLExtId "tmp"
149         nPar        = AST.unsafeVHDLBasicId "n"
150         -- Assign the ports
151         inport1     = mkAssocElemIndexed (argports!!0) tmpId (AST.unsafeVHDLBasicId "n-1")
152         inport2     = mkAssocElemIndexed (argports!!1) (varToVHDLId inVec) nPar 
153         outport     = mkAssocElemIndexed resport tmpId nPar
154         portassigns = Maybe.catMaybes [inport1,inport2,outport]
155         -- Generate the portmap
156         mapLabel    = "cell" ++ (AST.fromVHDLId entity_id)
157         compins     = mkComponentInst mapLabel entity_id portassigns
158         -- Return the generate functions
159         cellGn      = AST.GenerateSm cellLabel cellGenScheme [] [compins]
160     genLastCell (entity_id, argports, resport) [startVal, inVec, resVal] = cellGn
161       where
162         len         = (tfvec_len . Var.varType) inVec
163         cellLabel    = mkVHDLExtId "lastCell"
164         cellGenScheme = AST.IfGn ((AST.PrimName $ AST.NSimple nPar)  AST.:=: (AST.PrimLit $ show (len-1)))
165         tmpId       = mkVHDLExtId "tmp"
166         nPar        = AST.unsafeVHDLBasicId "n"
167         -- Assign the ports
168         inport1     = mkAssocElemIndexed (argports!!0) tmpId (AST.unsafeVHDLBasicId "n-1")
169         inport2     = mkAssocElemIndexed (argports!!1) (varToVHDLId inVec) nPar 
170         outport     = mkAssocElemIndexed resport tmpId nPar
171         portassigns = Maybe.catMaybes [inport1,inport2,outport]
172         -- Generate the portmap
173         mapLabel    = "cell" ++ (AST.fromVHDLId entity_id)
174         compins     = mkComponentInst mapLabel entity_id portassigns
175         -- Generate the output assignment
176         assign      = mkUncondAssign (Left resVal) (AST.PrimName (AST.NIndexed (AST.IndexedName 
177                               (AST.NSimple tmpId) [AST.PrimLit $ show (len-1)])))
178         -- Return the generate functions
179         cellGn      = AST.GenerateSm cellLabel cellGenScheme [] [compins,assign]
180
181
182 -- Returns the VHDLId of the vector function with the given name for the given
183 -- element type. Generates -- this function if needed.
184 vectorFunId :: Type.Type -> String -> VHDLSession AST.VHDLId
185 vectorFunId el_ty fname = do
186   elemTM <- vhdl_ty el_ty
187   -- TODO: This should not be duplicated from mk_vector_ty. Probably but it in
188   -- the VHDLState or something.
189   let vectorTM = mkVHDLExtId $ "vector_" ++ (AST.fromVHDLId elemTM)
190   typefuns <- getA vsTypeFuns
191   case Map.lookup (OrdType el_ty, fname) typefuns of
192     -- Function already generated, just return it
193     Just (id, _) -> return id
194     -- Function not generated yet, generate it
195     Nothing -> do
196       let functions = genUnconsVectorFuns elemTM vectorTM
197       case lookup fname functions of
198         Just body -> do
199           modA vsTypeFuns $ Map.insert (OrdType el_ty, fname) (function_id, body)
200           return function_id
201         Nothing -> error $ "I don't know how to generate vector function " ++ fname
202   where
203     function_id = mkVHDLExtId fname
204
205 genUnconsVectorFuns :: AST.TypeMark -- ^ type of the vector elements
206                     -> AST.TypeMark -- ^ type of the vector
207                     -> [(String, AST.SubProgBody)]
208 genUnconsVectorFuns elemTM vectorTM  = 
209   [ (exId, AST.SubProgBody exSpec      []                  [exExpr])
210   , (replaceId, AST.SubProgBody replaceSpec [AST.SPVD replaceVar] [replaceExpr,replaceRet])
211   , (headId, AST.SubProgBody headSpec    []                  [headExpr])
212   , (lastId, AST.SubProgBody lastSpec    []                  [lastExpr])
213   , (initId, AST.SubProgBody initSpec    [AST.SPVD initVar]  [initExpr, initRet])
214   , (tailId, AST.SubProgBody tailSpec    [AST.SPVD tailVar]  [tailExpr, tailRet])
215   , (takeId, AST.SubProgBody takeSpec    [AST.SPVD takeVar]  [takeExpr, takeRet])
216   , (dropId, AST.SubProgBody dropSpec    [AST.SPVD dropVar]  [dropExpr, dropRet])
217   , (plusgtId, AST.SubProgBody plusgtSpec  [AST.SPVD plusgtVar] [plusgtExpr, plusgtRet])
218   , (emptyId, AST.SubProgBody emptySpec   [AST.SPCD emptyVar] [emptyExpr])
219   , (singletonId, AST.SubProgBody singletonSpec [AST.SPVD singletonVar] [singletonRet])
220   , (copyId, AST.SubProgBody copySpec    [AST.SPVD copyVar]      [copyExpr])
221   ]
222   where 
223     ixPar   = AST.unsafeVHDLBasicId "ix"
224     vecPar  = AST.unsafeVHDLBasicId "vec"
225     nPar    = AST.unsafeVHDLBasicId "n"
226     iId     = AST.unsafeVHDLBasicId "i"
227     iPar    = iId
228     aPar    = AST.unsafeVHDLBasicId "a"
229     resId   = AST.unsafeVHDLBasicId "res"
230     exSpec = AST.Function (mkVHDLExtId exId) [AST.IfaceVarDec vecPar vectorTM,
231                                AST.IfaceVarDec ixPar  naturalTM] elemTM
232     exExpr = AST.ReturnSm (Just $ AST.PrimName $ AST.NIndexed 
233               (AST.IndexedName (AST.NSimple vecPar) [AST.PrimName $ 
234                 AST.NSimple ixPar]))
235     replaceSpec = AST.Function (mkVHDLExtId replaceId)  [ AST.IfaceVarDec vecPar vectorTM
236                                           , AST.IfaceVarDec iPar   naturalTM
237                                           , AST.IfaceVarDec aPar   elemTM
238                                           ] vectorTM 
239        -- variable res : fsvec_x (0 to vec'length-1);
240     replaceVar =
241          AST.VarDec resId 
242                 (AST.SubtypeIn vectorTM
243                   (Just $ AST.ConstraintIndex $ AST.IndexConstraint 
244                    [AST.ToRange (AST.PrimLit "0")
245                             (AST.PrimName (AST.NAttribute $ 
246                               AST.AttribName (AST.NSimple vecPar) (mkVHDLBasicId lengthId) Nothing) AST.:-:
247                                 (AST.PrimLit "1"))   ]))
248                 Nothing
249        --  res AST.:= vec(0 to i-1) & a & vec(i+1 to length'vec-1)
250     replaceExpr = AST.NSimple resId AST.:=
251            (vecSlice (AST.PrimLit "0") (AST.PrimName (AST.NSimple iPar) AST.:-: AST.PrimLit "1") AST.:&:
252             AST.PrimName (AST.NSimple aPar) AST.:&: 
253              vecSlice (AST.PrimName (AST.NSimple iPar) AST.:+: AST.PrimLit "1")
254                       ((AST.PrimName (AST.NAttribute $ 
255                                 AST.AttribName (AST.NSimple vecPar) (mkVHDLBasicId lengthId) Nothing)) 
256                                                               AST.:-: AST.PrimLit "1"))
257     replaceRet =  AST.ReturnSm (Just $ AST.PrimName $ AST.NSimple resId)
258     vecSlice init last =  AST.PrimName (AST.NSlice 
259                                         (AST.SliceName 
260                                               (AST.NSimple vecPar) 
261                                               (AST.ToRange init last)))
262     headSpec = AST.Function (mkVHDLExtId headId) [AST.IfaceVarDec vecPar vectorTM] elemTM
263        -- return vec(0);
264     headExpr = AST.ReturnSm (Just $ (AST.PrimName $ AST.NIndexed (AST.IndexedName 
265                     (AST.NSimple vecPar) [AST.PrimLit "0"])))
266     lastSpec = AST.Function (mkVHDLExtId lastId) [AST.IfaceVarDec vecPar vectorTM] elemTM
267        -- return vec(vec'length-1);
268     lastExpr = AST.ReturnSm (Just $ (AST.PrimName $ AST.NIndexed (AST.IndexedName 
269                     (AST.NSimple vecPar) 
270                     [AST.PrimName (AST.NAttribute $ 
271                                 AST.AttribName (AST.NSimple vecPar) (mkVHDLBasicId lengthId) Nothing) 
272                                                              AST.:-: AST.PrimLit "1"])))
273     initSpec = AST.Function (mkVHDLExtId initId) [AST.IfaceVarDec vecPar vectorTM] vectorTM 
274        -- variable res : fsvec_x (0 to vec'length-2);
275     initVar = 
276          AST.VarDec resId 
277                 (AST.SubtypeIn vectorTM
278                   (Just $ AST.ConstraintIndex $ AST.IndexConstraint 
279                    [AST.ToRange (AST.PrimLit "0")
280                             (AST.PrimName (AST.NAttribute $ 
281                               AST.AttribName (AST.NSimple vecPar) (mkVHDLBasicId lengthId) Nothing) AST.:-:
282                                 (AST.PrimLit "2"))   ]))
283                 Nothing
284        -- resAST.:= vec(0 to vec'length-2)
285     initExpr = AST.NSimple resId AST.:= (vecSlice 
286                                (AST.PrimLit "0") 
287                                (AST.PrimName (AST.NAttribute $ 
288                                   AST.AttribName (AST.NSimple vecPar) (mkVHDLBasicId lengthId) Nothing) 
289                                                              AST.:-: AST.PrimLit "2"))
290     initRet =  AST.ReturnSm (Just $ AST.PrimName $ AST.NSimple resId)
291     tailSpec = AST.Function (mkVHDLExtId tailId) [AST.IfaceVarDec vecPar vectorTM] vectorTM
292        -- variable res : fsvec_x (0 to vec'length-2); 
293     tailVar = 
294          AST.VarDec resId 
295                 (AST.SubtypeIn vectorTM
296                   (Just $ AST.ConstraintIndex $ AST.IndexConstraint 
297                    [AST.ToRange (AST.PrimLit "0")
298                             (AST.PrimName (AST.NAttribute $ 
299                               AST.AttribName (AST.NSimple vecPar) (mkVHDLBasicId lengthId) Nothing) AST.:-:
300                                 (AST.PrimLit "2"))   ]))
301                 Nothing       
302        -- res AST.:= vec(1 to vec'length-1)
303     tailExpr = AST.NSimple resId AST.:= (vecSlice 
304                                (AST.PrimLit "1") 
305                                (AST.PrimName (AST.NAttribute $ 
306                                   AST.AttribName (AST.NSimple vecPar) (mkVHDLBasicId lengthId) Nothing) 
307                                                              AST.:-: AST.PrimLit "1"))
308     tailRet = AST.ReturnSm (Just $ AST.PrimName $ AST.NSimple resId)
309     takeSpec = AST.Function (mkVHDLExtId takeId) [AST.IfaceVarDec nPar   naturalTM,
310                                    AST.IfaceVarDec vecPar vectorTM ] vectorTM
311        -- variable res : fsvec_x (0 to n-1);
312     takeVar = 
313          AST.VarDec resId 
314                 (AST.SubtypeIn vectorTM
315                   (Just $ AST.ConstraintIndex $ AST.IndexConstraint 
316                    [AST.ToRange (AST.PrimLit "0")
317                                ((AST.PrimName (AST.NSimple nPar)) AST.:-:
318                                 (AST.PrimLit "1"))   ]))
319                 Nothing
320        -- res AST.:= vec(0 to n-1)
321     takeExpr = AST.NSimple resId AST.:= 
322                     (vecSlice (AST.PrimLit "1") 
323                               (AST.PrimName (AST.NSimple $ nPar) AST.:-: AST.PrimLit "1"))
324     takeRet =  AST.ReturnSm (Just $ AST.PrimName $ AST.NSimple resId)
325     dropSpec = AST.Function (mkVHDLExtId dropId) [AST.IfaceVarDec nPar   naturalTM,
326                                    AST.IfaceVarDec vecPar vectorTM ] vectorTM 
327        -- variable res : fsvec_x (0 to vec'length-n-1);
328     dropVar = 
329          AST.VarDec resId 
330                 (AST.SubtypeIn vectorTM
331                   (Just $ AST.ConstraintIndex $ AST.IndexConstraint 
332                    [AST.ToRange (AST.PrimLit "0")
333                             (AST.PrimName (AST.NAttribute $ 
334                               AST.AttribName (AST.NSimple vecPar) (mkVHDLBasicId lengthId) Nothing) AST.:-:
335                                (AST.PrimName $ AST.NSimple nPar)AST.:-: (AST.PrimLit "1")) ]))
336                Nothing
337        -- res AST.:= vec(n to vec'length-1)
338     dropExpr = AST.NSimple resId AST.:= (vecSlice 
339                                (AST.PrimName $ AST.NSimple nPar) 
340                                (AST.PrimName (AST.NAttribute $ 
341                                   AST.AttribName (AST.NSimple vecPar) (mkVHDLBasicId lengthId) Nothing) 
342                                                              AST.:-: AST.PrimLit "1"))
343     dropRet =  AST.ReturnSm (Just $ AST.PrimName $ AST.NSimple resId)
344     plusgtSpec = AST.Function (mkVHDLExtId plusgtId) [AST.IfaceVarDec aPar   elemTM,
345                                        AST.IfaceVarDec vecPar vectorTM] vectorTM 
346     -- variable res : fsvec_x (0 to vec'length);
347     plusgtVar = 
348       AST.VarDec resId 
349              (AST.SubtypeIn vectorTM
350                (Just $ AST.ConstraintIndex $ AST.IndexConstraint 
351                 [AST.ToRange (AST.PrimLit "0")
352                         (AST.PrimName (AST.NAttribute $ 
353                           AST.AttribName (AST.NSimple vecPar) (mkVHDLBasicId lengthId) Nothing))]))
354              Nothing
355     plusgtExpr = AST.NSimple resId AST.:= 
356                    ((AST.PrimName $ AST.NSimple aPar) AST.:&: 
357                     (AST.PrimName $ AST.NSimple vecPar))
358     plusgtRet = AST.ReturnSm (Just $ AST.PrimName $ AST.NSimple resId)
359     emptySpec = AST.Function (mkVHDLExtId emptyId) [] vectorTM
360     emptyVar = 
361           AST.ConstDec resId 
362               (AST.SubtypeIn vectorTM Nothing)
363               (Just $ AST.PrimLit "\"\"")
364     emptyExpr = AST.ReturnSm (Just $ AST.PrimName (AST.NSimple resId))
365     singletonSpec = AST.Function (mkVHDLExtId singletonId) [AST.IfaceVarDec aPar elemTM ] 
366                                          vectorTM
367     -- variable res : fsvec_x (0 to 0) := (others => a);
368     singletonVar = 
369       AST.VarDec resId 
370              (AST.SubtypeIn vectorTM
371                (Just $ AST.ConstraintIndex $ AST.IndexConstraint 
372                 [AST.ToRange (AST.PrimLit "0") (AST.PrimLit "0")]))
373              (Just $ AST.Aggregate [AST.ElemAssoc (Just AST.Others) 
374                                           (AST.PrimName $ AST.NSimple aPar)])
375     singletonRet = AST.ReturnSm (Just $ AST.PrimName $ AST.NSimple resId)
376     copySpec = AST.Function (mkVHDLExtId copyId) [AST.IfaceVarDec nPar   naturalTM,
377                                    AST.IfaceVarDec aPar   elemTM   ] vectorTM 
378     -- variable res : fsvec_x (0 to n-1) := (others => a);
379     copyVar = 
380       AST.VarDec resId 
381              (AST.SubtypeIn vectorTM
382                (Just $ AST.ConstraintIndex $ AST.IndexConstraint 
383                 [AST.ToRange (AST.PrimLit "0")
384                             ((AST.PrimName (AST.NSimple nPar)) AST.:-:
385                              (AST.PrimLit "1"))   ]))
386              (Just $ AST.Aggregate [AST.ElemAssoc (Just AST.Others) 
387                                           (AST.PrimName $ AST.NSimple aPar)])
388     -- return res
389     copyExpr = AST.ReturnSm (Just $ AST.PrimName $ AST.NSimple resId)