--core <- GHC.compileToCoreSimplified "Adders.hs"
core <- GHC.compileToCoreSimplified "Adders.hs"
--liftIO $ printBinds (cm_binds core)
- let binds = Maybe.mapMaybe (findBind (cm_binds core)) ["full_adder", "half_adder"]
+ let binds = Maybe.mapMaybe (findBind (cm_binds core)) ["shalf_adder"]
liftIO $ printBinds binds
-- Turn bind into VHDL
let vhdl = State.evalState (mkVHDL binds) (VHDLSession 0 [])
mkVHDL binds = do
-- Add the builtin functions
mapM (uncurry addFunc) builtin_funcs
- -- Get the function signatures
- funcs <- mapM mkHWFunction binds
- -- Add them to the session
- mapM (uncurry addFunc) funcs
- let entities = map getEntity (snd $ unzip funcs)
- -- Create architectures for them
- archs <- mapM getArchitecture binds
+ -- Create entities and architectures for them
+ units <- mapM expandBind binds
return $ AST.DesignFile
[]
- ((map AST.LUEntity entities) ++ (map AST.LUArch archs))
+ (concat units)
printTarget (Target (TargetFile file (Just x)) obj Nothing) =
print $ show file
-- Accepts a port name and an argument to map to it.
-- Returns the appropriate line for in the port map
-getPortMapEntry (Signal portname _) (Signal signame _) =
+getPortMapEntry (Single (portname, _)) (Single (signame, _)) =
(Just portname) AST.:=>: (AST.ADName (AST.NSimple signame))
expandExpr ::
[(CoreBndr, SignalNameMap)]
res_signal')
expandExpr binds (Var id) =
- return ([], [], [], Signal signal_id ty)
+ return ([], [], [], Single (signal_id, ty))
where
-- Lookup the id in our binds map
- Signal signal_id ty = Maybe.fromMaybe
+ Single (signal_id, ty) = Maybe.fromMaybe
(error $ "Argument " ++ getOccString id ++ "is unknown")
(lookup id binds)
-- Generate a unique name for the application
appname <- uniqueName ("app_" ++ name)
-- Lookup the hwfunction to instantiate
- HWFunction vhdl_id inports outport <- getHWFunc name
+ HWFunction vhdl_id inports outport <- getHWFunc (appToHsFunction f args ty)
-- Expand each of the args, so each of them is reduced to output signals
(arg_signal_decls, arg_statements, arg_res_signals) <- expandArgs binds args
-- Bind each of the input ports to the expanded arguments
-> SignalNameMap -- The signals to bind to it
-> [AST.AssocElem] -- The resulting port map lines
-createAssocElems (Signal port_id _) (Signal signal_id _) =
+createAssocElems (Single (port_id, _)) (Single (signal_id, _)) =
[(Just port_id) AST.:=>: (AST.ADName (AST.NSimple signal_id))]
createAssocElems (Tuple ports) (Tuple signals) =
SignalNameMap
-> [AST.SigDec]
-mkSignalsFromMap (Signal id ty) =
+mkSignalsFromMap (Single (id, ty)) =
[mkSignalFromId id ty]
mkSignalsFromMap (Tuple signals) =
-- Map the output port of a component to the output port of the containing
-- entity.
-mapOutputPorts (Signal portname _) (Signal signalname _) =
+mapOutputPorts (Single (portname, _)) (Single (signalname, _)) =
[(Just portname) AST.:=>: (AST.ADName (AST.NSimple signalname))]
-- Map matching output ports in the tuple
mapOutputPorts (Tuple ports) (Tuple signals) =
concat (zipWith mapOutputPorts ports signals)
+expandBind ::
+ CoreBind -- The binder to expand into VHDL
+ -> VHDLState [AST.LibraryUnit] -- The resulting VHDL
+
+expandBind (Rec _) = error "Recursive binders not supported"
+
+expandBind bind@(NonRec var expr) = do
+ -- Create the function signature
+ hwfunc <- mkHWFunction bind
+ let ty = CoreUtils.exprType expr
+ let hsfunc = mkHsFunction var ty
+ -- Add it to the session
+ addFunc hsfunc hwfunc
+ arch <- getArchitecture hwfunc expr
+ let entity = getEntity hwfunc
+ return $ [
+ AST.LUEntity entity,
+ AST.LUArch arch ]
+
getArchitecture ::
- CoreBind -- The binder to expand into an architecture
+ HWFunction -- The function to generate an architecture for
+ -> CoreExpr -- The expression that is bound to the function
-> VHDLState AST.ArchBody -- The resulting architecture
-getArchitecture (Rec _) = error "Recursive binders not supported"
-
-getArchitecture (NonRec var expr) = do
- let name = (getOccString var)
- HWFunction vhdl_id inports outport <- getHWFunc name
- sess <- State.get
+getArchitecture hwfunc expr = do
+ -- Unpack our hwfunc
+ let HWFunction vhdl_id inports outport = hwfunc
+ -- Expand the expression into an architecture body
(signal_decls, statements, arg_signals, res_signal) <- expandExpr [] expr
let inport_assigns = concat $ zipWith createSignalAssignments arg_signals inports
let outport_assigns = createSignalAssignments outport res_signal
-> SignalNameMap -- The ports to generate a map for
-> [AST.IfaceSigDec] -- The resulting ports
-mkIfaceSigDecs mode (Signal port_id ty) =
+mkIfaceSigDecs mode (Single (port_id, ty)) =
[AST.IfaceSigDec port_id mode ty]
mkIfaceSigDecs mode (Tuple ports) =
-- A simple assignment of one signal to another (greatly complicated because
-- signal assignments can be conditional with multiple conditions in VHDL).
-createSignalAssignments (Signal dst _) (Signal src _) =
+createSignalAssignments (Single (dst, _)) (Single (src, _)) =
[AST.CSSASm assign]
where
src_name = AST.NSimple src
createSignalAssignments dst src =
error $ "Non matching source and destination: " ++ show dst ++ "\nand\n" ++ show src
-data SignalNameMap =
- Tuple [SignalNameMap]
- | Signal AST.VHDLId AST.TypeMark -- A signal (or port) of the given (VDHL) type
- deriving (Show)
+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
+ 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 -> HsValueMap mapto) -- ^ A function to map single value Types
+ -- (basically anything but tuples) to a
+ -- HsValueMap (not limited to the Single
+ -- constructor)
+ -> Type -- ^ The type to map to a HsValueMap
+ -> HsValueMap mapto -- ^ The resulting map
+
+mkHsValueMap f ty =
+ case Type.splitTyConApp_maybe ty of
+ Just (tycon, args) ->
+ if (TyCon.isTupleTyCon tycon)
+ then
+ -- Handle tuple construction especially
+ Tuple (map (mkHsValueMap f) args)
+ else
+ -- And let f handle the rest
+ f ty
+ -- And let f handle the rest
+ Nothing -> f ty
-- Generate a port name map (or multiple for tuple types) in the given direction for
-- each type given.
-- Expand tuples we find
Tuple (getPortNameMapForTys name 0 args)
else -- Assume it's a type constructor application, ie simple data type
- Signal (AST.unsafeVHDLBasicId name) (vhdl_ty ty)
+ Single ((AST.unsafeVHDLBasicId name), (vhdl_ty ty))
where
(tycon, args) = Type.splitTyConApp ty
-- output ports.
mkHWFunction ::
CoreBind -- The core binder to generate the interface for
- -> VHDLState (String, HWFunction) -- The name of the function and its interface
+ -> VHDLState HWFunction -- The function interface
mkHWFunction (NonRec var expr) =
- return (name, HWFunction (mkVHDLId name) inports outport)
+ return $ HWFunction (mkVHDLId name) inports outport
where
name = getOccString var
ty = CoreUtils.exprType expr
mkHWFunction (Rec _) =
error "Recursive binders not supported"
+-- | How is a given (single) value in a function's type (ie, argument or
+-- return value) used?
+data HsValueUse =
+ Port -- ^ Use it as a port (input or output)
+ | State --- ^ Use it as state (input or output)
+ deriving (Show, Eq)
+
+-- | This type describes a particular use of a Haskell function and is used to
+-- look up an appropriate hardware description.
+data HsFunction = HsFunction {
+ hsName :: String, -- ^ What was the name of the original Haskell function?
+ hsArgs :: [HsValueMap HsValueUse], -- ^ How are the arguments used?
+ hsRes :: HsValueMap HsValueUse -- ^ How is the result value used?
+} deriving (Show, Eq)
+
+-- | Translate a function application to a HsFunction. i.e., which function
+-- do you need to translate this function application.
+appToHsFunction ::
+ Var.Var -- ^ The function to call
+ -> [CoreExpr] -- ^ The function arguments
+ -> Type -- ^ The return type
+ -> HsFunction -- ^ The needed HsFunction
+
+appToHsFunction f args ty =
+ HsFunction hsname hsargs hsres
+ where
+ mkPort = \x -> Single Port
+ hsargs = map (mkHsValueMap mkPort . CoreUtils.exprType) args
+ hsres = mkHsValueMap mkPort ty
+ hsname = getOccString f
+
+-- | Translate a top level function declaration to a HsFunction. i.e., which
+-- interface will be provided by this function. This function essentially
+-- defines the "calling convention" for hardware models.
+mkHsFunction ::
+ Var.Var -- ^ The function defined
+ -> Type -- ^ The function type (including arguments!)
+ -> HsFunction -- ^ The resulting HsFunction
+
+mkHsFunction f ty =
+ HsFunction hsname hsargs hsres
+ where
+ mkPort = mkHsValueMap (\x -> Single Port)
+ mkState = mkHsValueMap (\x -> Single State)
+ hsname = getOccString f
+ (arg_tys, res_ty) = Type.splitFunTys ty
+ -- The last argument must be state
+ state_ty = last arg_tys
+ state = mkState state_ty
+ -- All but the last argument are inports
+ inports = map mkPort (init arg_tys)
+ hsargs = inports ++ [state]
+ hsres = case splitTupleType res_ty of
+ -- Result type must be a two tuple (state, ports)
+ Just [outstate_ty, outport_ty] -> if Type.coreEqType state_ty outstate_ty
+ then
+ Tuple [state, mkPort outport_ty]
+ else
+ error $ "Input state type of function " ++ hsname ++ ": " ++ (showSDoc $ ppr state_ty) ++ " does not match output state type: " ++ (showSDoc $ ppr outstate_ty)
+ otherwise -> error $ "Return type of top-level function " ++ hsname ++ " must be a two-tuple containing a state and output ports."
+
data VHDLSession = VHDLSession {
- nameCount :: Int, -- A counter that can be used to generate unique names
- funcs :: [(String, HWFunction)] -- All functions available, indexed by name
+ nameCount :: Int, -- A counter that can be used to generate unique names
+ funcs :: [(HsFunction, HWFunction)] -- All functions available
} deriving (Show)
type VHDLState = State.State VHDLSession
-- Add the function to the session
-addFunc :: String -> HWFunction -> VHDLState ()
-addFunc name f = do
+addFunc :: HsFunction -> HWFunction -> VHDLState ()
+addFunc hsfunc hwfunc = do
fs <- State.gets funcs -- Get the funcs element from the session
- State.modify (\x -> x {funcs = (name, f) : fs }) -- Prepend name and f
+ State.modify (\x -> x {funcs = (hsfunc, hwfunc) : fs }) -- Prepend name and f
-- Lookup the function with the given name in the current session. Errors if
-- it was not found.
-getHWFunc :: String -> VHDLState HWFunction
-getHWFunc name = do
+getHWFunc :: HsFunction -> VHDLState HWFunction
+getHWFunc hsfunc = do
fs <- State.gets funcs -- Get the funcs element from the session
return $ Maybe.fromMaybe
- (error $ "Function " ++ name ++ "is unknown? This should not happen!")
- (lookup name fs)
+ (error $ "Function " ++ (hsName hsfunc) ++ "is unknown? This should not happen!")
+ (lookup hsfunc fs)
+
+-- | Splits a tuple type into a list of element types, or Nothing if the type
+-- is not a tuple type.
+splitTupleType ::
+ Type -- ^ The type to split
+ -> Maybe [Type] -- ^ The tuples element types
+
+splitTupleType ty =
+ case Type.splitTyConApp_maybe ty of
+ Just (tycon, args) -> if TyCon.isTupleTyCon tycon
+ then
+ Just args
+ else
+ Nothing
+ Nothing -> Nothing
-- Makes the given name unique by appending a unique number.
-- This does not do any checking against existing names, so it only guarantees
builtin_funcs =
[
- ("hwxor", HWFunction (mkVHDLId "hwxor") [Signal (mkVHDLId "a") vhdl_bit_ty, Signal (mkVHDLId "b") vhdl_bit_ty] (Signal (mkVHDLId "o") vhdl_bit_ty)),
- ("hwand", HWFunction (mkVHDLId "hwand") [Signal (mkVHDLId "a") vhdl_bit_ty, Signal (mkVHDLId "b") vhdl_bit_ty] (Signal (mkVHDLId "o") vhdl_bit_ty)),
- ("hwor", HWFunction (mkVHDLId "hwor") [Signal (mkVHDLId "a") vhdl_bit_ty, Signal (mkVHDLId "b") vhdl_bit_ty] (Signal (mkVHDLId "o") vhdl_bit_ty)),
- ("hwnot", HWFunction (mkVHDLId "hwnot") [Signal (mkVHDLId "i") vhdl_bit_ty] (Signal (mkVHDLId "o") vhdl_bit_ty))
+ (HsFunction "hwxor" [(Single Port), (Single Port)] (Single Port), HWFunction (mkVHDLId "hwxor") [Single (mkVHDLId "a", vhdl_bit_ty), Single (mkVHDLId "b", vhdl_bit_ty)] (Single (mkVHDLId "o", vhdl_bit_ty))),
+ (HsFunction "hwand" [(Single Port), (Single Port)] (Single Port), HWFunction (mkVHDLId "hwand") [Single (mkVHDLId "a", vhdl_bit_ty), Single (mkVHDLId "b", vhdl_bit_ty)] (Single (mkVHDLId "o", vhdl_bit_ty))),
+ (HsFunction "hwor" [(Single Port), (Single Port)] (Single Port), HWFunction (mkVHDLId "hwor") [Single (mkVHDLId "a", vhdl_bit_ty), Single (mkVHDLId "b", vhdl_bit_ty)] (Single (mkVHDLId "o", vhdl_bit_ty))),
+ (HsFunction "hwnot" [(Single Port)] (Single Port), HWFunction (mkVHDLId "hwnot") [Single (mkVHDLId "i", vhdl_bit_ty)] (Single (mkVHDLId "o", vhdl_bit_ty)))
]
vhdl_bit_ty :: AST.TypeMark