X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=Translator.hs;h=d76ff15dc12f132483ac8244857809d01482e645;hb=1e1972884f324bbe6d046e2b52b9f9ea41014889;hp=56cbe5e698c764451f3f15bb19658f58e872cca2;hpb=553b58f58b14a0bbe3421fc7c69c268d071dd4bb;p=matthijs%2Fmaster-project%2Fc%CE%BBash.git diff --git a/Translator.hs b/Translator.hs index 56cbe5e..d76ff15 100644 --- a/Translator.hs +++ b/Translator.hs @@ -7,6 +7,8 @@ import qualified Type import qualified TyCon import qualified DataCon import qualified Maybe +import qualified Module +import qualified Control.Monad.State as State import Name import Data.Generics import NameEnv ( lookupNameEnv ) @@ -16,6 +18,14 @@ import Outputable ( showSDoc, ppr ) import GHC.Paths ( libdir ) import DynFlags ( defaultDynFlags ) import List ( find ) +-- The following modules come from the ForSyDe project. They are really +-- internal modules, so ForSyDe.cabal has to be modified prior to installing +-- ForSyDe to get access to these modules. +import qualified ForSyDe.Backend.VHDL.AST as AST +import qualified ForSyDe.Backend.VHDL.Ppr +import qualified ForSyDe.Backend.Ppr +-- This is needed for rendering the pretty printed VHDL +import Text.PrettyPrint.HughesPJ (render) main = do @@ -31,13 +41,21 @@ main = --core <- GHC.compileToCoreSimplified "Adders.hs" core <- GHC.compileToCoreSimplified "Adders.hs" liftIO $ printBinds (cm_binds core) - let bind = findBind "no_carry_adder" (cm_binds core) + let bind = findBind "half_adder" (cm_binds core) let NonRec var expr = bind + -- Add the HWFunction from the bind to the session + let sess = State.execState (addF bind) (VHDLSession 0 builtin_funcs) liftIO $ putStr $ showSDoc $ ppr expr liftIO $ putStr "\n\n" - liftIO $ putStr $ getEntity bind - liftIO $ putStr $ getArchitecture bind + liftIO $ putStr $ render $ ForSyDe.Backend.Ppr.ppr $ getArchitecture sess bind return expr + where + -- Turns the given bind into VHDL + addF bind = do + -- Get the function signature + (name, f) <- mkHWFunction bind + -- Add it to the session + addFunc name f printTarget (Target (TargetFile file (Just x)) obj Nothing) = print $ show file @@ -71,48 +89,10 @@ findBind lookfor = NonRec var _ -> lookfor == (occNameString $ nameOccName $ getName var) ) --- Generate a port (or multiple for tuple types) in the given direction for --- each type given. -getPortsForTys :: String -> String -> Int -> [Type] -> String -getPortsForTys dir prefix num [] = "" -getPortsForTys dir prefix num (t:ts) = - (getPortsForTy dir (prefix ++ show num) t) ++ getPortsForTys dir prefix (num + 1) ts - -getPortsForFunTy ty = - -- All of a function's arguments become IN ports, the result becomes on - -- (or more) OUT ports. - -- Drop the first ;\n - drop 2 (getPortsForTys "in" "portin" 0 args) ++ (getPortsForTy "out" "portout" res) ++ "\n" - where - (args, res) = Type.splitFunTys ty - -getPortsForTy :: String -> String -> Type -> String -getPortsForTy dir name ty = - if (TyCon.isTupleTyCon tycon) then - -- Expand tuples we find - getPortsForTys dir name 0 args - else -- Assume it's a type constructor application, ie simple data type - let - vhdlTy = showSDoc $ ppr $ TyCon.tyConName tycon; - in - ";\n\t" ++ name ++ " : " ++ dir ++ " " ++ vhdlTy - where - (tycon, args) = Type.splitTyConApp ty - -getEntity (NonRec var expr) = - "entity " ++ name ++ " is\n" - ++ "port (\n" - ++ getPortsForFunTy ty - ++ ");\n" - ++ "end " ++ name ++ ";\n\n" - where - name = (getOccString var) - ty = CoreUtils.exprType expr - -- Accepts a port name and an argument to map to it. -- Returns the appropriate line for in the port map -getPortMapEntry binds portname (Var id) = - "\t" ++ portname ++ " => " ++ signalname ++ "\n" +getPortMapEntry binds (Port portname) (Var id) = + (Just (AST.unsafeVHDLBasicId portname)) AST.:=>: (AST.ADName (AST.NSimple (AST.unsafeVHDLBasicId signalname))) where Port signalname = Maybe.fromMaybe (error $ "Argument " ++ getOccString id ++ "is unknown") @@ -121,24 +101,25 @@ getPortMapEntry binds portname (Var id) = getPortMapEntry binds _ a = error $ "Unsupported argument: " ++ (showSDoc $ ppr a) getInstantiations :: - PortNameMap -- The arguments that need to be applied to the - -- expression. Should always be the Args - -- constructor. + VHDLSession + -> [PortNameMap] -- The arguments that need to be applied to the + -- expression. + -> PortNameMap -- The output ports that the expression should generate. -> [(CoreBndr, PortNameMap)] -- A list of bindings in effect -> CoreSyn.CoreExpr -- The expression to generate an architecture for - -> String -- The resulting VHDL code + -> [AST.ConcSm] -- The resulting VHDL code -- A lambda expression binds the first argument (a) to the binder b. -getInstantiations (Args (a:as)) binds (Lam b expr) = - getInstantiations (Args as) ((b, a):binds) expr +getInstantiations sess (a:as) outs binds (Lam b expr) = + getInstantiations sess as outs ((b, a):binds) expr -- A case expression that checks a single variable and has a single -- alternative, can be used to take tuples apart -getInstantiations args binds (Case (Var v) b _ [res]) = +getInstantiations sess args outs binds (Case (Var v) b _ [res]) = case altcon of DataAlt datacon -> if (DataCon.isTupleCon datacon) then - getInstantiations args binds' expr + getInstantiations sess args outs binds' expr else error "Data constructors other than tuples not supported" otherwise -> @@ -152,37 +133,96 @@ getInstantiations args binds (Case (Var v) b _ [res]) = (lookup v binds) -- An application is an instantiation of a component -getInstantiations args binds app@(App expr arg) = - --indent ++ "F:\n" ++ (getInstantiations (' ':indent) expr) ++ "\n" ++ indent ++ "A:\n" ++ (getInstantiations (' ':indent) arg) ++ "\n" - "app : " ++ (getOccString f) ++ "\n" - ++ "port map (\n" - ++ concat (zipWith (getPortMapEntry binds) ["portin0", "portin1"] args) - ++ ");\n" +getInstantiations sess args outs binds app@(App expr arg) = + if isTupleConstructor f then + let + Tuple outports = outs + (tys, vals) = splitTupleConstructorArgs fargs + in + concat $ zipWith + (\outs' expr' -> getInstantiations sess args outs' binds expr') + outports vals + else + [AST.CSISm comp] where - ((Var f), args) = collectArgs app + ((Var f), fargs) = collectArgs app + comp = AST.CompInsSm + (AST.unsafeVHDLBasicId "app") + (AST.IUEntity (AST.NSimple (AST.unsafeVHDLBasicId compname))) + (AST.PMapAspect ports) + compname = getOccString f + hwfunc = Maybe.fromMaybe + (error $ "Function " ++ compname ++ "is unknown") + (lookup compname (funcs sess)) + HWFunction inports outport = hwfunc + ports = + zipWith (getPortMapEntry binds) inports fargs + ++ mapOutputPorts outport outs + +getInstantiations sess args outs binds expr = + error $ "Unsupported expression" ++ (showSDoc $ ppr $ expr) + +-- Is the given name a (binary) tuple constructor +isTupleConstructor :: Var.Var -> Bool +isTupleConstructor var = + Name.isWiredInName name + && Name.nameModule name == tuple_mod + && (Name.occNameString $ Name.nameOccName name) == "(,)" + where + name = Var.varName var + mod = nameModule name + tuple_mod = Module.mkModule (Module.stringToPackageId "ghc-prim") (Module.mkModuleName "GHC.Tuple") + +-- Split arguments into type arguments and value arguments This is probably +-- not really sufficient (not sure if Types can actually occur as value +-- arguments...) +splitTupleConstructorArgs :: [CoreExpr] -> ([CoreExpr], [CoreExpr]) +splitTupleConstructorArgs (e:es) = + case e of + Type t -> (e:tys, vals) + otherwise -> (tys, e:vals) + where + (tys, vals) = splitTupleConstructorArgs es + +mapOutputPorts :: + PortNameMap -- The output portnames of the component + -> PortNameMap -- The output portnames and/or signals to map these to + -> [AST.AssocElem] -- The resulting output ports -getInstantiations args binds expr = showSDoc $ ppr $ expr +-- Map the output port of a component to the output port of the containing +-- entity. +mapOutputPorts (Port portname) (Port signalname) = + [(Just (AST.unsafeVHDLBasicId portname)) AST.:=>: (AST.ADName (AST.NSimple (AST.unsafeVHDLBasicId signalname)))] -getArchitecture (NonRec var expr) = - "architecture structural of " ++ name ++ " is\n" - ++ "begin\n" - ++ getInstantiations (Args inportnames) [] expr - ++ "end structural\n" +-- Map matching output ports in the tuple +mapOutputPorts (Tuple ports) (Tuple signals) = + concat (zipWith mapOutputPorts ports signals) + +getArchitecture :: + VHDLSession + -> CoreBind -- The binder to expand into an architecture + -> AST.ArchBody -- The resulting architecture + +getArchitecture sess (Rec _) = error "Recursive binders not supported" + +getArchitecture sess (NonRec var expr) = + AST.ArchBody + (AST.unsafeVHDLBasicId "structural") + -- Use unsafe for now, to prevent pulling in ForSyDe error handling + (AST.NSimple (AST.unsafeVHDLBasicId name)) + [] + (getInstantiations sess inports outport [] expr) where name = (getOccString var) - ty = CoreUtils.exprType expr - (fargs, res) = Type.splitFunTys ty - --state = if length fargs == 1 then () else (last fargs) - ports = if length fargs == 1 then fargs else (init fargs) - inportnames = case ports of - [port] -> [getPortNameMapForTy "portin" port] - ps -> getPortNameMapForTys "portin" 0 ps + hwfunc = Maybe.fromMaybe + (error $ "Function " ++ name ++ "is unknown? This should not happen!") + (lookup name (funcs sess)) + HWFunction inports outport = hwfunc data PortNameMap = - Args [PortNameMap] -- Each of the submaps represent an argument to the - -- function. Should only occur at top level. - | Tuple [PortNameMap] + Tuple [PortNameMap] | Port String + deriving (Show) -- Generate a port name map (or multiple for tuple types) in the given direction for -- each type given. @@ -201,3 +241,51 @@ getPortNameMapForTy name ty = Port name where (tycon, args) = Type.splitTyConApp ty + +data HWFunction = HWFunction { -- A function that is available in hardware + inPorts :: [PortNameMap], + outPort :: PortNameMap + --entity :: AST.EntityDec +} deriving (Show) + +-- Turns a CoreExpr describing a function into a description of its input and +-- output ports. +mkHWFunction :: + CoreBind -- The core binder to generate the interface for + -> VHDLState (String, HWFunction) -- The name of the function and its interface + +mkHWFunction (NonRec var expr) = + return (name, HWFunction 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) + 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 + +mkHWFunction (Rec _) = + error "Recursive binders not supported" + +data VHDLSession = VHDLSession { + nameCount :: Int, -- A counter that can be used to generate unique names + funcs :: [(String, HWFunction)] -- All functions available, indexed by name +} deriving (Show) + +type VHDLState = State.State VHDLSession + +-- Add the function to the session +addFunc :: String -> HWFunction -> VHDLState () +addFunc name f = do + fs <- State.gets funcs -- Get the funcs element form the session + State.modify (\x -> x {funcs = (name, f) : fs }) -- Prepend name and f + +builtin_funcs = + [ + ("hwxor", HWFunction [Port "a", Port "b"] (Port "o")), + ("hwand", HWFunction [Port "a", Port "b"] (Port "o")) + ]