Make the PLL arbitrarily configurable

This commit is contained in:
Peder Bergebakken Sundt 2020-08-15 15:46:37 +02:00
parent 371e425d38
commit aead41b8b6
1 changed files with 63 additions and 20 deletions

View File

@ -1,47 +1,90 @@
import "/collections/namedtuple"
import "/nmigen/lib/cdc/ResetSynchronizer" import "/nmigen/lib/cdc/ResetSynchronizer"
import "/nmigen_boards.icebreaker/ICEBreakerPlatform" import "/nmigen_boards.icebreaker/ICEBreakerPlatform"
import "/nmigen_dg/*" import "/nmigen_dg/*"
import "/subprocess"
import "/sys" import "/sys"
import "common/pipeline"
import "resources/pmod" import "resources/pmod"
run_icepll = current target ->
current /= 1e6 # Hz -> MHz
target /= 1e6 # Hz -> MHz
out = subprocess.run ["icepll", "-i", str current, "-o", str target]
capture_output: True
check: True
get_field = field substring:None ->
pipeline out.stdout.decode!.splitlines!
bind filter $ x -> x.startswith field
if
substring => bind filter $ x -> substring in x
otherwise => x -> x # nop
head
str.split
tail
head
(namedtuple "icepll_config" "FEEDBACK FILTER_RANGE DIVR DIVF DIVQ given requested achieved")
str$ get_field "FEEDBACK"
int$ get_field "FILTER_RANGE"
int$ get_field "DIVR"
int$ get_field "DIVF"
int$ get_field "DIVQ"
float$ get_field "F_PLLIN"
float$ get_field "F_PLLOUT" "(requested)"
float$ get_field "F_PLLOUT" "(achieved)"
Top = subclass Elaboratable where Top = subclass Elaboratable where
elaborate = platform ~> m where with m = Module! => elaborate = platform ~> m where with m = Module! =>
reset = if
platform.default_rst => platform.request platform.default_rst
otherwise => Const 0
# setup clock # setup clock
clk40 = Signal! default_clk = platform.request platform.default_clk dir:"-"
pll_lock = Signal! default_freq = platform.default_clk_frequency
default_reset = if
platform.default_rst => platform.request platform.default_rst
otherwise => Const 1
pll_config = run_icepll
default_freq
40e6
print dvi.timings
print pll_config
pll_clk, pll_lock = Signal!, Signal!
Submodule.pll$ Instance "SB_PLL40_PAD" # "SB_PLL40_CORE" Submodule.pll$ Instance "SB_PLL40_PAD" # "SB_PLL40_CORE"
i_PACKAGEPIN : (platform.request "clk12" dir:"-") # i_REFERENCECLK i_PACKAGEPIN : default_clk # i_REFERENCECLK
i_BYPASS : (Const 0) i_BYPASS : (Const 0)
i_RESETB : ~reset i_RESETB : default_reset
o_LOCK : pll_lock o_LOCK : pll_lock
o_PLLOUTGLOBAL : clk40 o_PLLOUTGLOBAL : pll_clk
# icepll -o 40 p_FEEDBACK_PATH : pll_config.FEEDBACK
p_FEEDBACK_PATH : "SIMPLE" p_FILTER_RANGE : pll_config.FILTER_RANGE
p_FILTER_RANGE : 1 p_DIVR : pll_config.DIVR
p_DIVR : 0 p_DIVF : pll_config.DIVF
p_DIVF : 52 p_DIVQ : pll_config.DIVQ
p_DIVQ : 4
#m.domains.sync = ClockDomain "sync"
Domains.sync = ClockDomain "sync" Domains.sync = ClockDomain "sync"
Comb$ ClockSignal "sync" :== clk40 Comb$ ClockSignal "sync" :== pll_clk
Submodule$ ResetSynchronizer ~pll_lock domain: "sync"
Submodule.rs$ ResetSynchronizer
~pll_lock
domain: "sync"
# Simple test to see if the PLL works
state = Signal! state = Signal!
counter = Signal$ range (int plat.default_clk_frequency) counter = Signal$ range (int plat.default_clk_frequency)
Sync$ counter :== counter - 1 Sync$ counter :== counter - 1
When (counter==0) $ -> When (counter==0) $ ->
Sync$ counter :== (int plat.default_clk_frequency) Sync$ counter :== int plat.default_clk_frequency
Sync$ state :== ~state Sync$ state :== ~state
Comb$ platform.request "led_r" :== state # blinks at 1hz with default clk, but way faster when at 40MHz Comb$ platform.request "led_r" :== state
Comb$ platform.request "led_g" :== ~state # blinks at 1hz with default clk, but way faster when at 40MHz Comb$ platform.request "led_g" :== ~state
if __name__ == "__main__" => if __name__ == "__main__" =>