Make output ports optional.
authorMatthijs Kooijman <m.kooijman@student.utwente.nl>
Wed, 12 Aug 2009 10:19:27 +0000 (12:19 +0200)
committerMatthijs Kooijman <m.kooijman@student.utwente.nl>
Wed, 12 Aug 2009 10:19:27 +0000 (12:19 +0200)
This makes the output port in an Entity of the Maybe Port type, so we can
leave out the output port (for example when its type is empty). This makes
the code a bit more robus in the face of empty types.

cλash/CLasH/VHDL/Generate.hs
cλash/CLasH/VHDL/Testbench.hs
cλash/CLasH/VHDL/VHDLTools.hs
cλash/CLasH/VHDL/VHDLTypes.hs

index a6db1e0b99bb8b2e0bdfe96f1e27baa489687fec..dec1b62375a404867ec1c59f7908c2fc3befcd4e 100644 (file)
@@ -51,7 +51,7 @@ getEntity fname = Utils.makeCached fname tsEntities $ do
       -- There must be a let at top level 
       let (CoreSyn.Let binds (CoreSyn.Var res)) = letexpr
       -- TODO: Handle Nothing
-      Just res' <- mkMap res
+      res' <- mkMap res
       let vhdl_id = mkVHDLBasicId $ varToString fname ++ "_" ++ varToStringUniq fname
       let ent_decl = createEntityAST vhdl_id args' res'
       let signature = Entity vhdl_id args' res' ent_decl
@@ -81,7 +81,7 @@ getEntity fname = Utils.makeCached fname tsEntities $ do
 createEntityAST ::
   AST.VHDLId                   -- ^ The name of the function
   -> [Port]                    -- ^ The entity's arguments
-  -> Port                      -- ^ The entity's result
+  -> Maybe Port                -- ^ The entity's result
   -> AST.EntityDec             -- ^ The entity with the ent_decl filled in as well
 
 createEntityAST vhdl_id args res =
@@ -89,15 +89,16 @@ createEntityAST vhdl_id args res =
   where
     -- Create a basic Id, since VHDL doesn't grok filenames with extended Ids.
     ports = map (mkIfaceSigDec AST.In) args
-              ++ [mkIfaceSigDec AST.Out res]
+              ++ (Maybe.maybeToList res_port)
               ++ [clk_port]
     -- Add a clk port if we have state
     clk_port = AST.IfaceSigDec clockId AST.In std_logicTM
+    res_port = fmap (mkIfaceSigDec AST.Out) res
 
 -- | Create a port declaration
 mkIfaceSigDec ::
   AST.Mode                         -- ^ The mode for the port (In / Out)
-  -> (AST.VHDLId, AST.TypeMark)    -- ^ The id and type for the port
+  -> Port                          -- ^ The id and type for the port
   -> AST.IfaceSigDec               -- ^ The resulting port declaration
 
 mkIfaceSigDec mode (id, ty) = AST.IfaceSigDec id mode ty
index 235dda60c863b38f1a8616cbe71390c7bd07da50..4f20f6cf9c90470aa92b1dafd1167b56fb2eba5d 100644 (file)
@@ -70,12 +70,17 @@ createTestbenchArch mCycles stimuli top testent= do
       iIface  = ent_args signature
       oIface  = ent_res signature
       iIds    = map fst iIface
-      oId     = fst oIface
+  let (oId, oDec, oProc) = case oIface of
+        Just (id, ty) -> ( id
+                         , [AST.SigDec id ty Nothing]
+                         , [createOutputProc [id]])
+        -- No output port? Just use undefined for the output id, since it won't be
+        -- used by mkAssocElems when there is no output port.
+        Nothing -> (undefined, [], [])
   let iDecs   = map (\(vId, tm) -> AST.SigDec vId tm Nothing) iIface
   let finalIDecs = iDecs ++
                     [AST.SigDec clockId std_logicTM (Just $ AST.PrimLit "'0'"),
                      AST.SigDec resetId std_logicTM (Just $ AST.PrimLit "'0'")]
-  let oDecs   = AST.SigDec (fst oIface) (snd oIface) Nothing
   portmaps <- mkAssocElems (map idToVHDLExpr iIds) (AST.NSimple oId) signature
   let mIns    = mkComponentInst "totest" entId portmaps
   (stimuliAssigns, stimuliDecs, cycles, used) <- createStimuliAssigns mCycles stimuli (head iIds)
@@ -84,13 +89,12 @@ createTestbenchArch mCycles stimuli top testent= do
                                     (AST.Wform [AST.WformElem (AST.PrimLit "'1'") (Just $ AST.PrimLit "3 ns")])
                                     Nothing)) : stimuliAssigns
   let clkProc     = createClkProc
-  let outputProc  = createOutputProc [oId]
   let arch = AST.ArchBody
               (AST.unsafeVHDLBasicId "test")
               (AST.NSimple $ ent_id testent)
-              (map AST.BDISD (finalIDecs ++ stimuliDecs ++ [oDecs]))
+              (map AST.BDISD (finalIDecs ++ stimuliDecs ++ oDec))
               (mIns :
-                ( (AST.CSPSm clkProc) : (AST.CSPSm outputProc) : finalAssigns ) )
+                ( (AST.CSPSm clkProc) : (fmap AST.CSPSm oProc) ++ finalAssigns ) )
   return (arch, top : used)
 
 createStimuliAssigns ::
index a16ea0108f5998c7b9d123771d8f06c2e64df22b..36d35e3701c4076273d4e3272c6df8fe7457f0ae 100644 (file)
@@ -90,18 +90,16 @@ mkAssocElems ::
   -> Entity                     -- ^ The entity to map against.
   -> TranslatorSession [AST.AssocElem] -- ^ The resulting port maps
 mkAssocElems args res entity =
-    -- Create the actual AssocElems
-    return $ zipWith mkAssocElem ports sigs
+    return $ arg_maps ++ (Maybe.maybeToList res_map_maybe)
   where
-    -- Turn the ports and signals from a map into a flat list. This works,
-    -- since the maps must have an identical form by definition. TODO: Check
-    -- the similar form?
     arg_ports = ent_args entity
-    res_port  = ent_res entity
-    -- Extract the id part from the (id, type) tuple
-    ports     = map fst (res_port : arg_ports)
-    -- Translate signal numbers into names
-    sigs      = (vhdlNameToVHDLExpr res : args)
+    res_port_maybe = ent_res entity
+    -- Create an expression of res to map against the output port
+    res_expr = vhdlNameToVHDLExpr res
+    -- Map each of the input ports
+    arg_maps = zipWith mkAssocElem (map fst arg_ports) args
+    -- Map the output port, if present
+    res_map_maybe = fmap (\port -> mkAssocElem (fst port) res_expr) res_port_maybe
 
 -- | Create an VHDL port -> signal association
 mkAssocElem :: AST.VHDLId -> AST.Expr -> AST.AssocElem
index fbdf4d72932b37daedca11af577526226dec7de8..e95a0c6eac6af1bbd8fe948fc8e769079f82d2e4 100644 (file)
@@ -27,7 +27,7 @@ type Port = (AST.VHDLId, AST.TypeMark)
 data Entity = Entity { 
   ent_id     :: AST.VHDLId, -- ^ The id of the entity
   ent_args   :: [Port], -- ^ A port for each non-empty function argument
-  ent_res    :: Port, -- ^ The output port
+  ent_res    :: Maybe Port, -- ^ The output port
   ent_dec    :: AST.EntityDec -- ^ The complete entity declaration
 } deriving (Show);