Skip to content

Commit

Permalink
Add FINC/FDEC hiw-test
Browse files Browse the repository at this point in the history
  • Loading branch information
martijnbastiaan committed Jul 6, 2023
1 parent 0db0e73 commit 1b6a5ef
Show file tree
Hide file tree
Showing 9 changed files with 357 additions and 25 deletions.
5 changes: 3 additions & 2 deletions .github/synthesis/staging.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[
{"top": "clockControlDemo0", "stage": "bitstream"},
{"top": "simpleHardwareInTheLoopTest", "stage": "test"},
{"top": "extendedHardwareInTheLoopTest", "stage": "test"}
{"top": "extendedHardwareInTheLoopTest", "stage": "test"},
{"top": "fdecTest", "stage": "test"},
{"top": "simpleHardwareInTheLoopTest", "stage": "test"}
]
27 changes: 16 additions & 11 deletions bittide-instances/bin/Shake.hs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ import qualified Bittide.Instances.ScatterGather as ScatterGather
import qualified Bittide.Instances.Si539xSpi as Si539xSpi
import qualified Bittide.Instances.StabilityChecker as StabilityChecker
import qualified Bittide.Instances.Synchronizer as Synchronizer

import qualified Bittide.Instances.Tests.FincFdec as FincFdec

import qualified Clash.Util.Interpolate as I
import qualified Language.Haskell.TH as TH
import qualified System.Directory as Directory
Expand Down Expand Up @@ -199,6 +202,14 @@ defTarget name = Target
, targetHasTest = False
}

testTarget :: TH.Name -> Target
testTarget name = Target
{ targetName = name
, targetHasXdc = True
, targetHasVio = True
, targetHasTest = True
}

