2020-08-15 15:46:37 +02:00
|
|
|
import "/collections/namedtuple"
|
2020-08-15 02:20:42 +02:00
|
|
|
import "/nmigen/lib/cdc/ResetSynchronizer"
|
|
|
|
import "/nmigen_boards.icebreaker/ICEBreakerPlatform"
|
|
|
|
import "/nmigen_dg/*"
|
2020-08-15 15:46:37 +02:00
|
|
|
import "/subprocess"
|
2020-08-15 02:20:42 +02:00
|
|
|
import "/sys"
|
2020-08-15 15:46:37 +02:00
|
|
|
import "common/pipeline"
|
2020-08-15 15:48:53 +02:00
|
|
|
import "common/to_signed"
|
|
|
|
import "modules/vga/DviController12"
|
2020-08-15 02:20:42 +02:00
|
|
|
import "resources/pmod"
|
|
|
|
|
|
|
|
|
2020-08-15 15:46:37 +02:00
|
|
|
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"
|
2020-08-16 23:42:45 +02:00
|
|
|
(*) 1e6 $ float $ get_field "F_PLLIN"
|
|
|
|
(*) 1e6 $ float $ get_field "F_PLLOUT" "(requested)"
|
|
|
|
(*) 1e6 $ float $ get_field "F_PLLOUT" "(achieved)"
|
2020-08-15 15:46:37 +02:00
|
|
|
|
|
|
|
|
2020-08-15 02:20:42 +02:00
|
|
|
Top = subclass Elaboratable where
|
2020-08-19 16:33:41 +02:00
|
|
|
__init__ = x y fps ~> None where
|
|
|
|
@x, @y, @fps = x, y, fps
|
2020-08-16 23:47:35 +02:00
|
|
|
|
2020-08-15 02:20:42 +02:00
|
|
|
elaborate = platform ~> m where with m = Module! =>
|
|
|
|
|
2020-08-15 15:48:53 +02:00
|
|
|
# Configure DVI controller
|
2020-08-19 16:33:41 +02:00
|
|
|
dvi = Submodule.dvi$ DviController12 @x @y @fps
|
2020-08-15 15:48:53 +02:00
|
|
|
|
2020-08-19 16:33:41 +02:00
|
|
|
# setup PLL clock
|
2020-08-15 02:20:42 +02:00
|
|
|
|
2020-08-15 15:46:37 +02:00
|
|
|
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
|
2020-08-19 16:33:41 +02:00
|
|
|
otherwise => Const 0
|
2020-08-15 02:20:42 +02:00
|
|
|
|
2020-08-15 15:46:37 +02:00
|
|
|
pll_config = run_icepll
|
|
|
|
default_freq
|
2020-08-15 15:48:53 +02:00
|
|
|
dvi.pix_freq
|
2020-08-15 15:46:37 +02:00
|
|
|
print dvi.timings
|
|
|
|
print pll_config
|
|
|
|
|
|
|
|
pll_clk, pll_lock = Signal!, Signal!
|
2020-08-19 16:33:41 +02:00
|
|
|
Submodule.pll$ Instance "SB_PLL40_PAD" # or "SB_PLL40_CORE"
|
|
|
|
i_PACKAGEPIN : default_clk # or i_REFERENCECLK
|
2020-08-15 02:20:42 +02:00
|
|
|
i_BYPASS : (Const 0)
|
2020-08-19 16:33:41 +02:00
|
|
|
i_RESETB : ~default_reset
|
2020-08-15 02:20:42 +02:00
|
|
|
o_LOCK : pll_lock
|
2020-08-15 15:46:37 +02:00
|
|
|
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
|
|
|
|
|
2020-08-15 02:20:42 +02:00
|
|
|
Domains.sync = ClockDomain "sync"
|
2020-08-17 00:34:12 +02:00
|
|
|
Comb$ ClockSignal "sync" ::= pll_clk
|
2020-08-15 15:46:37 +02:00
|
|
|
|
|
|
|
Submodule.rs$ ResetSynchronizer
|
|
|
|
~pll_lock
|
|
|
|
domain: "sync"
|
2020-08-15 02:20:42 +02:00
|
|
|
|
2020-08-15 15:46:37 +02:00
|
|
|
|
2020-08-16 23:30:36 +02:00
|
|
|
# Feed a picture to the DVI controller
|
|
|
|
|
|
|
|
scroll = Signal 8
|
|
|
|
|
2020-08-19 16:33:41 +02:00
|
|
|
period = int$ pll_config.achieved / @fps
|
2020-08-16 23:30:36 +02:00
|
|
|
counter = Signal$ range period
|
2020-08-17 00:34:12 +02:00
|
|
|
Sync$ counter ::= counter - 1
|
2020-08-15 02:20:42 +02:00
|
|
|
When (counter==0) $ ->
|
2020-08-17 00:34:12 +02:00
|
|
|
Sync$ counter ::= int period
|
|
|
|
Sync$ scroll ::= scroll + 1
|
2020-08-15 02:20:42 +02:00
|
|
|
|
2020-08-17 00:34:12 +02:00
|
|
|
Sync$ dvi.r ::= 0x0
|
|
|
|
Sync$ dvi.g ::= 0x0
|
|
|
|
Sync$ dvi.b ::= 0x0
|
2020-08-16 23:47:35 +02:00
|
|
|
cx = to_signed dvi.pixel_x - (@x // 2)
|
|
|
|
cy = to_signed dvi.pixel_y - (@y // 2)
|
2020-08-19 16:33:41 +02:00
|
|
|
rx = cx * cx
|
|
|
|
ry = cy * cy
|
2020-08-16 23:47:35 +02:00
|
|
|
tx1 = (dvi.pixel_x - scroll ) & (1<<5)
|
|
|
|
ty1 = (dvi.pixel_y - scroll ) & (1<<5)
|
|
|
|
tx2 = (dvi.pixel_x + scroll ) & (1<<6)
|
2020-08-16 23:30:36 +02:00
|
|
|
ty2 = (dvi.pixel_y + scroll + 40) & (1<<6)
|
|
|
|
When
|
|
|
|
rx + ry < 200**2 ,->
|
2020-08-17 00:34:12 +02:00
|
|
|
Sync$ dvi.r ::= 0xF
|
|
|
|
#Sync$ dvi.g ::= 0xF
|
|
|
|
Sync$ dvi.b ::= 0xF
|
2020-08-19 16:33:41 +02:00
|
|
|
|
2020-08-16 23:30:36 +02:00
|
|
|
tx1 ^ ty1 ,->
|
2020-08-17 00:34:12 +02:00
|
|
|
Sync$ dvi.b ::= 0xF
|
2020-08-19 16:33:41 +02:00
|
|
|
|
2020-08-16 23:30:36 +02:00
|
|
|
tx2 ^ ty2 ,->
|
2020-08-17 00:34:12 +02:00
|
|
|
Sync$ dvi.r ::= 0xF
|
|
|
|
Sync$ dvi.g ::= 0xF
|
2020-08-15 15:48:53 +02:00
|
|
|
|
2020-08-15 02:20:42 +02:00
|
|
|
|
|
|
|
if __name__ == "__main__" =>
|
|
|
|
plat = ICEBreakerPlatform!
|
|
|
|
plat.add_resources$ pmod.dvi_12bit 0
|
|
|
|
plat.add_resources$ plat.break_off_pmod
|
2020-08-16 23:47:35 +02:00
|
|
|
plat.build (Top 800 480) do_program: ("--flash" in sys.argv) synth_opts: "-dsp"
|