clash-lib-1.2.0: src/Clash/Primitives/Intel/ClockGen.hs
{-|
Copyright : (C) 2018, Google Inc.
License : BSD2 (see the file LICENSE)
Maintainer : Christiaan Baaij <christiaan.baaij@gmail.com>
Blackbox template functions for Clash.Intel.ClockGen.{alteraPll,altpll}
-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ViewPatterns #-}
module Clash.Primitives.Intel.ClockGen where
import Clash.Backend
import Clash.Netlist.BlackBox.Util
import Clash.Netlist.Id
import Clash.Netlist.Types
import Clash.Netlist.Util hiding (mkUniqueIdentifier)
import Control.Monad.State
import Data.Semigroup.Monad
import qualified Data.String.Interpolate.IsString as I
import Data.Text.Prettyprint.Doc.Extra
import qualified Data.Text as TextS
altpllTF :: TemplateFunction
altpllTF = TemplateFunction used valid altpllTemplate
where
used = [0..4]
valid bbCtx
| [_,_,(nm,_,_),_,_] <- bbInputs bbCtx
, Just _ <- exprToString nm
, (Identifier _ Nothing,Product {}) <- bbResult bbCtx
= True
valid _ = False
altpllQsysTF :: TemplateFunction
altpllQsysTF = TemplateFunction used valid altpllQsysTemplate
where
used = [0..4]
valid bbCtx
| [_,_,(nm,_,_),_,_] <- bbInputs bbCtx
, Just _ <- exprToString nm
, (Identifier _ Nothing,Product {}) <- bbResult bbCtx
= True
valid _ = False
alteraPllTF :: TemplateFunction
alteraPllTF = TemplateFunction used valid alteraPllTemplate
where
used = [1..20]
valid bbCtx
| ((nm,_,_):_) <- drop 3 (bbInputs bbCtx)
, Just _ <- exprToString nm
= True
valid _ = False
alteraPllQsysTF :: TemplateFunction
alteraPllQsysTF = TemplateFunction used valid alteraPllQsysTemplate
where
used = [1..20]
valid bbCtx
| ((nm,_,_):_) <- drop 3 (bbInputs bbCtx)
, Just _ <- exprToString nm
= True
valid _ = False
alteraPllTemplate
:: Backend s
=> BlackBoxContext
-> State s Doc
alteraPllTemplate bbCtx = do
let mkId = mkUniqueIdentifier Basic
locked <- mkId "locked"
pllLock <- mkId "pllLock"
alteraPll <- mkId "altera_pll_block"
alteraPll_inst <- mkId instname0
clocks <- traverse (mkUniqueIdentifier Extended)
[TextS.pack ("pllOut" ++ show n) | n <- [0..length tys - 1]]
getMon $ blockDecl alteraPll $ concat
[[ NetDecl Nothing locked rstTy
, NetDecl' Nothing Reg pllLock (Right Bool) Nothing]
,[ NetDecl Nothing clkNm ty | (clkNm,ty) <- zip clocks tys]
,[ InstDecl Comp Nothing compName alteraPll_inst [] $ concat
[[(Identifier "refclk" Nothing,In,clkTy,clk)
,(Identifier "rst" Nothing,In,rstTy,rst)]
,[(Identifier (TextS.pack ("outclk_" ++ show n)) Nothing,Out,ty,Identifier k Nothing)
|(k,ty,n) <- zip3 clocks tys [(0 :: Int)..] ]
,[(Identifier "locked" Nothing,Out,rstTy,Identifier locked Nothing)]]
, CondAssignment pllLock Bool (Identifier locked Nothing) rstTy
[(Just (BitLit H),Literal Nothing (BoolLit True))
,(Nothing ,Literal Nothing (BoolLit False))]
, Assignment result (DataCon resTy (DC (resTy,0)) $ concat
[[Identifier k Nothing | k <- clocks]
,[Identifier pllLock Nothing]])
]
]
where
(Identifier result Nothing,resTy@(Product _ _ (init -> tys))) = bbResult bbCtx
[(nm,_,_),(clk,clkTy,_),(rst,rstTy,_)] = drop 3 (bbInputs bbCtx)
Just nm' = exprToString nm
instname0 = TextS.pack nm'
compName = head (bbQsysIncName bbCtx)
altpllTemplate
:: Backend s
=> BlackBoxContext
-> State s Doc
altpllTemplate bbCtx = do
let mkId = mkUniqueIdentifier Basic
pllOut <- mkId "pllOut"
locked <- mkId "locked"
pllLock <- mkId "pllLock"
alteraPll <- mkId "altpll_block"
alteraPll_inst <- mkId instname0
getMon $ blockDecl alteraPll
[ NetDecl Nothing locked Bit
, NetDecl' Nothing Reg pllLock (Right Bool) Nothing
, NetDecl Nothing pllOut clkOutTy
, InstDecl Comp Nothing compName alteraPll_inst []
[(Identifier "clk" Nothing,In,clkTy,clk)
,(Identifier "areset" Nothing,In,rstTy,rst)
,(Identifier "c0" Nothing,Out,clkOutTy,Identifier pllOut Nothing)
,(Identifier "locked" Nothing,Out,Bit,Identifier locked Nothing)]
, CondAssignment pllLock Bool (Identifier locked Nothing) rstTy
[(Just (BitLit H),Literal Nothing (BoolLit True))
,(Nothing ,Literal Nothing (BoolLit False))]
, Assignment result (DataCon resTy (DC (resTy,0))
[Identifier pllOut Nothing
,Identifier pllLock Nothing])
]
where
[_,_,(nm,_,_),(clk,clkTy,_),(rst,rstTy,_)] = bbInputs bbCtx
(Identifier result Nothing,resTy@(Product _ _ [clkOutTy,_])) = bbResult bbCtx
Just nm' = exprToString nm
instname0 = TextS.pack nm'
compName = head (bbQsysIncName bbCtx)
altpllQsysTemplate
:: Backend s
=> BlackBoxContext
-> State s Doc
altpllQsysTemplate bbCtx = pure bbText
where
((_,stripVoid -> kdIn,_):(_,stripVoid -> kdOut,_):_) = bbInputs bbCtx
KnownDomain _ clkInPeriod _ _ _ _ = kdIn
KnownDomain _ clkOutPeriod _ _ _ _ = kdOut
clkOutFreq :: Double
clkOutFreq = (1.0 / (fromInteger clkOutPeriod * 1.0e-12)) / 1e6
clklcm = lcm clkInPeriod clkOutPeriod
clkmult = clklcm `quot` clkOutPeriod
clkdiv = clklcm `quot` clkInPeriod
-- Note [QSys file templates]
-- This QSys file template was derived from a "full" QSys system with a single
-- "altpll" IP. Module parameters were then stripped on a trial-and-error
-- basis to get a template that has the minimal number of parameters, but
-- still has the desired, working, configuration.
bbText = [I.i|<?xml version="1.0" encoding="UTF-8"?>
<system name="$${FILENAME}">
<module
name="altpll0"
kind="altpll"
enabled="1"
autoexport="1">
<parameter name="AVALON_USE_SEPARATE_SYSCLK" value="NO" />
<parameter name="BANDWIDTH" value="" />
<parameter name="BANDWIDTH_TYPE" value="AUTO" />
<parameter name="CLK0_DIVIDE_BY" value="#{clkdiv}" />
<parameter name="CLK0_DUTY_CYCLE" value="50" />
<parameter name="CLK0_MULTIPLY_BY" value="#{clkmult}" />
<parameter name="CLK0_PHASE_SHIFT" value="0" />
<parameter name="COMPENSATE_CLOCK" value="CLK0" />
<parameter name="INCLK0_INPUT_FREQUENCY" value="#{clkInPeriod}" />
<parameter name="OPERATION_MODE" value="NORMAL" />
<parameter name="PLL_TYPE" value="AUTO" />
<parameter name="PORT_ARESET" value="PORT_USED" />
<parameter name="PORT_INCLK0" value="PORT_USED" />
<parameter name="PORT_LOCKED" value="PORT_USED" />
<parameter name="PORT_clk0" value="PORT_USED" />
<parameter name="HIDDEN_IS_FIRST_EDIT" value="0" />
<parameter name="HIDDEN_PRIVATES">PT#EFF_OUTPUT_FREQ_VALUE0 #{clkOutFreq}</parameter>
</module>
</system>|]
alteraPllQsysTemplate
:: Backend s
=> BlackBoxContext
-> State s Doc
alteraPllQsysTemplate bbCtx = pure bbText
where
(_:(_,stripVoid -> kdIn,_):(_,stripVoid -> kdOutsProd,_):_) = bbInputs bbCtx
kdOuts = case kdOutsProd of
Product _ _ ps -> ps
KnownDomain {} -> [kdOutsProd]
_ -> error "internal error: not a Product or KnownDomain"
cklFreq (KnownDomain _ p _ _ _ _)
= (1.0 / (fromInteger p * 1.0e-12 :: Double)) / 1e6
cklFreq _ = error "internal error: not a KnownDomain"
clkOuts = TextS.unlines
[[I.i|<parameter name="gui_output_clock_frequency#{n}" value="#{f}"/>|]
| (n,f) <- zip [(0 :: Word)..] (map cklFreq kdOuts)
]
-- See Note [QSys file templates] on how this qsys template was derived.
bbText = [I.i|<?xml version="1.0" encoding="UTF-8"?>
<system name="$${FILENAME}">
<module
name="pll_0"
kind="altera_pll"
enabled="1"
autoexport="1">
<parameter name="gui_feedback_clock" value="Global Clock" />
<parameter name="gui_number_of_clocks" value="#{length kdOuts}" />
<parameter name="gui_operation_mode" value="direct" />
#{clkOuts}
<parameter name="gui_pll_mode" value="Integer-N PLL" />
<parameter name="gui_reference_clock_frequency" value="#{cklFreq kdIn}" />
<parameter name="gui_use_locked" value="true" />
</module>
</system>|]