1
0
mirror of synced 2026-01-11 23:42:59 +00:00

Emulate a bw2 FB, mostly to test feasibility of 1bpp FB in Litex

This commit is contained in:
Romain Dolbeau 2021-12-18 11:30:45 +01:00
parent d95a233268
commit 6e7bb3b1e3
7 changed files with 426 additions and 31 deletions

View File

@ -0,0 +1,145 @@
\ simplified version of the OpenBIOS cgthree code
\ ... for the bw2
: openbios-video-width
h# SBUSFPGA_CG3_WIDTH
;
: openbios-video-height
h# SBUSFPGA_CG3_HEIGHT
;
: depth-bits
h# 1
;
: line-bytes
h# SBUSFPGA_CG3_WIDTH h# 8 /
;
sbusfpga_regionaddr_bw2_bt constant bw2-off-dac
h# 20 constant /bw2-off-dac
h# 800000 constant bw2-off-fb
h# SBUSFPGA_CG3_BUFSIZE constant /bw2-off-fb
: >bw2-reg-spec ( offset size -- encoded-reg )
>r 0 my-address d+ my-space encode-phys r> encode-int encode+
;
: bw2-reg
\ A real bw2 rom appears to just map the entire region with a
\ single entry
h# 0 h# 1000000 >bw2-reg-spec
" reg" property
;
: do-map-in ( offset size -- virt )
>r my-space r> " map-in" $call-parent
;
: do-map-out ( virt size )
" map-out" $call-parent
;
\
\ DAC
\
-1 value bw2-dac
-1 value fb-addr
: dac! ( data reg# -- )
bw2-dac + c!
;
headerless
\
\ Mapping
\
: dac-map
bw2-off-dac /bw2-off-dac do-map-in to bw2-dac
;
: dac-unmap
bw2-dac /bw2-off-dac do-map-out
-1 to bw2-dac
;
: fb-map
bw2-off-fb /bw2-off-fb do-map-in to fb-addr
;
: fb-unmap
bw2-off-fb /bw2-off-fb do-map-out
-1 to fb-addr
;
: map-regs
dac-map fb-map
;
: unmap-regs
dac-unmap fb-unmap
;
\
\ Installation
\
" bwtwo" device-name
" display" device-type
" RDOL,sbusfpga" model
: qemu-bw2-driver-install ( -- )
bw2-dac -1 = if
map-regs
fb-map
fb-addr to frame-buffer-adr
default-font set-font
frame-buffer-adr encode-int " address" property \ CHECKME
openbios-video-width openbios-video-height over char-width / over char-height /
\ fb1-install ; not supported in my OF compiler :-( -> explicit code# 1 7b
tokenizer[ h# 1 emit-byte h# 7b emit-byte ]tokenizer
then
;
: qemu-bw2-driver-remove ( -- )
bw2-dac -1 <> if
unmap-regs
fb-unmap
-1 to frame-buffer-adr
" address" delete-attribute
then
;
: qemu-bw2-driver-init
bw2-reg
openbios-video-height encode-int " height" property
openbios-video-width encode-int " width" property
depth-bits encode-int " depth" property
line-bytes encode-int " linebytes" property
h# 39 encode-int 0 encode-int encode+ " intr" property
\ Monitor sense. Some searching suggests that this is
\ 5 for 1024x768 and 7 for 1152x900
h# 7 encode-int " monitor-sense" property
" RDOL" encode-string " manufacturer" property
" ISO8859-1" encode-string " character-set" property
h# c encode-int " cursorshift" property
['] qemu-bw2-driver-install is-install
['] qemu-bw2-driver-remove is-remove
;
qemu-bw2-driver-init

View File

@ -0,0 +1,197 @@
from migen import *
from migen.genlib.fifo import *
from litex.soc.interconnect.csr import *
from litex.soc.interconnect import stream
from litex.soc.interconnect import wishbone
from litex.soc.cores.code_tmds import TMDSEncoder
from litex.build.io import SDROutput, DDROutput
from litex.soc.cores.video import *
from math import ceil;
DEPTH=1
def bw2_rounded_size(hres, vres):
mib = int(ceil(((hres * vres * DEPTH)/8 + 0) / 1048576))
if (mib == 3):
mib = 4
if (mib > 4 and mib < 8):
mib = 8
if (mib > 8 or mib < 1):
print(f"{mib} mebibytes framebuffer not supported")
assert(False)
return int(1048576 * mib)
class VideoFrameBufferBW(Module, AutoCSR):
"""Video FrameBufferBW"""
def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65536, clock_domain="sys", clock_faster_than_sys=False):
print(f"FRAMEBUFFER: dram_port.data_width = {dram_port.data_width}, {hres}x{vres}, 0x{base:x}, in {clock_domain}, clock_faster_than_sys={clock_faster_than_sys}")
self.vtg_sink = vtg_sink = stream.Endpoint(video_timing_layout)
self.source = source = stream.Endpoint(video_data_layout)
self.underflow = Signal()
# # #
# Video DMA.
from litedram.frontend.dma import LiteDRAMDMAReader
self.submodules.dma = LiteDRAMDMAReader(dram_port, fifo_depth=fifo_depth//(dram_port.data_width//8), fifo_buffered=True)
self.dma.add_csr(
default_base = base,
default_length = (hres*vres*DEPTH)//8, # 1-bit B&W
default_enable = 0,
default_loop = 1
)
# If DRAM Data Width > DEPTH-bit and Video clock is faster than sys_clk:
if (dram_port.data_width > DEPTH) and clock_faster_than_sys:
# Do Clock Domain Crossing first...
self.submodules.cdc = stream.ClockDomainCrossing([("data", dram_port.data_width)], cd_from="sys", cd_to=clock_domain)
self.comb += self.dma.source.connect(self.cdc.sink)
# bit reverse every byte...
self.comb += [
self.cdc.sink.data[0:8].eq(self.dma.source.data[7::-1])
]
self.comb += [
self.cdc.sink.data[x*8:(x+1)*8].eq(self.dma.source.data[((x+1)*8)-1:(x*8)-1:-1]) for x in range(1,(dram_port.data_width//8))
]
# ... and then Data-Width Conversion.
self.submodules.conv = ClockDomainsRenamer({"sys": clock_domain})(stream.Converter(dram_port.data_width, DEPTH))
self.comb += self.cdc.source.connect(self.conv.sink)
video_pipe_source = self.conv.source
# Elsif DRAM Data Width < DEPTH-bit or Video clock is slower than sys_clk:
else: #### FIXME: bit reversal in byte missing
# Do Data-Width Conversion first...
self.submodules.conv = stream.Converter(dram_port.data_width, DEPTH)
self.comb += self.dma.source.connect(self.conv.sink)
# ... and then Clock Domain Crossing.
self.submodules.cdc = stream.ClockDomainCrossing([("data", DEPTH)], cd_from="sys", cd_to=clock_domain)
self.comb += self.conv.source.connect(self.cdc.sink)
video_pipe_source = self.cdc.source
# Video Generation.
self.comb += [
vtg_sink.ready.eq(1),
If(vtg_sink.valid & vtg_sink.de,
video_pipe_source.connect(source, keep={"valid", "ready"}),
vtg_sink.ready.eq(source.valid & source.ready),
),
vtg_sink.connect(source, keep={"de", "hsync", "vsync"}),
# use the same bit for everything ; console is W-on-B but X11 seems OK
source.r.eq(Replicate(video_pipe_source.data[0], 8)),
source.g.eq(Replicate(video_pipe_source.data[0], 8)),
source.b.eq(Replicate(video_pipe_source.data[0], 8)),
]
# Underflow.
self.comb += self.underflow.eq(~source.valid)
class bw2(Module, AutoCSR):
def __init__(self, soc, phy=None, timings = None, clock_domain="sys"):
name = "video_framebuffer"
# near duplicate of plaform.add_video_framebuffer
# Video Timing Generator.
vtg = VideoTimingGenerator(default_video_timings=timings if isinstance(timings, str) else timings[1])
vtg = ClockDomainsRenamer(clock_domain)(vtg)
setattr(self.submodules, f"{name}_vtg", vtg)
# Video FrameBuffer.
timings = timings if isinstance(timings, str) else timings[0]
base = soc.mem_map.get(name)
print(f"BW2: visible memory at {base:x}")
hres = int(timings.split("@")[0].split("x")[0])
vres = int(timings.split("@")[0].split("x")[1])
freq = vtg.video_timings["pix_clk"]
print(f"BW2: using {hres} x {vres}, {freq/1e6} MHz pixclk")
vfb = VideoFrameBufferBW(dram_port = soc.sdram.crossbar.get_port(),
hres = hres,
vres = vres,
base = base,
clock_domain = clock_domain,
clock_faster_than_sys = (vtg.video_timings["pix_clk"] > soc.sys_clk_freq))
setattr(self.submodules, name, vfb)
# Connect Video Timing Generator to Video FrameBuffer.
self.comb += vtg.source.connect(vfb.vtg_sink)
# Connect Video FrameBuffer to Video PHY.
self.comb += vfb.source.connect(phy if isinstance(phy, stream.Endpoint) else phy.sink)
# Constants.
soc.add_constant("VIDEO_FRAMEBUFFER_BASE", base)
soc.add_constant("VIDEO_FRAMEBUFFER_HRES", hres)
soc.add_constant("VIDEO_FRAMEBUFFER_VRES", vres)
self.bus = bus = wishbone.Interface()
# drievr uses the same struct fbcontrol for bw2 as for cg3
fbc_ctrl = Signal(8, reset = 0x60) # FBC_VENAB | FBC_TIMING # 0x10 ?
hres_to_sense = {
"default": 0x30, # 1152x900
1024: 0x10,
1152: 0x30,
1280: 0x40,
};
fbc_status = Signal(8, reset = (hres_to_sense[hres] | 0x01)) # 1280x1024 color # 0x11 ?
fbc_cursor_start = Signal(8) # 0x12 ?
fbc_cursor_end = Signal(8) # 0x13 ?
fbc_vcontrol = Array(Signal(8) for a in range(0, 3))
self.submodules.wishbone_fsm = wishbone_fsm = FSM(reset_state = "Reset")
wishbone_fsm.act("Reset",
NextValue(bus.ack, 0),
NextState("Idle"))
wishbone_fsm.act("Idle",
If(bus.cyc & bus.stb & bus.we & ~bus.ack, #write
# FIXME: should check for prefix?
Case(bus.adr[0:3], {
# bt_addr
0: [],
# bt_cmap
1: [],
# bt_ctrl: unused ??
2: [],
# bt_omap: unused ??
3: [],
# fbc_ctrl & friends: 4 in one go
# should be byte-accessed
# CHECKME: byte ordering
4: [ Case(bus.sel, {
8: [ NextValue(fbc_ctrl, bus.dat_w[24:32]),],
4: [ NextValue(fbc_status, fbc_status & 0x7F),], #FIXME: if high bit set, cancel interrupt
2: [ NextValue(fbc_cursor_start, bus.dat_w[24:32]),],
1: [ NextValue(fbc_cursor_end, bus.dat_w[24:32]),],
}),
],
5: [NextValue(fbc_vcontrol[0], (bus.dat_w & Cat(Replicate(bus.sel[3], 8), Replicate(bus.sel[2], 8), Replicate(bus.sel[1], 8), Replicate(bus.sel[0], 8))) | (fbc_vcontrol[0] & ~Cat(Replicate(bus.sel[3], 8), Replicate(bus.sel[2], 8), Replicate(bus.sel[1], 8), Replicate(bus.sel[0], 8)))) ],
6: [NextValue(fbc_vcontrol[1], (bus.dat_w & Cat(Replicate(bus.sel[3], 8), Replicate(bus.sel[2], 8), Replicate(bus.sel[1], 8), Replicate(bus.sel[0], 8))) | (fbc_vcontrol[1] & ~Cat(Replicate(bus.sel[3], 8), Replicate(bus.sel[2], 8), Replicate(bus.sel[1], 8), Replicate(bus.sel[0], 8)))) ],
7: [NextValue(fbc_vcontrol[2], (bus.dat_w & Cat(Replicate(bus.sel[3], 8), Replicate(bus.sel[2], 8), Replicate(bus.sel[1], 8), Replicate(bus.sel[0], 8))) | (fbc_vcontrol[2] & ~Cat(Replicate(bus.sel[3], 8), Replicate(bus.sel[2], 8), Replicate(bus.sel[1], 8), Replicate(bus.sel[0], 8)))) ],
}),
NextValue(bus.ack, 1),
).Elif(bus.cyc & bus.stb & ~bus.we & ~bus.ack, #read
Case(bus.adr[0:3], {
# bt_addr
0: [ NextValue(bus.dat_r, 0) ],
# bt_cmap
1: [ NextValue(bus.dat_r, 0)],
# bt_ctrl: unused ??
2: [ NextValue(bus.dat_r, 0)],
# bt_omap: unused ??
3: [ NextValue(bus.dat_r, 0)],
# fbc_ctrl & friends: 4 in one go
# should be byte-accessed
# CHECKME: byte ordering
4: [ NextValue(bus.dat_r, Cat(fbc_cursor_end, fbc_cursor_start, fbc_status, fbc_ctrl))],
5: [ NextValue(bus.dat_r, fbc_vcontrol[0])],
6: [ NextValue(bus.dat_r, fbc_vcontrol[1])],
7: [ NextValue(bus.dat_r, fbc_vcontrol[2])],
}),
NextValue(bus.ack, 1),
).Else(
NextValue(bus.ack, 0),
)
)

View File

@ -0,0 +1,24 @@
: bw2_vid_fb_vtg_enable_rd ( -- csr_value)
bw2-virt h# 0000 + l@
;
: bw2_vid_fb_dma_enable_rd ( -- csr_value)
bw2-virt h# 002c + l@
;
: bw2_vid_fb_vtg_enable_wr ( value -- )
bw2-virt h# 0000 + l!
;
: bw2_vid_fb_dma_enable_wr ( value -- )
bw2-virt h# 002c + l!
;
: bw2_init!
map-in-bw2extraregs
0 bw2_vid_fb_vtg_enable_wr
0 bw2_vid_fb_dma_enable_wr
1 bw2_vid_fb_vtg_enable_wr
1 bw2_vid_fb_dma_enable_wr
map-out-bw2extraregs
;

View File

@ -316,8 +316,14 @@ class cg3(Module, AutoCSR):
bt_cmap_state = Signal(2)
bt_cmap_buf = Signal(24)
fbc_ctrl = Signal(8) # 0x10 ?
fbc_status = Signal(8, reset = 0x61) # 1152x900 color # 0x11 ?
fbc_ctrl = Signal(8, reset = 0x60) # FBC_VENAB | FBC_TIMING # 0x10 ?
hres_to_sense = {
"default": 0x30, # 1152x900
1024: 0x10,
1152: 0x30,
1280: 0x40,
};
fbc_status = Signal(8, reset = (hres_to_sense[hres] | 0x01)) # 1280x1024 color # 0x11 ?
fbc_cursor_start = Signal(8) # 0x12 ?
fbc_cursor_end = Signal(8) # 0x13 ?
fbc_vcontrol = Array(Signal(8) for a in range(0, 3))

View File

@ -16,7 +16,7 @@ class CG6Accel(Module): # AutoCSR ?
self.COORD_BITS = COORD_BITS = 12
fbc_config = Signal(32, reset = (0x60000000)) # bit 11-12 are for resolution, see the GX manual
fbc_config = Signal(32, reset = (0x60000000)) # bit 11-12 are for resolution, see the GX manual (seem unused by drivers)
fbc_mode = Signal(32)
fbc_clip = Signal(32)
fbc_s = Signal(32)

View File

@ -6,6 +6,7 @@ from sysconfig import get_platform
from migen import *
import bw2_fb
import cg3_fb
import cg6_fb
@ -98,10 +99,13 @@ def get_prom(soc,
sdram=True,
engine=False,
i2c=False,
bw2=False,
cg3=False,
cg6=False,
cg3_res=None,
sdcard=False):
framebuffer = (bw2 or cg3 or cg6)
r = "fcode-version2\nfload prom_csr_{}.fth\n".format(version.replace(".", "_"))
@ -114,7 +118,7 @@ def get_prom(soc,
r += "\" RDOL,sbusstat\" device-name\n"
r += get_header_map_stuff("sbus_bus_stat", "sbus_bus_stat", 256)
if (trng or usb or (sdram or not sdram) or engine or i2c or cg3 or cg6 or sdcard):
if (trng or usb or (sdram or not sdram) or engine or i2c or framebuffer or sdcard):
r += "finish-device\nnew-device\n"
if (trng):
@ -126,7 +130,7 @@ def get_prom(soc,
r += " map-out-trng\n"
r += ";\n"
r += "disabletrng!\n"
if (usb or (sdram or not sdram) or engine or i2c or cg3 or cg6 or sdcard):
if (usb or (sdram or not sdram) or engine or i2c or framebuffer or sdcard):
r += "finish-device\nnew-device\n"
if (usb):
@ -146,7 +150,7 @@ def get_prom(soc,
r += " map-out-usb_host_ctrl\n"
r += ";\n"
r += "my-reset!\n"
if ((sdram or not sdram) or engine or i2c or cg3 or cg6 or sdcard):
if ((sdram or not sdram) or engine or i2c or framebuffer or sdcard):
r += "finish-device\nnew-device\n"
if (sdram):
@ -158,7 +162,7 @@ def get_prom(soc,
r += "\" RDOL,hidden_sdram\" device-name\n"
r += get_header_mapx_stuff("mregs", [ "ddrphy", "sdram" ], [ 4096, 4096 ], [ "csr", "csr" ])
r += "fload sdram_init.fth\ninit!\n"
if (engine or i2c or cg3 or cg6 or sdcard):
if (engine or i2c or framebuffer or sdcard):
r += "finish-device\nnew-device\n"
if (engine):
@ -166,36 +170,44 @@ def get_prom(soc,
r += ": sbusfpga_regionaddr_curve25519engine-microcode sbusfpga_regionaddr_curve25519engine ;\n"
r += ": sbusfpga_regionaddr_curve25519engine-regfile sbusfpga_regionaddr_curve25519engine h# 10000 + ;\n"
r += get_header_mapx_stuff("curve25519engine", [ "curve25519engine-regs", "curve25519engine-microcode", "curve25519engine-regfile" ], [ 4096, 4096, 65536 ] , ["csr", "region", "region" ] )
if (i2c or cg3 or cg6 or sdcard):
if (i2c or framebuffer or sdcard):
r += "finish-device\nnew-device\n"
if (i2c):
r += "\" RDOL,i2c\" device-name\n"
r += get_header_map_stuff("i2c", "i2c", 64)
if (cg3 or cg6 or sdcard):
if (framebuffer or sdcard):
r += "finish-device\nnew-device\n"
if (cg3 or cg6):
if (framebuffer):
hres = int(cg3_res.split("@")[0].split("x")[0])
vres = int(cg3_res.split("@")[0].split("x")[1])
hres_h=(f"{hres:x}").replace("0x", "")
vres_h=(f"{vres:x}").replace("0x", "")
if (cg3):
if (bw2):
cg3_file = open("bw2.fth")
elif (cg3):
cg3_file = open("cg3.fth")
else:
cg3_file = open("cg6.fth")
cg3_lines = cg3_file.readlines()
buf_size=cg3_fb.cg3_rounded_size(hres, vres)
if (bw2):
buf_size=bw2_fb.bw2_rounded_size(hres, vres)
else:
buf_size=cg3_fb.cg3_rounded_size(hres, vres)
for line in cg3_lines:
r += line.replace("SBUSFPGA_CG3_WIDTH", hres_h).replace("SBUSFPGA_CG3_HEIGHT", vres_h).replace("SBUSFPGA_CG3_BUFSIZE", f"{buf_size:x}")
#r += "\" LITEX,fb\" device-name\n"
#r += get_header_map2_stuff("cg3extraregs", "vid_fb", "vid_fb_vtg", 4096, 4096)
#r += "fload fb_init.fth\nfb_init!\n"
r += "\n"
if (cg3):
if (bw2):
r += get_header_map_stuff("bw2extraregs", "bw2", 4096, reg=False)
r += "fload bw2_init.fth\nbw2_init!\n"
elif (cg3):
r += get_header_map_stuff("cg3extraregs", "cg3", 4096, reg=False)
r += "fload cg3_init.fth\ncg3_init!\n"
if (cg6):
else:
r += get_header_map_stuff("cg6extraregs", "cg6", 4096, reg=False)
r += "fload cg6_init.fth\ncg6_init!\n"
if (sdcard):

View File

@ -36,6 +36,7 @@ import sbus_to_fpga_export
import sbus_to_fpga_prom
from litex.soc.cores.video import VideoVGAPHY
import bw2_fb
import cg3_fb
import cg6_fb
import cg6_accel
@ -52,7 +53,7 @@ class _CRG(Module):
usb_clk_freq=48e6,
engine=False,
i2c=False,
cg3=False,
framebuffer=False,
pix_clk=0):
self.clock_domains.cd_sys = ClockDomain() # 100 MHz PLL, reset'ed by SBus (via pll), SoC/Wishbone main clock
self.clock_domains.cd_sys4x = ClockDomain(reset_less=True)
@ -69,7 +70,7 @@ class _CRG(Module):
#self.clock_domains.cd_clk100 = ClockDomain() # 100 MHz for curve25519engine -> sys_clk
self.clock_domains.cd_clk200 = ClockDomain() # 200 MHz (gated) for curve25519engine -> rf_clk
self.clock_domains.cd_clk100_gated = ClockDomain() # 100 MHz (gated) for curve25519engine -> mul_clk # aways created, along sysclk
if (cg3):
if (framebuffer):
self.clock_domains.cd_vga = ClockDomain(reset_less=True)
# # #
@ -184,7 +185,7 @@ class _CRG(Module):
num_adv = num_adv + 1
num_clk = 0
if (cg3):
if (framebuffer):
self.submodules.video_pll = video_pll = S7MMCM(speedgrade=platform.speedgrade)
video_pll.register_clkin(self.clk48_bufg, 48e6)
video_pll.create_clkout(self.cd_vga, pix_clk, margin = 0.0005)
@ -211,7 +212,9 @@ class SBusFPGA(SoCCore):
#if self.irq.enabled:
#self.irq.add(name, use_loc_if_exists=True)
def __init__(self, variant, version, sys_clk_freq, trng, usb, sdram, engine, i2c, cg3, cg6, cg3_res, sdcard, **kwargs):
def __init__(self, variant, version, sys_clk_freq, trng, usb, sdram, engine, i2c, bw2, cg3, cg6, cg3_res, sdcard, **kwargs):
framebuffer = (bw2 or cg3 or cg6)
print(f"Building SBusFPGA for board version {version}")
kwargs["cpu_type"] = "None"
@ -223,13 +226,16 @@ class SBusFPGA(SoCCore):
self.platform = platform = ztex213_sbus.Platform(variant = variant, version = version)
if ((cg3 or cg6) and (version == "V1.2")):
if (framebuffer and (version == "V1.2")):
platform.add_extension(ztex213_sbus._vga_pmod_io_v1_2)
if (cg3 or cg6):
if (framebuffer):
hres = int(cg3_res.split("@")[0].split("x")[0])
vres = int(cg3_res.split("@")[0].split("x")[1])
cg3_fb_size = cg3_fb.cg3_rounded_size(hres, vres)
if (bw2):
cg3_fb_size = bw2_fb.bw2_rounded_size(hres, vres)
else:
cg3_fb_size = cg3_fb.cg3_rounded_size(hres, vres)
print(f"Reserving {cg3_fb_size} bytes ({cg3_fb_size//1048576} MiB) for the CG3/CG6")
else:
hres = 0
@ -273,18 +279,18 @@ class SBusFPGA(SoCCore):
#"cg6_dhc": 0x00240000, # required for compatibility, unused
"cg6_fhc": 0x00300000, # required for compatibility
#"cg6_thc": 0x00301000, # required for compatibility
"cg3_bt": 0x00400000, # required for compatibility, bt_regs for cg3
"cg3_bt": 0x00400000, # required for compatibility, bt_regs for cg3 & bw2
"cg6_accel_rom": 0x00410000, # R5 microcode
"cg6_accel_ram": 0x00420000, # R5 microcode working space (stack)
"cg6_fbc": 0x00700000, # required for compatibility
#"cg6_tec": 0x00701000, # required for compatibility
"cg3_pixels": 0x00800000, # required for compatibility, 1/2/4/8 MiB for now (up to 0x00FFFFFF inclusive) (cg3 and cg6 idem)
"cg3_pixels": 0x00800000, # required for compatibility, 1/2/4/8 MiB for now (up to 0x00FFFFFF inclusive) (bw2, cg3 and cg6 idem)
"main_ram": 0x80000000, # not directly reachable from SBus mapping (only 0x0 - 0x10000000 is accessible),
"video_framebuffer":0x80000000 + 0x10000000 - cg3_fb_size, # Updated later
"dvma_bridge": 0xfc000000, # required to match DVMA virtual addresses
}
self.mem_map.update(wb_mem_map)
self.submodules.crg = _CRG(platform=platform, sys_clk_freq=sys_clk_freq, usb=usb, usb_clk_freq=48e6, engine=engine, cg3=(cg3 or cg6), pix_clk=litex.soc.cores.video.video_timings[cg3_res]["pix_clk"])
self.submodules.crg = _CRG(platform=platform, sys_clk_freq=sys_clk_freq, usb=usb, usb_clk_freq=48e6, engine=engine, framebuffer=framebuffer, pix_clk=litex.soc.cores.video.video_timings[cg3_res]["pix_clk"])
#self.platform.add_period_constraint(self.platform.lookup_request("SBUS_3V3_CLK", loose=True), 1e9/25e6) # SBus max
## add our custom timings after the clocks have been defined
@ -353,7 +359,7 @@ class SBusFPGA(SoCCore):
avail_sdram = self.bus.regions["main_ram"].size
base_fb = self.wb_mem_map["main_ram"] + avail_sdram - 1048576 # placeholder
if (cg3 or cg6):
if (framebuffer):
if (avail_sdram >= cg3_fb_size):
avail_sdram = avail_sdram - cg3_fb_size
base_fb = self.wb_mem_map["main_ram"] + avail_sdram
@ -488,16 +494,18 @@ class SBusFPGA(SoCCore):
if (i2c):
self.submodules.i2c = i2c.RTLI2C(platform, pads=platform.request("i2c"))
if (cg3 or cg6):
if (framebuffer):
self.submodules.videophy = VideoVGAPHY(platform.request("vga"), clock_domain="vga")
if (cg3):
if (bw2):
self.submodules.bw2 = bw2_fb.bw2(soc=self, phy=self.videophy, timings=cg3_res, clock_domain="vga") # clock_domain for the VGA side, bw2 is running in cd_sys
self.bus.add_slave("bw2_bt", self.bw2.bus, SoCRegion(origin=self.mem_map.get("cg3_bt", None), size=0x1000, cached=False)) # bw2 uses cg3_bt
elif (cg3):
self.submodules.cg3 = cg3_fb.cg3(soc=self, phy=self.videophy, timings=cg3_res, clock_domain="vga") # clock_domain for the VGA side, cg3 is running in cd_sys
self.bus.add_slave("cg3_bt", self.cg3.bus, SoCRegion(origin=self.mem_map.get("cg3_bt", None), size=0x1000, cached=False))
else:
self.submodules.cg6 = cg6_fb.cg6(soc=self, phy=self.videophy, timings=cg3_res, clock_domain="vga") # clock_domain for the VGA side, cg6 is running in cd_sys
self.bus.add_slave("cg6_bt", self.cg6.bus, SoCRegion(origin=self.mem_map.get("cg6_bt", None), size=0x1000, cached=False))
if (cg6):
self.submodules.cg6_accel = cg6_accel.CG6Accel(soc = self, base_fb = base_fb, hres = hres, vres = vres)
self.bus.add_slave("cg6_fbc", self.cg6_accel.bus, SoCRegion(origin=self.mem_map.get("cg6_fbc", None), size=0x2000, cached=False))
@ -535,6 +543,7 @@ def main():
parser.add_argument("--usb", action="store_true", help="add a USB OHCI controller [V1.2]")
parser.add_argument("--engine", action="store_true", help="add a Engine crypto core [all]")
parser.add_argument("--i2c", action="store_true", help="add an I2C bus [none, placeholder]")
parser.add_argument("--bw2", action="store_true", help="add a BW2 framebuffer [V1.2+VGA_RGB222 pmod]")
parser.add_argument("--cg3", action="store_true", help="add a CG3 framebuffer [V1.2+VGA_RGB222 pmod]")
parser.add_argument("--cg3-res", default="1152x900@76Hz", help="Specify the CG3/CG6 resolution")
parser.add_argument("--cg6", action="store_true", help="add a CG6 framebuffer [V1.2+VGA_RGB222 pmod]")
@ -549,11 +558,11 @@ def main():
print(" ***** WARNING ***** : USB on V1.0 is an ugly hack \n");
if (args.i2c):
print(" ***** WARNING ***** : I2C on V1.x is for testing the core \n");
if ((args.cg3 or args.cg6) and (args.version == "V1.0")):
if ((args.bw2 or args.cg3 or args.cg6) and (args.version == "V1.0")):
print(" ***** ERROR ***** : VGA not supported on V1.0\n")
assert(False)
if (args.cg3 and args.cg6):
print(" ***** ERROR ***** : can't have both CG3 and CG6\n")
if ((args.bw2 and args.cg3) or (args.bw2 and args.cg6) or (args.cg3 and args.cg6)):
print(" ***** ERROR ***** : can't have more than one of BW2, CG3 and CG6\n")
assert(False)
soc = SBusFPGA(**soc_core_argdict(args),
@ -565,6 +574,7 @@ def main():
usb=args.usb,
engine=args.engine,
i2c=args.i2c,
bw2=args.bw2,
cg3=args.cg3,
cg6=args.cg6,
cg3_res=args.cg3_res,
@ -612,6 +622,7 @@ def main():
sdram=args.sdram,
engine=args.engine,
i2c=args.i2c,
bw2=args.bw2,
cg3=args.cg3,
cg6=args.cg6,
cg3_res=args.cg3_res,