module CLasH.VHDL.Testbench where
import qualified Control.Monad as Monad
import qualified Maybe
import qualified Data.Map as Map
import qualified Data.Accessor.Monad.Trans.State as MonadState
import qualified Language.VHDL.AST as AST
import qualified CoreSyn
import qualified HscTypes
import qualified Var
import qualified TysWiredIn
import CLasH.Translator.TranslatorTypes
import CLasH.VHDL.Constants
import CLasH.VHDL.Generate
import CLasH.VHDL.VHDLTools
import CLasH.VHDL.VHDLTypes
import CLasH.Normalize
import CLasH.Utils.Core.BinderTools
import CLasH.Utils.Core.CoreTools
import CLasH.Utils
createTestbench ::
Maybe Int
-> [HscTypes.CoreModule]
-> CoreSyn.CoreExpr
-> CoreSyn.CoreBndr
-> TranslatorSession CoreSyn.CoreBndr
createTestbench mCycles cores stimuli top = do
stimuli' <- reduceCoreListToHsList cores stimuli
bndr <- mkInternalVar "testbench" TysWiredIn.unitTy
let entity = createTestbenchEntity bndr
MonadState.modify tsEntities (Map.insert bndr entity)
arch <- createTestbenchArch mCycles stimuli' top entity
MonadState.modify tsArchitectures (Map.insert bndr arch)
return bndr
createTestbenchEntity ::
CoreSyn.CoreBndr
-> Entity
createTestbenchEntity bndr = entity
where
vhdl_id = mkVHDLBasicId "testbench"
ent_decl = AST.EntityDec vhdl_id []
entity = Entity vhdl_id [] undefined ent_decl
createTestbenchArch ::
Maybe Int
-> [CoreSyn.CoreExpr]
-> CoreSyn.CoreBndr
-> Entity
-> TranslatorSession (Architecture, [CoreSyn.CoreBndr])
createTestbenchArch mCycles stimuli top testent= do
signature <- getEntity top
let entId = ent_id signature
iIface = ent_args signature
oIface = ent_res signature
iIds = map fst iIface
let (oId, oDec, oProc) = case oIface of
Just (id, ty) -> ( id
, [AST.SigDec id ty Nothing]
, [createOutputProc [id]])
Nothing -> (undefined, [], [])
let iDecs = map (\(vId, tm) -> AST.SigDec vId tm Nothing) iIface
let finalIDecs = iDecs ++
[AST.SigDec clockId std_logicTM (Just $ AST.PrimLit "'0'"),
AST.SigDec resetId std_logicTM (Just $ AST.PrimLit "'0'")]
let portmaps = mkAssocElems (map idToVHDLExpr iIds) (AST.NSimple oId) signature
let mIns = mkComponentInst "totest" entId portmaps
(stimuliAssigns, stimuliDecs, cycles, used) <- createStimuliAssigns mCycles stimuli (head iIds)
let finalAssigns = (AST.CSSASm (AST.NSimple resetId AST.:<==:
AST.ConWforms []
(AST.Wform [AST.WformElem (AST.PrimLit "'0'") (Just $ AST.PrimLit "0 ns"), AST.WformElem (AST.PrimLit "'1'") (Just $ AST.PrimLit "3 ns")])
Nothing)) : stimuliAssigns
let clkProc = createClkProc
let arch = AST.ArchBody
(AST.unsafeVHDLBasicId "test")
(AST.NSimple $ ent_id testent)
(map AST.BDISD (finalIDecs ++ stimuliDecs ++ oDec))
(mIns :
( (AST.CSPSm clkProc) : (fmap AST.CSPSm oProc) ++ finalAssigns ) )
return (arch, top : used)
createStimuliAssigns ::
Maybe Int
-> [CoreSyn.CoreExpr]
-> AST.VHDLId
-> TranslatorSession ( [AST.ConcSm]
, [AST.SigDec]
, Int
, [CoreSyn.CoreBndr])
createStimuliAssigns mCycles [] _ = return ([], [], Maybe.maybe 0 id mCycles, [])
createStimuliAssigns mCycles stimuli signal = do
let genWformElem time stim = (AST.WformElem stim (Just $ AST.PrimLit (show time ++ " ns")))
let inputlen = length stimuli
assigns <- Monad.zipWithM createStimulans stimuli [0..inputlen]
let (stimuli_sms, resvars, useds) = unzip3 assigns
sig_dec_maybes <- mapM mkSigDec resvars
let sig_decs = Maybe.catMaybes sig_dec_maybes
outps <- mapM (\x -> MonadState.lift tsType (varToVHDLExpr x)) resvars
let wformelems = zipWith genWformElem [0,10..] outps
let inassign = AST.CSSASm $ AST.NSimple signal AST.:<==: AST.ConWforms [] (AST.Wform wformelems) Nothing
case (concat stimuli_sms) of
[] -> return ([inassign], [], inputlen, concat useds)
stims -> return (stims ++ [inassign], sig_decs, inputlen, concat useds)
createStimulans ::
CoreSyn.CoreExpr
-> Int
-> TranslatorSession ( [AST.ConcSm]
, Var.Var
, [CoreSyn.CoreBndr])
createStimulans expr cycl = do
expr <- normalizeExpr ("test input #" ++ show cycl) expr
let ([], binds, res) = splitNormalized expr
(stimulansbindss, useds) <- unzipM $ Monad.mapM mkConcSm binds
sig_dec_maybes <- mapM (mkSigDec . fst) (filter ((/=res).fst) binds)
let sig_decs = map (AST.BDISD) (Maybe.catMaybes sig_dec_maybes)
let block_label = mkVHDLExtId ("testcycle_" ++ (show cycl))
let block = AST.BlockSm block_label [] (AST.PMapAspect []) sig_decs (concat stimulansbindss)
case (sig_decs,(concat stimulansbindss)) of
([],[]) -> return ([], res, concat useds)
otherwise -> return ([AST.CSBSm block], res, concat useds)
createClkProc :: AST.ProcSm
createClkProc = AST.ProcSm (AST.unsafeVHDLBasicId "clkproc") [] sms
where sms =
[AST.WaitFor $ AST.PrimLit "5 ns",
AST.NSimple clockId `AST.SigAssign`
AST.Wform [AST.WformElem (AST.Not (AST.PrimName $ AST.NSimple clockId)) Nothing]]
createOutputProc :: [AST.VHDLId]
-> AST.ProcSm
createOutputProc outs =
AST.ProcSm (AST.unsafeVHDLBasicId "writeoutput")
[clockId]
[AST.IfSm clkPred (writeOuts outs) [] Nothing]
where clkPred = AST.PrimName (AST.NAttribute $ AST.AttribName (AST.NSimple clockId)
(AST.NSimple eventId)
Nothing ) `AST.And`
(AST.PrimName (AST.NSimple clockId) AST.:=: AST.PrimLit "'1'")
writeOuts :: [AST.VHDLId] -> [AST.SeqSm]
writeOuts [] = []
writeOuts [i] = [writeOut i (AST.PrimLit "LF")]
writeOuts (i:is) = writeOut i (AST.PrimLit "HT") : writeOuts is
writeOut outSig suffix =
genExprPCall2 writeId
(AST.PrimName $ AST.NSimple outputId)
((genExprFCall showId (AST.PrimName $ AST.NSimple outSig)) AST.:&: suffix)