Skip to content

Commit

Permalink
Add Xilinx clock wizard support through Tcl
Browse files Browse the repository at this point in the history
  • Loading branch information
hiddemoll committed Feb 22, 2023
1 parent 031a664 commit 56cd335
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 66 deletions.
1 change: 1 addition & 0 deletions clash-lib/clash-lib.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ Library
Clash.Primitives.Sized.Signed
Clash.Primitives.Sized.Vector
Clash.Primitives.Verification
Clash.Primitives.Xilinx.ClockGen

Clash.Rewrite.Combinators
Clash.Rewrite.Types
Expand Down
54 changes: 33 additions & 21 deletions clash-lib/prims/commonverilog/Clash_Xilinx_ClockGen.primitives.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,51 @@
type: |-
clockWizard
:: ( KnownDomain domIn confIn -- ARG[0]
, KnownDomain domOut confOut ) -- ARG[1]
=> SSymbol name -- ARG[2]
-> Clock pllIn -- ARG[3]
-> Reset pllIn -- ARG[4]
-> (Clock pllOut, Enable pllOut)
, KnownDomain domOut confOut -- ARG[1]
, KnownDomain domPllLock confPllLock ) -- ARG[2]
=> SSymbol name -- ARG[3]
-> Clock pllIn -- ARG[4]
-> Reset pllIn -- ARG[5]
-> (Clock pllOut, Signal domPllLock Bool)
template: |-
// clockWizard begin
~NAME[2] ~GENSYM[clockWizard_inst][2]
(.CLK_IN1 (~ARG[3])
,.RESET (~IF ~ISACTIVEHIGH[0] ~THEN ~ELSE ! ~FI ~ARG[4])
,.CLK_OUT1 (~RESULT[1])
,.LOCKED (~RESULT[0]));
~NAME[3] ~GENSYM[clockWizard_inst][2]
(.clk_in1 (~ARG[4])
,.reset (~IF ~ISACTIVEHIGH[0] ~THEN ~ELSE ! ~FI ~ARG[5])
,.clk_out1 (~RESULT[1])
,.locked (~RESULT[0]));
// clockWizard end
includes:
- name: clk_wiz
extension: clash.tcl
format: Haskell
templateFunction: Clash.Primitives.Xilinx.ClockGen.clockWizardTclTF
workInfo: Always
- BlackBox:
name: Clash.Xilinx.ClockGen.clockWizardDifferential
kind: Declaration
type: |-
clockWizardDifferential
:: ( KnownDomain domIn confIn -- ARG[0]
, KnownDomain domOut confOut ) -- ARG[1]
:: SSymbol name -- ARG[2]
-> Clock pllIn -- ARG[3]
, KnownDomain domOut confOut -- ARG[1]
, KnownDomain domPllLock confPllLock ) -- ARG[2]
:: SSymbol name -- ARG[3]
-> Clock pllIn -- ARG[4]
-> Reset pllIn -- ARG[5]
-> (Clock pllOut, Enable pllOut)
-> Clock pllIn -- ARG[5]
-> Reset pllIn -- ARG[6]
-> (Clock pllOut, Signal domPllLock Bool)
template: |-
// clockWizardDifferential begin
~NAME[2] ~GENSYM[clockWizardDifferential_inst][2]
(.CLK_IN1_D_clk_n (~ARG[3])
,.CLK_IN1_D_clk_n (~ARG[4])
,.RESET (~IF ~ISACTIVEHIGH[0] ~THEN ~ELSE ! ~FI ~ARG[5])
,.CLK_OUT1 (~RESULT[1])
,.LOCKED (~RESULT[0]));
~NAME[3] ~GENSYM[clockWizardDifferential_inst][2]
(.clk_in1_n (~ARG[4])
,.clk_in1_p (~ARG[5])
,.reset (~IF ~ISACTIVEHIGH[0] ~THEN ~ELSE ! ~FI ~ARG[6])
,.clk_out1 (~RESULT[1])
,.locked (~RESULT[0]));
// clockWizardDifferential end
includes:
- name: clk_wiz
extension: clash.tcl
format: Haskell
templateFunction: Clash.Primitives.Xilinx.ClockGen.clockWizardDifferentialTclTF
workInfo: Always
67 changes: 39 additions & 28 deletions clash-lib/prims/vhdl/Clash_Xilinx_ClockGen.primitives.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,73 @@
type: |-
clockWizard
:: ( KnownDomain domIn confIn -- ARG[0]
, KnownDomain domOut confOut ) -- ARG[1]
=> SSymbol name -- ARG[2]
-> Clock pllIn -- ARG[3]
-> Reset pllIn -- ARG[4]
-> (Clock pllOut, Enable pllOut)
, KnownDomain domOut confOut -- ARG[1]
, KnownDomain domPllLock confPllLock ) -- ARG[2]
=> SSymbol name -- ARG[3]
-> Clock pllIn -- ARG[4]
-> Reset pllIn -- ARG[5]
-> (Clock pllOut, Signal domPllLock Bool)
template: |-
-- clockWizard begin
~GENSYM[clockWizard][0] : block
signal ~GENSYM[pllOut][1] : std_logic;
signal ~GENSYM[locked][2] : std_logic;
signal ~GENSYM[pllLock][3] : boolean;
component ~NAME[2]
port (CLK_IN1 : in std_logic;
RESET : in std_logic;
CLK_OUT1 : out std_logic;
LOCKED : out std_logic);
component ~NAME[3]
port (clk_in1 : in std_logic;
reset : in std_logic;
clk_out1 : out std_logic;
locked : out std_logic);
end component;
begin
~GENSYM[clockWizard_inst][4] : component ~NAME[2] port map (~ARG[3],~IF ~ISACTIVEHIGH[0] ~THEN ~ARG[4] ~ELSE NOT(~ARG[4]) ~FI,~SYM[1],~SYM[2]);
~GENSYM[clockWizard_inst][4] : component ~NAME[3] port map (~ARG[4],~IF ~ISACTIVEHIGH[0] ~THEN ~ARG[5] ~ELSE NOT(~ARG[5]) ~FI,~SYM[1],~SYM[2]);
~SYM[3] <= true when ~SYM[2] = '1' else false;
~RESULT <= (~SYM[1],~SYM[3]);
end block;
-- clockWizard end
includes:
- name: clk_wiz
extension: clash.tcl
format: Haskell
templateFunction: Clash.Primitives.Xilinx.ClockGen.clockWizardTclTF
workInfo: Always
- BlackBox:
name: Clash.Xilinx.ClockGen.clockWizardDifferential
kind: Declaration
type: |-
clockWizardDifferential
:: ( KnownDomain domIn confIn -- ARG[0]
, KnownDomain domOut confOut ) -- ARG[1]
=> SSymbol name -- ARG[2]
-> Clock pllIn -- ARG[3]
-> Clock pllIn -- ARG[4]
-> Reset pllIn -- ARG[5]
-> (Clock pllOut, Enable pllOut)
clockWizard
:: ( KnownDomain domIn confIn -- ARG[0]
, KnownDomain domOut confOut -- ARG[1]
, KnownDomain domPllLock confPllLock ) -- ARG[2]
=> SSymbol name -- ARG[3]
-> Clock pllIn -- ARG[4]
-> Clock pllIn -- ARG[5]
-> Reset pllIn -- ARG[6]
-> (Clock pllOut, Signal domPllLock Bool)
template: |-
-- clockWizardDifferential begin
~GENSYM[clockWizardDifferential][0] : block
signal ~GENSYM[pllOut][1] : std_logic;
signal ~GENSYM[locked][2] : std_logic;
signal ~GENSYM[pllLock][3] : boolean;
component ~NAME[2]
port (CLK_IN1_D_clk_n : in std_logic;
CLK_IN1_D_clk_p : in std_logic;
RESET : in std_logic;
CLK_OUT1 : out std_logic;
LOCKED : out std_logic);
component ~NAME[3]
port (clk_in1_n : in std_logic;
clk_in1_p : in std_logic;
reset : in std_logic;
clk_out1 : out std_logic;
locked : out std_logic);
end component;
begin
~GENSYM[clockWizardDifferential_inst][4] : component ~NAME[2]
port map (~ARG[3],~ARG[4],~IF ~ISACTIVEHIGH[0] ~THEN ~ARG[5] ~ELSE NOT(~ARG[5]) ~FI,~SYM[1],~SYM[2]);
~GENSYM[clockWizardDifferential_inst][4] : component ~NAME[3]
port map (~ARG[4],~ARG[5],~IF ~ISACTIVEHIGH[0] ~THEN ~ARG[6] ~ELSE NOT(~ARG[6]) ~FI,~SYM[1],~SYM[2]);
~SYM[3] <= true when ~SYM[2] = '1' else false;
~RESULT <= (~SYM[1],~SYM[3]);
end block;
-- clockWizardDifferential end
includes:
- name: clk_wiz
extension: clash.tcl
format: Haskell
templateFunction: Clash.Primitives.Xilinx.ClockGen.clockWizardDifferentialTclTF
workInfo: Always
3 changes: 3 additions & 0 deletions clash-lib/src/Clash/Driver.hs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ import qualified Clash.Primitives.GHC.Word as P
import qualified Clash.Primitives.Intel.ClockGen as P
import qualified Clash.Primitives.Prelude as P
import qualified Clash.Primitives.Verification as P
import qualified Clash.Primitives.Xilinx.ClockGen as P
import Clash.Primitives.Types
import Clash.Signal.Internal
import Clash.Unique (Unique, getUnique)
Expand Down Expand Up @@ -602,6 +603,8 @@ knownTemplateFunctions =
, ('P.alteraPllTF, P.alteraPllTF)
, ('P.altpllTF, P.altpllTF)
, ('P.fromIntegerTFvhdl, P.fromIntegerTFvhdl)
, ('P.clockWizardTclTF, P.clockWizardTclTF)
, ('P.clockWizardDifferentialTclTF, P.clockWizardDifferentialTclTF)
]

-- | Compiles blackbox functions and parses blackbox templates.
Expand Down
126 changes: 126 additions & 0 deletions clash-lib/src/Clash/Primitives/Xilinx/ClockGen.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
{-|
Copyright : (C) 2023, QBayLogic B.V.
2023, Google Inc.
License : BSD2 (see the file LICENSE)
Maintainer : QBayLogic B.V. <devops@qbaylogic.com>
Blackbox template functions for
Clash.Xilinx.ClockGen.{clockWizard,clockWizardDifferential}
-}

{-# LANGUAGE QuasiQuotes #-}

module Clash.Primitives.Xilinx.ClockGen where

import Clash.Backend (Backend)
import Clash.Netlist.BlackBox.Util (exprToString)
import Clash.Netlist.Types
import Clash.Netlist.Util (stripVoid)

import Control.Monad.State (State)
import qualified Data.String.Interpolate as I
import Data.Text.Prettyprint.Doc.Extra (Doc)


clockWizardTclTF :: TemplateFunction
clockWizardTclTF =
TemplateFunction used valid clockWizardTclTemplate
where
used = [0..4]
valid bbCtx
| [_,_,_,(nm,_,_),_,_] <- bbInputs bbCtx
, Just _ <- exprToString nm
, [(Identifier _ Nothing,Product {})] <- bbResults bbCtx
= True
valid _ = False

clockWizardTclTemplate
:: Backend s
=> BlackBoxContext
-> State s Doc
clockWizardTclTemplate bbCtx = pure bbText
where
((_,stripVoid -> kdIn,_):(_,stripVoid -> kdOut,_):_:(nm,_,_):_) = bbInputs bbCtx
Just compName = exprToString nm
KnownDomain _ clkInPeriod _ _ _ _ = kdIn
KnownDomain _ clkOutPeriod _ _ _ _ = kdOut
clkInFreq :: Double
clkInFreq = (1.0 / (fromInteger clkInPeriod * 1.0e-12)) / 1e6
clkOutFreq :: Double
clkOutFreq = (1.0 / (fromInteger clkOutPeriod * 1.0e-12)) / 1e6

bbText = [I.__i|
namespace eval $tclIface {
variable api 1
variable scriptPurpose createIp
variable ipName {#{compName}}

proc createIp {ipName0 args} {
create_ip \\
-name clk_wiz \\
-vendor xilinx.com \\
-library ip \\
-version 6.0 \\
-module_name $ipName0 \\
{*}$args

set_property \\
-dict [list \\
CONFIG.PRIM_IN_FREQ #{clkInFreq} \\
CONFIG.CLKOUT1_REQUESTED_OUT_FREQ #{clkOutFreq} \\
] [get_ips $ipName0]
return
}
}|]

clockWizardDifferentialTclTF :: TemplateFunction
clockWizardDifferentialTclTF =
TemplateFunction used valid clockWizardDifferentialTclTemplate
where
used = [0..5]
valid bbCtx
| [_,_,_,(nm,_,_),_,_,_] <- bbInputs bbCtx
, Just _ <- exprToString nm
, [(Identifier _ Nothing,Product {})] <- bbResults bbCtx
= True
valid _ = False

clockWizardDifferentialTclTemplate
:: Backend s
=> BlackBoxContext
-> State s Doc
clockWizardDifferentialTclTemplate bbCtx = pure bbText
where
((_,stripVoid -> kdIn,_):(_,stripVoid -> kdOut,_):_:(nm,_,_):_) = bbInputs bbCtx
Just compName = exprToString nm
KnownDomain _ clkInPeriod _ _ _ _ = kdIn
KnownDomain _ clkOutPeriod _ _ _ _ = kdOut
clkInFreq :: Double
clkInFreq = (1.0 / (fromInteger clkInPeriod * 1.0e-12)) / 1e6
clkOutFreq :: Double
clkOutFreq = (1.0 / (fromInteger clkOutPeriod * 1.0e-12)) / 1e6

bbText = [I.__i|
namespace eval $tclIface {
variable api 1
variable scriptPurpose createIp
variable ipName {#{compName}}

proc createIp {ipName0 args} {
create_ip \\
-name clk_wiz \\
-vendor xilinx.com \\
-library ip \\
-version 6.0 \\
-module_name $ipName0 \\
{*}$args

set_property \\
-dict [list \\
CONFIG.PRIM_SOURCE Differential_clock_capable_pin \\
CONFIG.PRIM_IN_FREQ #{clkInFreq} \\
CONFIG.CLKOUT1_REQUESTED_OUT_FREQ #{clkOutFreq} \\
] [get_ips $ipName0]
return
}
}|]

0 comments on commit 56cd335

Please sign in to comment.