forsyde-deep-0.2.0: src/ForSyDe/Deep/Backend/VHDL/Traverse.hs
-----------------------------------------------------------------------------
-- |
-- Module : ForSyDe.Deep.Backend.VHDL.Traverse
-- Copyright : (c) ES Group, KTH/ICT/ES 2007-2013
-- License : BSD-style (see the file LICENSE)
--
-- Maintainer : forsyde-dev@ict.kth.se
-- Stability : experimental
-- Portability : portable
--
-- This module provides specialized Netlist traversing functions aimed at
-- VHDL compilation.
-----------------------------------------------------------------------------
module ForSyDe.Deep.Backend.VHDL.Traverse
(writeVHDLM,
module ForSyDe.Deep.Backend.VHDL.Traverse.VHDLM) where
import ForSyDe.Deep.Backend.VHDL.Traverse.VHDLM
import ForSyDe.Deep.Backend.VHDL.Translate
import ForSyDe.Deep.Backend.VHDL.Generate
import ForSyDe.Deep.Backend.VHDL.FileIO
import ForSyDe.Deep.Backend.VHDL.AST
import ForSyDe.Deep.Backend.VHDL.Quartus (callQuartus)
import ForSyDe.Deep.Backend.VHDL.Modelsim
import ForSyDe.Deep.ForSyDeErr
import ForSyDe.Deep.System.SysDef
import ForSyDe.Deep.Process.ProcVal
import ForSyDe.Deep.Process.ProcFun
import ForSyDe.Deep.Netlist.Traverse
import ForSyDe.Deep.Netlist
import ForSyDe.Deep.OSharing
import Control.Monad.State
import System.Directory
import System.FilePath
import Data.Maybe (fromJust, isJust)
-- | Internal VHDL-Monad version of 'ForSyDe.Backend.writeVHDL'
-- (Note: the initial and final CWD will be / )
writeVHDLM :: VHDLM ()
writeVHDLM = do
-- create and change to systemName/vhdl/work
rootDir <- gets (sid.globalSysDef.global)
let workDir = rootDir </> "vhdl" </> "work"
liftIO $ createDirectoryIfMissing True workDir
liftIO $ setCurrentDirectory workDir
-- if we are in recursive mode, also write the local results
-- for the rest of the subsystems
rec <- isRecursiveSet
when rec $ do subs <- gets (subSys.globalSysDef.global)
let writeSub s =
withLocalST (initLocalST ((readURef.unPrimSysDef) s))
writeLocalVHDLM
mapM_ writeSub subs
-- write the local results for the first-level entity
writeLocalVHDLM
-- create and change to systemName/vhdl/systemName_lib
-- (remember we are in workDir)
let libDir = ".." </> rootDir ++ "_lib"
liftIO $ createDirectoryIfMissing True libDir
liftIO $ setCurrentDirectory $ libDir
-- write the global results
writeGlobalVHDLM
-- change to systemName/vhdl
liftIO $ setCurrentDirectory ".."
-- call quartus if necessary
callQuartus
-- analyze with modelsim if necessary
compile <- isCompileModelsimSet
when compile compileResultsModelsim
-- go back to the original directory
liftIO $ setCurrentDirectory (".." </> "..")
-- | Write the global traversing results (i.e. the library design file)
-- accumulated in the state of the monad
writeGlobalVHDLM :: VHDLM ()
writeGlobalVHDLM = do
gSysId <- gets (sid.globalSysDef.global)
debugMsg $ "Generating global system library for `" ++ gSysId ++ "' ...\n"
globalRes <- gets (globalRes.global)
-- We can create the id unsafely because sysId was already checked in
-- transSysDef2Ent
let libName = gSysId ++ "_lib"
libDesignFile = genLibDesignFile globalRes
liftIO $ writeDesignFile libDesignFile (libName ++ ".vhd")
-- | Traverse the netlist and write the local results (i.e. system design files)
writeLocalVHDLM :: VHDLM ()
writeLocalVHDLM = do
gSysDefVal <- gets (globalSysDef.global)
lSysDefVal <- gets (currSysDef.local)
let lSysDefId = sid lSysDefVal
debugMsg $ "Compiling system definition `" ++ lSysDefId ++ "' ...\n"
-- Obtain the netlist of the system definition
let nl = netlist lSysDefVal
-- Traverse the netlist, and get the traversing results
intOutsInfo <- traverseVHDLM nl
LocalTravResult decs stms <- gets (localRes.local)
let finalLogic = logic lSysDefVal
-- Obtain the entity declaration of the system and the VHDL identifiers
-- of the output signals.
entity@(EntityDec _ eIface) <- transSysDef2Ent finalLogic lSysDefVal
-- For each output signal, we need an assigment between its intermediate
-- signal and the final output signal declared in the entity interface.
let outIds = mapFilter (\(IfaceSigDec id _ _) -> id)
(\(IfaceSigDec _ m _) -> m == Out) eIface
outAssigns = genOutAssigns outIds intOutsInfo
finalRes = LocalTravResult decs (stms ++ outAssigns)
-- Finally, generate the design file
sysDesignFile = genSysDesignFile (sid gSysDefVal) entity finalRes
-- and write it to disk
liftIO $ writeDesignFile sysDesignFile (lSysDefId ++ ".vhd")
where mapFilter f p = foldr (\x ys -> if p x then (f x):ys else ys) []
-- | Traverse the netlist of a System Definition,
-- returning the (implicit) final traversing state and a list
-- containing the 'IntSignalInfo' of each output of the system
traverseVHDLM :: Netlist [] -> VHDLM [IntSignalInfo]
traverseVHDLM = traverseSEIO newVHDL defineVHDL
-- | \'new\' traversing function for the VHDL backend
newVHDL :: NlNode NlSignal -> VHDLM [(NlNodeOut, IntSignalInfo)]
newVHDL node = case node of
-- FIXME: Skip the case, basing the generation of tags on
-- outTags
InPort id -> do vId <- transPortId2VHDL id
return [(InPortOut, vId)]
Proc pid proc -> withProcC pid $ do
-- Obtain the VHDL id of the process
vpid <- transProcId2VHDL pid
-- function to create an intermediate signal out of the process
-- identifier and a string suffix
let procSuffSignal sigSuffix = unsafeIdAppend vpid sigSuffix
-- Multiple output tags, add a numeric suffix specifying the output
multOutTags =
zipWith (\tag n -> (tag, procSuffSignal $ outSuffix ++ show n))
(outTags node) [(1::Int)..]
case proc of
Const _ -> return [(ConstOut, procSuffSignal outSuffix)]
ZipWithNSY _ _ -> return [(ZipWithNSYOut, procSuffSignal outSuffix)]
ZipWithxSY _ _ -> return [(ZipWithxSYOut, procSuffSignal outSuffix)]
UnzipNSY _ _ _ -> return multOutTags
UnzipxSY _ _ _ _ -> return multOutTags
DelaySY _ _ -> return [(DelaySYOut, procSuffSignal outSuffix)]
SysIns _ _ ->
-- Note: Here we could use the name of the System outputs instead of
-- instanceid_out_n but ... that could cause
-- clashes with the oher signal names (we only check for the
-- of the uniqueness of all process ids within a system when
-- creating it). We could check for those clashes but it would be
-- ineffective and ilogical.
return multOutTags
where outSuffix = "_out"
-- | \'define\' traversing function for the VHDL backend
defineVHDL :: [(NlNodeOut, IntSignalInfo)]
-> NlNode IntSignalInfo
-> VHDLM ()
defineVHDL outs ins = do
case (outs,ins) of
(_, InPort _) -> return ()
(outs, Proc pid proc) -> withProcC pid $ do
-- We can unsafely transform the pid to a VHDL identifier because
-- it was checked in newVHDL
let vPid = unsafeVHDLExtId pid
case (outs, proc) of
([(ConstOut, intSig)], Const ProcVal{valAST=ast}) -> do
-- Generate a Signal declaration for the constant
let cons = expVal ast
dec <- withProcValC cons $ transVHDLName2SigDec
intSig (expTyp ast) (Just cons)
addSigDec dec
([(ZipWithNSYOut, intOut)], ZipWithNSY f intIns) -> do
-- Translate the zipWithN process to a block
-- and get the declaration of its output signal
(block, dec) <- transZipWithN2Block vPid intIns (tpfloc f) (tast f) intOut
addStm $ CSBSm block
-- Generate a signal declaration for the resulting signal
addSigDec dec
([(ZipWithxSYOut, intOut)], ZipWithxSY f intIns) -> do
-- Translate the zipWithx process to a block
-- and get the declaration of its output signal
(block, dec) <- transZipWithx2Block vPid intIns (tpfloc f) (tast f) intOut
addStm $ CSBSm block
-- Generate a signal declaration for the resulting signal
addSigDec dec
(intOuts, UnzipNSY outTypes _ intIn) -> do
-- Translate the zipWithNSY process to a block
-- and get the declaration of its output signal
(block, decs) <- transUnzipNSY2Block vPid intIn (map snd intOuts) outTypes
addStm $ CSBSm block
-- Generate a signal declaration for the resulting signals
mapM_ addSigDec decs
(intOuts, UnzipxSY typ size _ intIn) -> do
-- Translate the UnzipxSY process to a block
-- and get the declaration of its output signal
(block, decs) <- transUnzipxSY2Block vPid intIn (map snd intOuts) typ size
addStm $ CSBSm block
-- Generate a signal declaration for the resulting signals
mapM_ addSigDec decs
([(DelaySYOut, intOut)], DelaySY initExp intIn) -> do
-- Translate the delay process to a block
-- and get the declaration of its output signal
(block, dec) <- transDelay2Block vPid intIn (valAST initExp) intOut
addStm $ CSBSm block
-- Generate a signal declaration for the resulting delayed signal
addSigDec dec
(intOuts, SysIns pSys intIns) -> do
let parentSysRef = unPrimSysDef pSys
parentSysVal = readURef parentSysRef
parentLogic = logic parentSysVal
parentInIface = iIface parentSysVal
parentOutIface = oIface parentSysVal
typedOuts = zipWith (\(_, t) (_, int) -> (int,t)) parentOutIface
intOuts
parentId = sid parentSysVal
-- Translate the instance to a component instantiation
-- and get the declaration of the output signals
(mCompIns, decs) <- transSysIns2CompIns parentLogic
vPid
intIns
typedOuts
parentId
(map fst parentInIface)
(map fst parentOutIface)
when (isJust mCompIns) (addStm $ CSISm $ fromJust mCompIns)
-- Generate a signal declaration for each of the resulting signals
mapM_ addSigDec decs
-- Othewise there is a problem of inconsisten tags
_ -> intError "ForSyDe.Backend.VHDL.Traverse.defineVHDL" InconsOutTag