diff --git a/fpga/icebreaker_vga.dg b/fpga/icebreaker_vga.dg index e840d88..870a550 100644 --- a/fpga/icebreaker_vga.dg +++ b/fpga/icebreaker_vga.dg @@ -1,47 +1,90 @@ +import "/collections/namedtuple" import "/nmigen/lib/cdc/ResetSynchronizer" import "/nmigen_boards.icebreaker/ICEBreakerPlatform" import "/nmigen_dg/*" +import "/subprocess" import "/sys" +import "common/pipeline" 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 elaborate = platform ~> m where with m = Module! => - reset = if - platform.default_rst => platform.request platform.default_rst - otherwise => Const 0 # setup clock - clk40 = Signal! - pll_lock = Signal! + default_clk = platform.request platform.default_clk dir:"-" + 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" - i_PACKAGEPIN : (platform.request "clk12" dir:"-") # i_REFERENCECLK + i_PACKAGEPIN : default_clk # i_REFERENCECLK i_BYPASS : (Const 0) - i_RESETB : ~reset + i_RESETB : default_reset o_LOCK : pll_lock - o_PLLOUTGLOBAL : clk40 - # icepll -o 40 - p_FEEDBACK_PATH : "SIMPLE" - p_FILTER_RANGE : 1 - p_DIVR : 0 - p_DIVF : 52 - p_DIVQ : 4 + o_PLLOUTGLOBAL : pll_clk + p_FEEDBACK_PATH : pll_config.FEEDBACK + p_FILTER_RANGE : pll_config.FILTER_RANGE + p_DIVR : pll_config.DIVR + p_DIVF : pll_config.DIVF + p_DIVQ : pll_config.DIVQ - #m.domains.sync = ClockDomain "sync" Domains.sync = ClockDomain "sync" - Comb$ ClockSignal "sync" :== clk40 - Submodule$ ResetSynchronizer ~pll_lock domain: "sync" + Comb$ ClockSignal "sync" :== pll_clk + Submodule.rs$ ResetSynchronizer + ~pll_lock + domain: "sync" + + + # Simple test to see if the PLL works state = Signal! counter = Signal$ range (int plat.default_clk_frequency) Sync$ counter :== counter - 1 When (counter==0) $ -> - Sync$ counter :== (int plat.default_clk_frequency) + Sync$ counter :== int plat.default_clk_frequency 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_g" :== ~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 + if __name__ == "__main__" =>