From 66ef5bd26b2c02cb12e702c60668294fd80ea8c2 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Wed, 12 Aug 2009 12:19:27 +0200 Subject: [PATCH] Make output ports optional. 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\316\273ash/CLasH/VHDL/Generate.hs" | 9 +++++---- "c\316\273ash/CLasH/VHDL/Testbench.hs" | 14 +++++++++----- "c\316\273ash/CLasH/VHDL/VHDLTools.hs" | 18 ++++++++---------- "c\316\273ash/CLasH/VHDL/VHDLTypes.hs" | 2 +- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git "a/c\316\273ash/CLasH/VHDL/Generate.hs" "b/c\316\273ash/CLasH/VHDL/Generate.hs" index a6db1e0..dec1b62 100644 --- "a/c\316\273ash/CLasH/VHDL/Generate.hs" +++ "b/c\316\273ash/CLasH/VHDL/Generate.hs" @@ -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 diff --git "a/c\316\273ash/CLasH/VHDL/Testbench.hs" "b/c\316\273ash/CLasH/VHDL/Testbench.hs" index 235dda6..4f20f6c 100644 --- "a/c\316\273ash/CLasH/VHDL/Testbench.hs" +++ "b/c\316\273ash/CLasH/VHDL/Testbench.hs" @@ -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 :: diff --git "a/c\316\273ash/CLasH/VHDL/VHDLTools.hs" "b/c\316\273ash/CLasH/VHDL/VHDLTools.hs" index a16ea01..36d35e3 100644 --- "a/c\316\273ash/CLasH/VHDL/VHDLTools.hs" +++ "b/c\316\273ash/CLasH/VHDL/VHDLTools.hs" @@ -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 diff --git "a/c\316\273ash/CLasH/VHDL/VHDLTypes.hs" "b/c\316\273ash/CLasH/VHDL/VHDLTypes.hs" index fbdf4d7..e95a0c6 100644 --- "a/c\316\273ash/CLasH/VHDL/VHDLTypes.hs" +++ "b/c\316\273ash/CLasH/VHDL/VHDLTypes.hs" @@ -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); -- 2.30.2