enforceValidTarget :: Target -> Target
enforceValidTarget target@Target{..}
| targetHasTest && not targetHasVio =
Expand All @@ -210,17 +221,7 @@ enforceValidTarget target@Target{..}
-- | All synthesizable targets
targets :: [Target]
targets = map enforceValidTarget
[ (defTarget 'BoardTest.simpleHardwareInTheLoopTest)
{ targetHasXdc = True
, targetHasVio = True
, targetHasTest = True
}
, (defTarget 'BoardTest.extendedHardwareInTheLoopTest)
{ targetHasXdc = True
, targetHasVio = True
, targetHasTest = True
}
, defTarget 'Calendar.switchCalendar1k
[ defTarget 'Calendar.switchCalendar1k
, defTarget 'Calendar.switchCalendar1kReducedPins
, defTarget 'ClockControl.callisto3
, defTarget 'Counter.counterReducedPins
Expand All @@ -235,6 +236,10 @@ targets = map enforceValidTarget
, defTarget 'Si539xSpi.si5391Spi
, defTarget 'StabilityChecker.stabilityChecker_3_1M
, defTarget 'Synchronizer.safeDffSynchronizer

, testTarget 'BoardTest.extendedHardwareInTheLoopTest
, testTarget 'BoardTest.simpleHardwareInTheLoopTest
, testTarget 'FincFdec.fdecTest
]

shakeOpts :: ShakeOptions
Expand Down
2 changes: 2 additions & 0 deletions bittide-instances/bittide-instances.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ library
Bittide.Instances.StabilityChecker
Bittide.Instances.Synchronizer

Bittide.Instances.Tests.FincFdec

Clash.Shake.Extra
Clash.Shake.Flags
Clash.Shake.Vivado
Expand Down
44 changes: 44 additions & 0 deletions bittide-instances/data/constraints/fdecTest.xdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# SPDX-FileCopyrightText: 2022-2023 Google LLC
#
# SPDX-License-Identifier: Apache-2.0
#
# NOTE: This configuration is only valid for the leftmost FPGA in the demo rack.
#
# Color | FPGA pin | LVLShift | Connection
# --------|---------------|---------------|---------
# Grey | PMOD0_0 | IO1 | SWDIO
# Blue | PMOD0_1 | IO2 | FINC
# Yellow | PMOD0_2 | IO3 | MOSI/SDIO
# Red | PMOD0_3 | IO4 | SCLK
# White | PMOD0_4 | IO5 | SWCLK
# Purple | PMOD0_5 | IO6 | FDEC
# Green | PMOD0_6 | IO7 | CSB
# Orange | PMOD0_7 | IO8 | MISO/SDO
# Black | Not connected | Not connected | GND (SWD)
# Brown | PMOD_GND | GND | GND (SPI)
#
# The data wire of the external reset button is connected to PMOD1_3.


# CLK_125MHZ
set_property BOARD_PART_PIN sysclk_125_p [get_ports {CLK_125MHZ_P}]
set_property BOARD_PART_PIN sysclk_125_n [get_ports {CLK_125MHZ_N}]

# USER_SMA_CLOCK
set_property -dict {IOSTANDARD LVDS PACKAGE_PIN D23} [get_ports {USER_SMA_CLOCK_P}]
set_property -dict {IOSTANDARD LVDS PACKAGE_PIN C23} [get_ports {USER_SMA_CLOCK_N}]

# GPIO_LED_0_LS
set_property BOARD_PART_PIN GPIO_LED_0_LS [get_ports {done}]
# GPIO_LED_1_LS
set_property BOARD_PART_PIN GPIO_LED_1_LS [get_ports {success}]

# PMOD0_[0..7]
# set_property -dict {IOSTANDARD LVCMOS12 PACKAGE_PIN AK25} [get_ports {SWDIO}]
set_property -dict {IOSTANDARD LVCMOS12 PACKAGE_PIN AN21} [get_ports {FINC}]
set_property -dict {IOSTANDARD LVCMOS12 PACKAGE_PIN AH18} [get_ports {MOSI}]
set_property -dict {IOSTANDARD LVCMOS12 PACKAGE_PIN AM19} [get_ports {SCLK}]
# set_property -dict {IOSTANDARD LVCMOS12 PACKAGE_PIN AE26} [get_ports {SWCLK}]
set_property -dict {IOSTANDARD LVCMOS12 PACKAGE_PIN AF25} [get_ports {FDEC}]
set_property -dict {IOSTANDARD LVCMOS12 PACKAGE_PIN AE21} [get_ports {CSB}]
set_property -dict {IOSTANDARD LVCMOS12 PACKAGE_PIN AM17} [get_ports {MISO}]
1 change: 1 addition & 0 deletions bittide-instances/data/tcl/HardwareTest.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ proc run_single_test {start_probe} {
# Verify that `done` is not set before starting the test
set_property OUTPUT_VALUE 0 $start_probe
commit_hw_vio [get_hw_vios hw_vio_1]
after 10
refresh_hw_vio [get_hw_vios hw_vio_1]
set done [get_property INPUT_VALUE [get_hw_probes probe_test_done]]
if {$done != 0} {
Expand Down
3 changes: 3 additions & 0 deletions bittide-instances/src/Bittide/Instances/MVPs.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NumericUnderscores #-}

{-# OPTIONS_GHC -fconstraint-solver-iterations=10 #-}

module Bittide.Instances.MVPs where

import Clash.Prelude
Expand Down
219 changes: 219 additions & 0 deletions bittide-instances/src/Bittide/Instances/Tests/FincFdec.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
-- SPDX-FileCopyrightText: 2022-2023 Google LLC
--
-- SPDX-License-Identifier: Apache-2.0

{-# LANGUAGE NumericUnderscores #-}

-- | A couple of tests testing clock board programming, and subsequently the
-- FINC and FDEC pins.
module Bittide.Instances.Tests.FincFdec where

import Clash.Annotations.TH (makeTopEntity)
import Clash.Explicit.Prelude
import Clash.Prelude (withClockResetEnable)

import Bittide.Arithmetic.Time
import Bittide.Counter (domainDiffCounter)
import Bittide.ClockControl (SpeedChange(NoChange, SlowDown, SpeedUp), speedChangeToFincFdec)
import Bittide.ClockControl.Si539xSpi (si539xSpi, ConfigState(Finished))
import Bittide.Instances.Domains

import Clash.Xilinx.ClockGen (clockWizardDifferential)

import Clash.Cores.Xilinx.Extra (ibufds)
import Clash.Cores.Xilinx.VIO (vioProbe)
import Clash.Cores.Xilinx.Xpm.Cdc.Single (xpmCdcSingle)

import qualified Bittide.ClockControl.Si5395J as Si5395J

data TestState = Busy | Fail | Success
data Test = Fdec | Finc

testStateToDoneSuccess :: TestState -> (Bool, Bool)
testStateToDoneSuccess = \case
Busy -> (False, False)
Fail -> (True, False)
Success -> (True, True)

noReset :: KnownDomain dom => Reset dom
noReset = unsafeFromHighPolarity (pure False)

eitherReset :: KnownDomain dom => Reset dom -> Reset dom -> Reset dom
eitherReset (unsafeToHighPolarity -> rstA) (unsafeToHighPolarity -> rstB) =
unsafeFromHighPolarity (rstA .||. rstB)

bothReset :: KnownDomain dom => Reset dom -> Reset dom -> Reset dom
bothReset (unsafeToHighPolarity -> rstA) (unsafeToHighPolarity -> rstB) =
unsafeFromHighPolarity (rstA .&&. rstB)

fdecTestGo ::
Clock Basic200A ->
Reset Basic200A ->
Clock Basic200B ->
Signal Basic200A Test ->
"MISO" ::: Signal Basic200A Bit -> -- SPI
"" :::
( Signal Basic200A TestState

-- Freq increase / freq decrease request to clock board
, ( "FINC" ::: Signal Basic200A Bool
, "FDEC" ::: Signal Basic200A Bool
)

-- SPI to clock board:
, "" :::
( "SCLK" ::: Signal Basic200A Bool
, "MOSI" ::: Signal Basic200A Bit
, "CSB" ::: Signal Basic200A Bool
)

-- Debug signals:
, "" :::
( "SPI_BUSY" ::: Signal Basic200A Bool
, "SPI_STATE" ::: Signal Basic200A (BitVector 40)
, "SI_LOCKED" ::: Signal Basic200A Bool
, "COUNTER_ACTIVE" ::: Signal Basic200A Bool
, "COUNTER" ::: Signal Basic200A (Signed 32)
)
)
fdecTestGo clk rst clkControlled testSelect miso =
(testResult, fIncDec, spiOut, debugSignals)
where
debugSignals = (spiBusy, pack <$> spiState, siClkLocked, counterActive, counter)

(_, spiBusy, spiState@(fmap (==Finished) -> siClkLocked), spiOut) =
withClockResetEnable clk rst enableGen $
si539xSpi
Si5395J.testConfig6_200_on_0a_and_0
-- Si5395J.testConfigAll200
(SNat @(Nanoseconds 1000))
(pure Nothing)
miso

rstTest = unsafeFromLowPolarity siClkLocked

rstControlled =
unsafeFromLowPolarity $
xpmCdcSingle clk clkControlled $ -- improvised reset syncer
unsafeToLowPolarity rst

(counter, counterActive) =
unbundle $
-- Note that in a "real" Bittide system the clocks would be wired up the
-- other way around: the controlled domain would be the target domain. We
-- don't do that here because we know 'rstControlled' will come out of
-- reset much earlier than 'rstTest'. Doing it the "proper" way would
-- therefore introduce extra complexity, without adding to the test's
-- coverage.
domainDiffCounter clkControlled rstControlled clk rstTest

fIncDec = unbundle $ speedChangeToFincFdec clk rst fIncDecRequest

(fIncDecRequest, testResult) =
mealyB clk rstTest enableGen go () (counter, testSelect)

go :: () -> (Signed 32, Test) -> ((), (SpeedChange, TestState))
go () (n, Fdec) = ((), goFdec n)
go () (n, Finc) = ((), goFinc n)


goFdec :: Signed 32 -> (SpeedChange, TestState)
goFdec n
| n > 20_000 = (NoChange, Fail)
| n < -20_000 = (NoChange, Success)
| otherwise = (SlowDown, Busy)

goFinc :: Signed 32 -> (SpeedChange, TestState)
goFinc n
| n > 20_000 = (NoChange, Success)
| n < -20_000 = (NoChange, Fail)
| otherwise = (SpeedUp, Busy)

fdecTest ::
-- Pins from internal oscillator:
"CLK_125MHZ_P" ::: Clock Basic125 ->
"CLK_125MHZ_N" ::: Clock Basic125 ->

-- Pins from clock board:
"USER_SMA_CLOCK_P" ::: Clock Basic200B ->
"USER_SMA_CLOCK_N" ::: Clock Basic200B ->
"MISO" ::: Signal Basic200A Bit -> -- SPI

"" :::
( "" :::
( "done" ::: Signal Basic200A Bool
, "success" ::: Signal Basic200A Bool
)

-- Freq increase / freq decrease request to clock board
, "" :::
( "FINC" ::: Signal Basic200A Bool
, "FDEC" ::: Signal Basic200A Bool
)

-- SPI to clock board:
, "" :::
( "SCLK" ::: Signal Basic200A Bool
, "MOSI" ::: Signal Basic200A Bit
, "CSB" ::: Signal Basic200A Bool
)
)
fdecTest clkP clkN controlledClockP controlledClockN spiIn =
((testDone, testSuccess), fIncDec, spiOut)
where
clkControlled = ibufds controlledClockP controlledClockN

(clk, clkStable0) = clockWizardDifferential (SSymbol @"pll") clkN clkP noReset
clkStable1 = xpmCdcSingle clk clk clkStable0 -- improvised reset syncer

clkStableRst = unsafeFromLowPolarity clkStable1
startFdecTestRst = unsafeFromLowPolarity startFdecTest
startFincTestRst = unsafeFromLowPolarity startFincTest
testRst = eitherReset clkStableRst (bothReset startFdecTestRst startFincTestRst)
testRstBool = unsafeToHighPolarity testRst

(fInc, fDec) = fIncDec

testF = mux startFdecTest (pure Fdec) (pure Finc)

(testResult, fIncDec, spiOut, debugSignals) =
fdecTestGo clk testRst clkControlled testF spiIn

(testDone, testSuccess) = unbundle $ testStateToDoneSuccess <$> testResult

(spiBusy, spiState, siClkLocked, counterActive, counter) = debugSignals

(startFdecTest, startFincTest) = unbundle $
vioProbe
( "probe_test_done"
:> "probe_test_success"

-- Debug signals:
:> "probe_clkStable1"
:> "probe_testRstBool"
:> "probe_spiBusy"
:> "probe_spiState"
:> "probe_siClkLocked"
:> "probe_counterActive"
:> "probe_counter"
:> "probe_fInc"
:> "probe_fDec"
:> Nil)
("probe_test_start_fdec" :> "probe_test_start_finc" :> Nil)
(False, False)
clk
testDone
testSuccess

-- Debug signals
clkStable1
testRstBool
spiBusy
spiState
siClkLocked
counterActive
counter
fInc
fDec
{-# NOINLINE fdecTest #-}
makeTopEntity 'fdecTest
Loading

0 comments on commit 1b6a5ef

Please sign in to comment.