--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)) ["dff"]
liftIO $ printBinds binds
-- Turn bind into VHDL
- let vhdl = State.evalState (mkVHDL binds) (VHDLSession 0 [])
+ let (vhdl, sess) = State.runState (mkVHDL binds) (VHDLSession 0 [])
liftIO $ putStr $ render $ ForSyDe.Backend.Ppr.ppr vhdl
liftIO $ ForSyDe.Backend.VHDL.FileIO.writeDesignFile vhdl "../vhdl/vhdl/output.vhdl"
+ liftIO $ putStr $ "\n\nFinal session:\n" ++ show sess
return ()
where
-- Turns the given bind into VHDL
-- Find the type of the binder
let (arg_ty, _) = Type.splitFunTy (CoreUtils.exprType lam)
-- Create signal names for the binder
- let arg_signal = getPortNameMapForTy ("xxx") arg_ty
+ -- TODO: We assume arguments are ports here
+ let arg_signal = getPortNameMapForTy ("xxx") arg_ty (useAsPort arg_ty)
-- Create the corresponding signal declarations
let signal_decls = mkSignalsFromMap arg_signal
-- Add the binder to the list of binds
res_signal')
expandExpr binds (Var id) =
- return ([], [], [], Single (signal_id, ty))
+ return ([], [], [], bind)
where
-- Lookup the id in our binds map
- Single (signal_id, ty) = Maybe.fromMaybe
+ bind = Maybe.fromMaybe
(error $ "Argument " ++ getOccString id ++ "is unknown")
(lookup id binds)
-- Bind each of the input ports to the expanded arguments
let inmaps = concat $ zipWith createAssocElems inports arg_res_signals
-- Create signal names for our result
- let res_signal = getPortNameMapForTy (appname ++ "_out") ty
+ -- TODO: We assume the result is a port here
+ let res_signal = getPortNameMapForTy (appname ++ "_out") ty (useAsPort ty)
-- Create the corresponding signal declarations
let signal_decls = mkSignalsFromMap res_signal
-- Bind each of the output ports to our output signals
expandBind bind@(NonRec var expr) = do
-- Create the function signature
- hwfunc <- mkHWFunction bind
let ty = CoreUtils.exprType expr
let hsfunc = mkHsFunction var ty
+ hwfunc <- mkHWFunction bind hsfunc
-- Add it to the session
addFunc hsfunc hwfunc
arch <- getArchitecture hwfunc expr
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 ::
createSignalAssignments (Tuple dsts) (Tuple srcs) =
concat $ zipWith createSignalAssignments dsts srcs
+createSignalAssignments Unused (Single (src, _)) =
+ -- Write state
+ []
+
+createSignalAssignments (Single (src, _)) Unused =
+ -- Read state
+ []
+
createSignalAssignments dst src =
- error $ "Non matching source and destination: " ++ show dst ++ "\nand\n" ++ show src
+ error $ "Non matching source and destination: " ++ show dst ++ " <= " ++ show src
type SignalNameMap = HsValueMap (AST.VHDLId, AST.TypeMark)
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
-- Generate a port name map (or multiple for tuple types) in the given direction for
-- each type given.
-getPortNameMapForTys :: String -> Int -> [Type] -> [SignalNameMap]
-getPortNameMapForTys prefix num [] = []
-getPortNameMapForTys prefix num (t:ts) =
- (getPortNameMapForTy (prefix ++ show num) t) : getPortNameMapForTys prefix (num + 1) ts
+getPortNameMapForTys :: String -> Int -> [Type] -> [HsUseMap] -> [SignalNameMap]
+getPortNameMapForTys prefix num [] [] = []
+getPortNameMapForTys prefix num (t:ts) (u:us) =
+ (getPortNameMapForTy (prefix ++ show num) t u) : getPortNameMapForTys prefix (num + 1) ts us
+
+getPortNameMapForTy :: String -> Type -> HsUseMap -> SignalNameMap
+getPortNameMapForTy name _ (Single State) =
+ Unused
-getPortNameMapForTy :: String -> Type -> SignalNameMap
-getPortNameMapForTy name ty =
+getPortNameMapForTy name ty use =
if (TyCon.isTupleTyCon tycon) then
+ let (Tuple uses) = use in
-- Expand tuples we find
- Tuple (getPortNameMapForTys name 0 args)
+ Tuple (getPortNameMapForTys name 0 args uses)
else -- Assume it's a type constructor application, ie simple data type
Single ((AST.unsafeVHDLBasicId name), (vhdl_ty ty))
where
-- output ports.
mkHWFunction ::
CoreBind -- The core binder to generate the interface for
+ -> HsFunction -- The HsFunction describing the function
-> VHDLState HWFunction -- The function interface
-mkHWFunction (NonRec var expr) =
+mkHWFunction (NonRec var expr) hsfunc =
return $ HWFunction (mkVHDLId name) inports outport
where
name = getOccString var
ty = CoreUtils.exprType expr
- (fargs, res) = Type.splitFunTys ty
- args = if length fargs == 1 then fargs else (init fargs)
- --state = if length fargs == 1 then () else (last fargs)
+ (args, res) = Type.splitFunTys ty
inports = case args of
-- Handle a single port specially, to prevent an extra 0 in the name
- [port] -> [getPortNameMapForTy "portin" port]
- ps -> getPortNameMapForTys "portin" 0 ps
- outport = getPortNameMapForTy "portout" res
+ [port] -> [getPortNameMapForTy "portin" port (head $ hsArgs hsfunc)]
+ ps -> getPortNameMapForTys "portin" 0 ps (hsArgs hsfunc)
+ outport = getPortNameMapForTy "portout" res (hsRes hsfunc)
-mkHWFunction (Rec _) =
+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)
+useAsPort = mkHsValueMap (\x -> Single Port)
+useAsState = mkHsValueMap (\x -> Single State)
+
+type HsUseMap = HsValueMap HsValueUse
+
-- | 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?
+ hsArgs :: [HsUseMap], -- ^ How are the arguments used?
+ hsRes :: HsUseMap -- ^ How is the result value used?
} deriving (Show, Eq)
-- | Translate a function application to a HsFunction. i.e., which function
mkHsFunction f ty =
HsFunction hsname hsargs hsres
where
+ hsname = getOccString f
(arg_tys, res_ty) = Type.splitFunTys ty
- mkPort = \x -> Single Port
- hsargs = map (mkHsValueMap mkPort) arg_tys
- hsres = mkHsValueMap mkPort res_ty
- hsname = getOccString f
+ -- The last argument must be state
+ state_ty = last arg_tys
+ state = useAsState state_ty
+ -- All but the last argument are inports
+ inports = map useAsPort (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, useAsPort 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
(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
-- uniqueness with other names generated by uniqueName.