+ (AST.NSimple vhdl_id)
+ (map AST.BDISD signal_decls)
+ (state_procs ++ inport_assigns ++ outport_assigns ++ statements)
+
+-- | Sorts a map modeled as a list of (key,value) pairs by key
+sortMap :: Ord a => [(a, b)] -> [(a, b)]
+sortMap = List.sortBy (\(a, _) (b, _) -> compare a b)
+
+-- | Generate procs for state variables
+createStateProcs ::
+ [(Int, AST.VHDLId)]
+ -- ^ The sorted list of signals that should be assigned
+ -- to each state
+ -> [(Int, AST.VHDLId)]
+ -- ^ The sorted list of signals that contain each new state
+ -> [AST.ProcSm] -- ^ The resulting procs
+
+createStateProcs ((old_num, old_id):olds) ((new_num, new_id):news) =
+ if (old_num == new_num)
+ then
+ AST.ProcSm label [clk] [statement] : createStateProcs olds news
+ else
+ error "State numbers don't match!"
+ where
+ label = mkVHDLId $ "state_" ++ (show old_num)
+ clk = mkVHDLId "clk"
+ rising_edge = AST.NSimple $ mkVHDLId "rising_edge"
+ wform = AST.Wform [AST.WformElem (AST.PrimName $ AST.NSimple $ new_id) Nothing]
+ assign = AST.SigAssign (AST.NSimple old_id) wform
+ rising_edge_clk = AST.PrimFCall $ AST.FCall rising_edge [Nothing AST.:=>: (AST.ADName $ AST.NSimple clk)]
+ statement = AST.IfSm rising_edge_clk [assign] [] Nothing
+
+createStateProcs [] [] = []
+
+-- Generate a VHDL entity declaration for the given function
+getEntity :: HWFunction -> [AST.IfaceSigDec] -> AST.EntityDec
+getEntity (HWFunction vhdl_id inports outport) extra_ports =
+ AST.EntityDec vhdl_id ports
+ where
+ ports =
+ (concat $ map (mkIfaceSigDecs AST.In) inports)
+ ++ mkIfaceSigDecs AST.Out outport
+ ++ extra_ports
+
+mkIfaceSigDecs ::
+ AST.Mode -- The port's mode (In or Out)
+ -> SignalNameMap -- The ports to generate a map for
+ -> [AST.IfaceSigDec] -- The resulting ports
+
+mkIfaceSigDecs mode (Single (port_id, ty)) =
+ [AST.IfaceSigDec port_id mode ty]
+
+mkIfaceSigDecs mode (Tuple ports) =
+ concat $ map (mkIfaceSigDecs mode) ports
+
+-- Unused values (state) don't generate ports
+mkIfaceSigDecs mode Unused =
+ []
+
+-- Create concurrent assignments of one map of signals to another. The maps
+-- should have a similar form.
+createSignalAssignments ::
+ SignalNameMap -- The signals to assign to
+ -> SignalNameMap -- The signals to assign
+ -> HsUseMap -- What function does each of the signals have?
+ -> ([AST.ConcSm], -- The resulting assignments
+ [(Int, AST.VHDLId)]) -- The resulting state -> signal mappings
+
+-- A simple assignment of one signal to another (greatly complicated because
+-- signal assignments can be conditional with multiple conditions in VHDL).
+createSignalAssignments (Single (dst, _)) (Single (src, _)) (Single Port)=
+ ([AST.CSSASm assign], [])
+ where
+ src_name = AST.NSimple src
+ src_expr = AST.PrimName src_name
+ src_wform = AST.Wform [AST.WformElem src_expr Nothing]
+ dst_name = (AST.NSimple dst)
+ assign = dst_name AST.:<==: (AST.ConWforms [] src_wform Nothing)
+
+createSignalAssignments (Tuple dsts) (Tuple srcs) (Tuple uses) =
+ concat_elements $ unzip $ zipWith3 createSignalAssignments dsts srcs uses
+
+createSignalAssignments Unused (Single (src, _)) (Single (State n)) =
+ -- Write state
+ ([], [(n, src)])
+
+createSignalAssignments (Single (dst, _)) Unused (Single (State n)) =
+ -- Read state
+ ([], [(n, dst)])
+
+createSignalAssignments dst src use =
+ error $ "Non matching source and destination: " ++ show dst ++ " <= " ++ show src ++ " (Used as " ++ show use ++ ")"
+
+type SignalNameMap = HsValueMap (AST.VHDLId, AST.TypeMark)
+
+-- | A datatype that maps each of the single values in a haskell structure to
+-- a mapto. The map has the same structure as the haskell type mapped, ie
+-- nested tuples etc.
+data HsValueMap mapto =
+ Tuple [HsValueMap mapto]
+ | Single mapto
+ | Unused
+ deriving (Show, Eq)
+
+-- | Creates a HsValueMap with the same structure as the given type, using the
+-- given function for mapping the single types.
+mkHsValueMap ::
+ ((Type, s) -> (HsValueMap mapto, s))
+ -- ^ A function to map single value Types
+ -- (basically anything but tuples) to a
+ -- HsValueMap (not limited to the Single
+ -- constructor) Also accepts and produces a
+ -- state that will be passed on between
+ -- each call to the function.
+ -> s -- ^ The initial state
+ -> Type -- ^ The type to map to a HsValueMap
+ -> (HsValueMap mapto, s) -- ^ The resulting map and state
+
+mkHsValueMap f s ty =
+ case Type.splitTyConApp_maybe ty of
+ Just (tycon, args) ->
+ if (TyCon.isTupleTyCon tycon)
+ then
+ let (args', s') = mapTuple f s args in
+ -- Handle tuple construction especially
+ (Tuple args', s')
+ else
+ -- And let f handle the rest
+ f (ty, s)
+ -- And let f handle the rest
+ Nothing -> f (ty, s)
+ where
+ mapTuple f s (ty:tys) =
+ let (map, s') = mkHsValueMap f s ty in
+ let (maps, s'') = mapTuple f s' tys in
+ (map: maps, s'')
+ mapTuple f s [] = ([], s)