module ForSyDe.Deep.Backend.VHDL.TestBench
(writeVHDLTestBench,
parseTestBenchOut) where
import ForSyDe.Deep.Backend.VHDL.Constants
import ForSyDe.Deep.Backend.VHDL.AST
import ForSyDe.Deep.Backend.VHDL.Translate
import ForSyDe.Deep.Backend.VHDL.Traverse.VHDLM
import ForSyDe.Deep.Backend.VHDL.Generate
import ForSyDe.Deep.Backend.VHDL.FileIO
import ForSyDe.Deep.Ids
import ForSyDe.Deep.System.SysDef
import qualified Language.Haskell.TH as TH (Exp)
import Control.Monad.State
import Data.List (transpose)
import System.Directory
import System.FilePath
parseTestBenchOut :: String
-> VHDLM [[String]]
parseTestBenchOut str = do
outN <- gets (length.oIface.globalSysDef.global)
case tabSeparatedRows of
[] -> return (replicate outN [])
_ -> return $ transpose tabSeparatedRows
where tabSeparatedRows = ((map (unintersperse '\t')).lines) str
unintersperse _ [] = []
unintersperse e (c:cs)
| c == e = if null cs then [[],[]]
else [] : unintersperse e cs
| otherwise = let rest = unintersperse e cs in
case rest of
[] -> [[c]]
(a:as) -> (c:a):as
writeVHDLTestBench :: Maybe Int
-> [[TH.Exp]]
-> VHDLM Int
writeVHDLTestBench mCycles stimuli = do
sys <- gets (globalSysDef.global)
let sysId = sid sys
cxt = genVHDLTestBenchContext sysId
ent = genVHDLTestBenchEntity sysId
(arch, cycles) <- genVHDLTestBenchArch mCycles stimuli
let design = DesignFile cxt [LUEntity ent, LUArch arch]
tbdir = sysId </> "vhdl" </> "test"
tbpath = tbdir </> (sysId ++ "_tb.vhd")
liftIO $ createDirectoryIfMissing True tbdir
liftIO $ writeDesignFile design tbpath
return cycles
genVHDLTestBenchContext :: SysId
-> [ContextItem]
genVHDLTestBenchContext id = commonContextClause ++
[Library libId,
Use $ NSelected (NSimple libId :.: SSimple typesId) :.: All,
Use $ NSelected (NSimple stdId :.: SSimple textioId) :.: All]
where libId = unsafeVHDLBasicId (id ++ "_lib")
genVHDLTestBenchEntity :: SysId
-> EntityDec
genVHDLTestBenchEntity id = EntityDec (unsafeVHDLBasicId (id ++ "_tb")) []
genVHDLTestBenchArch :: Maybe Int
-> [[TH.Exp]]
-> VHDLM (ArchBody, Int)
genVHDLTestBenchArch mCycles stimuli = do
sys <- gets (globalSysDef.global)
let sysId = sid sys
iface = iIface sys
oface = oIface sys
l = logic sys
iIds = map fst iface
iVHDLIds = map unsafeVHDLExtId iIds
oIds = map fst oface
iDecs <- mapM
(\(pId, t) -> transVHDLName2SigDec (unsafeVHDLExtId pId) t Nothing) iface
let finalIDecs = iDecs ++
[SigDec clockId std_logicTM (Just $ PrimLit "'0'"),
SigDec resetId std_logicTM (Just $ PrimLit "'0'")]
(mIns, outDecs) <-
transSysIns2CompIns l
(unsafeVHDLBasicId "totest")
iVHDLIds
(map (\(id, t) -> (unsafeVHDLExtId id,t)) oface)
sysId
iIds
oIds
(stimuliAssigns, cycles) <- genStimuliAssigns mCycles stimuli iVHDLIds
let finalAssigns =
(NSimple resetId :<==:
ConWforms []
(Wform [WformElem (PrimLit "'1'") (Just $ PrimLit "3 ns")])
Nothing) : stimuliAssigns
clkProc = genClkProc
outputProc = genOutputProc (map unsafeVHDLExtId oIds)
return $ (ArchBody
(unsafeVHDLBasicId "test")
(NSimple $ unsafeVHDLBasicId (sysId ++ "_tb"))
(map BDISD (finalIDecs ++ outDecs))
( maybe [] (\s -> [CSISm s]) mIns ++
( (CSPSm clkProc) : (CSPSm outputProc) : (map CSSASm finalAssigns) ) ),
cycles)
genStimuliAssigns :: Maybe Int
-> [[TH.Exp]]
-> [VHDLId]
-> VHDLM ([ConSigAssignSm], Int)
genStimuliAssigns mCycles [] _ = return ([], maybe 0 id mCycles)
genStimuliAssigns mCycles stimuli signals = do
let genWformElem time thExp =
do vExp <- transExp2VHDL thExp
return (WformElem vExp (Just $ PrimLit (show time ++ " ns")))
wformElems <- mapM (zipWithM genWformElem ([0,10..] :: [Int])) stimuli
let (normWformElems, cycles) = normalize maxCycles wformElems
if cycles == 0
then return ([],0)
else return
(zipWith
(\s elems -> NSimple s :<==: ConWforms [] (Wform elems) Nothing)
signals
normWformElems,
cycles)
where maxCycles = maybe (-1) id mCycles
normalize :: Int
-> [[a]]
-> ([[a]], Int)
normalize max xss
| any null xss || max == 0 = (replicate l [], 0)
| otherwise = let (transres, acum) = normalize' max (transpose xss)
in (transpose transres, acum)
where l = length xss
normalize' max (xs:xss)
| length xs == l && max /= 0 =
let (nextlist, nextacum) = normalize' (max-1) xss
in (xs : nextlist, nextacum+1)
normalize' _ _ = ([], 0)
genClkProc :: ProcSm
genClkProc = ProcSm (unsafeVHDLBasicId "clkproc") [] sms
where sms =
[WaitFor $ PrimLit "5 ns",
NSimple clockId `SigAssign`
Wform [WformElem (Not (PrimName $ NSimple clockId)) Nothing]]
genOutputProc :: [VHDLId]
-> ProcSm
genOutputProc outs =
ProcSm (unsafeVHDLBasicId "writeoutput")
[clockId]
[IfSm clkPred (writeOuts outs) [] Nothing]
where clkPred = PrimName (NAttribute $ AttribName (NSimple clockId)
eventId
Nothing ) `And`
(PrimName (NSimple clockId) :=: PrimLit "'1'")
writeOuts [] = []
writeOuts [i] = [writeOut i (PrimLit "LF")]
writeOuts (i:is) = writeOut i (PrimLit "HT") : writeOuts is
writeOut outSig suffix =
genExprProcCall2 writeId
(PrimName $ NSimple outputId)
(genExprFCall1 showId (PrimName $ NSimple outSig) :&:
suffix)