Merge branch 'main' of github.com:rdolbeau/SBusFPGA into main
This commit is contained in:
commit
2aec1af733
145
sbus-to-ztex-gateware-migen/bw2.fth
Normal file
145
sbus-to-ztex-gateware-migen/bw2.fth
Normal 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
|
||||
197
sbus-to-ztex-gateware-migen/bw2_fb.py
Normal file
197
sbus-to-ztex-gateware-migen/bw2_fb.py
Normal 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),
|
||||
)
|
||||
)
|
||||
24
sbus-to-ztex-gateware-migen/bw2_init.fth
Normal file
24
sbus-to-ztex-gateware-migen/bw2_init.fth
Normal 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
|
||||
;
|
||||
@ -27,6 +27,17 @@ cg3_timings = {
|
||||
},
|
||||
}
|
||||
|
||||
cmap_layout = [
|
||||
("color", 2),
|
||||
("address", 8),
|
||||
("data", 8),
|
||||
]
|
||||
omap_layout = [
|
||||
("color", 2),
|
||||
("address", 2),
|
||||
("data", 8),
|
||||
]
|
||||
|
||||
def cg3_rounded_size(hres, vres):
|
||||
mib = int(ceil(((hres * vres) + 0) / 1048576))
|
||||
if (mib == 3):
|
||||
@ -42,6 +53,13 @@ class VideoFrameBuffer256c(Module, AutoCSR):
|
||||
"""Video FrameBuffer256c"""
|
||||
def __init__(self, dram_port, upd_clut_fifo = None, hres=800, vres=600, base=0x00000000, fifo_depth=65536, clock_domain="sys", clock_faster_than_sys=False, hwcursor=False, upd_overlay_fifo=False, upd_omap_fifo=False):
|
||||
clut = Array(Array(Signal(8, reset = (255-i)) for i in range(0, 256)) for j in range(0, 3))
|
||||
|
||||
upd_clut_fifo_dout = Record(cmap_layout)
|
||||
self.comb += upd_clut_fifo_dout.raw_bits().eq(upd_clut_fifo.dout)
|
||||
|
||||
if (hwcursor):
|
||||
upd_omap_fifo_dout = Record(omap_layout)
|
||||
self.comb += upd_omap_fifo_dout.raw_bits().eq(upd_omap_fifo.dout)
|
||||
|
||||
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}")
|
||||
|
||||
@ -49,7 +67,7 @@ class VideoFrameBuffer256c(Module, AutoCSR):
|
||||
vga_sync += [
|
||||
If(upd_clut_fifo.readable,
|
||||
upd_clut_fifo.re.eq(1),
|
||||
clut[upd_clut_fifo.dout[0:2]][upd_clut_fifo.dout[2:10]].eq(upd_clut_fifo.dout[10:18]),
|
||||
clut[upd_clut_fifo_dout.color][upd_clut_fifo_dout.address].eq(upd_clut_fifo_dout.data),
|
||||
).Else(
|
||||
upd_clut_fifo.re.eq(0),
|
||||
)
|
||||
@ -70,7 +88,7 @@ class VideoFrameBuffer256c(Module, AutoCSR):
|
||||
vga_sync += [
|
||||
If(upd_omap_fifo.readable,
|
||||
upd_omap_fifo.re.eq(1),
|
||||
omap[upd_omap_fifo.dout[0:2]][upd_omap_fifo.dout[2:4]].eq(upd_omap_fifo.dout[4:12]),
|
||||
omap[upd_omap_fifo_dout.color][upd_omap_fifo_dout.address].eq(upd_omap_fifo_dout.data),
|
||||
).Else(
|
||||
upd_omap_fifo.re.eq(0),
|
||||
)
|
||||
@ -234,7 +252,9 @@ class cg3(Module, AutoCSR):
|
||||
def __init__(self, soc, phy=None, timings = None, clock_domain="sys"):
|
||||
|
||||
# 2 bits for color (0/r, 1/g, 2/b), 8 for @ and 8 for value
|
||||
self.submodules.upd_cmap_fifo = upd_cmap_fifo = ClockDomainsRenamer({"read": "vga", "write": "sys"})(AsyncFIFOBuffered(width=2+8+8, depth=8))
|
||||
self.submodules.upd_cmap_fifo = upd_cmap_fifo = ClockDomainsRenamer({"read": "vga", "write": "sys"})(AsyncFIFOBuffered(width=layout_len(cmap_layout), depth=8))
|
||||
upd_cmap_fifo_din = Record(cmap_layout)
|
||||
self.comb += self.upd_cmap_fifo.din.eq(upd_cmap_fifo_din.raw_bits())
|
||||
|
||||
name = "video_framebuffer"
|
||||
# near duplicate of plaform.add_video_framebuffer
|
||||
@ -296,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))
|
||||
@ -322,7 +348,9 @@ class cg3(Module, AutoCSR):
|
||||
1: [ Case(bus.sel, {
|
||||
"default": [ NextValue(bt_cmap_buf, bus.dat_w[0:24]),
|
||||
upd_cmap_fifo.we.eq(1),
|
||||
upd_cmap_fifo.din.eq(Cat(bt_cmap_state, bt_cmap_idx, bus.dat_w[24:32])),
|
||||
upd_cmap_fifo_din.color.eq(bt_cmap_state),
|
||||
upd_cmap_fifo_din.address.eq(bt_cmap_idx),
|
||||
upd_cmap_fifo_din.data.eq(bus.dat_w[24:32]),
|
||||
Case(bt_cmap_state, {
|
||||
0: [ NextValue(bt_cmap_state, 1), ],
|
||||
1: [ NextValue(bt_cmap_state, 2), ],
|
||||
@ -333,7 +361,9 @@ class cg3(Module, AutoCSR):
|
||||
],
|
||||
# will sel be 1 or 8 ?
|
||||
1: [ upd_cmap_fifo.we.eq(1),
|
||||
upd_cmap_fifo.din.eq(Cat(bt_cmap_state, bt_cmap_idx, bus.dat_w[24:32])),
|
||||
upd_cmap_fifo_din.color.eq(bt_cmap_state),
|
||||
upd_cmap_fifo_din.address.eq(bt_cmap_idx),
|
||||
upd_cmap_fifo_din.data.eq(bus.dat_w[24:32]),
|
||||
Case(bt_cmap_state, {
|
||||
0: [ NextValue(bt_cmap_state, 1), ],
|
||||
1: [ NextValue(bt_cmap_state, 2), ],
|
||||
@ -342,7 +372,9 @@ class cg3(Module, AutoCSR):
|
||||
})
|
||||
],
|
||||
8: [ upd_cmap_fifo.we.eq(1),
|
||||
upd_cmap_fifo.din.eq(Cat(bt_cmap_state, bt_cmap_idx, bus.dat_w[24:32])),
|
||||
upd_cmap_fifo_din.color.eq(bt_cmap_state),
|
||||
upd_cmap_fifo_din.address.eq(bt_cmap_idx),
|
||||
upd_cmap_fifo_din.data.eq(bus.dat_w[24:32]),
|
||||
Case(bt_cmap_state, {
|
||||
0: [ NextValue(bt_cmap_state, 1), ],
|
||||
1: [ NextValue(bt_cmap_state, 2), ],
|
||||
@ -397,7 +429,9 @@ class cg3(Module, AutoCSR):
|
||||
wishbone_fsm.act("cmap_a",
|
||||
If(upd_cmap_fifo.writable,
|
||||
upd_cmap_fifo.we.eq(1),
|
||||
upd_cmap_fifo.din.eq(Cat(bt_cmap_state, bt_cmap_idx, bt_cmap_buf[16:24])),
|
||||
upd_cmap_fifo_din.color.eq(bt_cmap_state),
|
||||
upd_cmap_fifo_din.address.eq(bt_cmap_idx),
|
||||
upd_cmap_fifo_din.data.eq(bus.dat_w[16:24]),
|
||||
Case(bt_cmap_state, {
|
||||
0: [ NextValue(bt_cmap_state, 1), ],
|
||||
1: [ NextValue(bt_cmap_state, 2), ],
|
||||
@ -408,7 +442,9 @@ class cg3(Module, AutoCSR):
|
||||
wishbone_fsm.act("cmap_b",
|
||||
If(upd_cmap_fifo.writable,
|
||||
upd_cmap_fifo.we.eq(1),
|
||||
upd_cmap_fifo.din.eq(Cat(bt_cmap_state, bt_cmap_idx, bt_cmap_buf[8:16])),
|
||||
upd_cmap_fifo_din.color.eq(bt_cmap_state),
|
||||
upd_cmap_fifo_din.address.eq(bt_cmap_idx),
|
||||
upd_cmap_fifo_din.data.eq(bus.dat_w[8:16]),
|
||||
Case(bt_cmap_state, {
|
||||
0: [ NextValue(bt_cmap_state, 1), ],
|
||||
1: [ NextValue(bt_cmap_state, 2), ],
|
||||
@ -419,7 +455,9 @@ class cg3(Module, AutoCSR):
|
||||
wishbone_fsm.act("cmap_c",
|
||||
If(upd_cmap_fifo.writable,
|
||||
upd_cmap_fifo.we.eq(1),
|
||||
upd_cmap_fifo.din.eq(Cat(bt_cmap_state, bt_cmap_idx, bt_cmap_buf[0:8])),
|
||||
upd_cmap_fifo_din.color.eq(bt_cmap_state),
|
||||
upd_cmap_fifo_din.address.eq(bt_cmap_idx),
|
||||
upd_cmap_fifo_din.data.eq(bus.dat_w[0:8]),
|
||||
Case(bt_cmap_state, {
|
||||
0: [ NextValue(bt_cmap_state, 1), ],
|
||||
1: [ NextValue(bt_cmap_state, 2), ],
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -13,7 +13,6 @@ from litex.soc.cores.video import *
|
||||
from math import ceil;
|
||||
|
||||
# reuse the simple 8-bits DAC from cg3
|
||||
# we will be missing the HW cursor
|
||||
import cg3_fb;
|
||||
|
||||
# a lot of that is identical to cg3_fb.cg3
|
||||
@ -21,9 +20,15 @@ class cg6(Module, AutoCSR):
|
||||
def __init__(self, soc, phy=None, timings = None, clock_domain="sys"):
|
||||
|
||||
# 2 bits for color (0/r, 1/g, 2/b), 8 for @ and 8 for value
|
||||
self.submodules.upd_cmap_fifo = upd_cmap_fifo = ClockDomainsRenamer({"read": "vga", "write": "sys"})(AsyncFIFOBuffered(width=2+8+8, depth=8))
|
||||
self.submodules.upd_cmap_fifo = upd_cmap_fifo = ClockDomainsRenamer({"read": "vga", "write": "sys"})(AsyncFIFOBuffered(width=layout_len(cg3_fb.cmap_layout), depth=8))
|
||||
upd_cmap_fifo_din = Record(cg3_fb.cmap_layout)
|
||||
self.comb += self.upd_cmap_fifo.din.eq(upd_cmap_fifo_din.raw_bits())
|
||||
|
||||
self.submodules.upd_overlay_fifo = upd_overlay_fifo = ClockDomainsRenamer({"read": "vga", "write": "sys"})(AsyncFIFOBuffered(width=1+5+32, depth=8))
|
||||
self.submodules.upd_omap_fifo = upd_omap_fifo = ClockDomainsRenamer({"read": "vga", "write": "sys"})(AsyncFIFOBuffered(width=2+2+8, depth=8))
|
||||
|
||||
self.submodules.upd_omap_fifo = upd_omap_fifo = ClockDomainsRenamer({"read": "vga", "write": "sys"})(AsyncFIFOBuffered(width=layout_len(cg3_fb.omap_layout), depth=8))
|
||||
upd_omap_fifo_din = Record(cg3_fb.omap_layout)
|
||||
self.comb += self.upd_omap_fifo.din.eq(upd_omap_fifo_din.raw_bits())
|
||||
|
||||
name = "video_framebuffer"
|
||||
# near duplicate of plaform.add_video_framebuffer
|
||||
@ -94,7 +99,9 @@ class cg6(Module, AutoCSR):
|
||||
],
|
||||
# bt_cmap
|
||||
1: [ upd_cmap_fifo.we.eq(1),
|
||||
upd_cmap_fifo.din.eq(Cat(bt_cmap_state, bt_addr, bus.dat_w[24:32])),
|
||||
upd_cmap_fifo_din.color.eq(bt_cmap_state),
|
||||
upd_cmap_fifo_din.address.eq(bt_addr),
|
||||
upd_cmap_fifo_din.data.eq(bus.dat_w[24:32]),
|
||||
Case(bt_cmap_state, {
|
||||
0: [ NextValue(bt_cmap_state, 1), ],
|
||||
1: [ NextValue(bt_cmap_state, 2), ],
|
||||
@ -108,7 +115,9 @@ class cg6(Module, AutoCSR):
|
||||
# bt_omap
|
||||
# NetBSD driver write the cursor color in there
|
||||
3: [ upd_omap_fifo.we.eq(1),
|
||||
upd_omap_fifo.din.eq(Cat(bt_cmap_state, bt_addr, bus.dat_w[24:32])),
|
||||
upd_omap_fifo_din.color.eq(bt_cmap_state),
|
||||
upd_omap_fifo_din.address.eq(bt_addr[0:2]),
|
||||
upd_omap_fifo_din.data.eq(bus.dat_w[24:32]),
|
||||
Case(bt_cmap_state, {
|
||||
0: [ NextValue(bt_cmap_state, 1), ],
|
||||
1: [ NextValue(bt_cmap_state, 2), ],
|
||||
|
||||
@ -20,6 +20,13 @@ class ExchangeWithMem(Module, AutoCSR):
|
||||
self.dram_dma_writer = dram_dma_writer
|
||||
self.dram_dma_reader = dram_dma_reader
|
||||
|
||||
tosbus_fifo_din = Record(soc.tosbus_layout)
|
||||
self.comb += self.tosbus_fifo.din.eq(tosbus_fifo_din.raw_bits())
|
||||
fromsbus_req_fifo_din = Record(soc.fromsbus_req_layout)
|
||||
self.comb += self.fromsbus_req_fifo.din.eq(fromsbus_req_fifo_din.raw_bits())
|
||||
fromsbus_fifo_dout = Record(soc.fromsbus_layout)
|
||||
self.comb += fromsbus_fifo_dout.raw_bits().eq(self.fromsbus_fifo.dout)
|
||||
|
||||
print(f"Configuring the SDRAM for {mem_size} MiB\n")
|
||||
|
||||
data_width = burst_size * 4
|
||||
@ -186,7 +193,8 @@ class ExchangeWithMem(Module, AutoCSR):
|
||||
req_r_fsm.act("WaitForData",
|
||||
If(self.dram_dma_reader.source.valid & self.tosbus_fifo.writable,
|
||||
self.tosbus_fifo.we.eq(1),
|
||||
self.tosbus_fifo.din.eq(Cat(dma_r_addr, self.dram_dma_reader.source.data)),
|
||||
tosbus_fifo_din.address.eq(dma_r_addr),
|
||||
tosbus_fifo_din.data.eq(self.dram_dma_reader.source.data),
|
||||
If(do_checksum,
|
||||
self.checksum.we.eq(1),
|
||||
self.checksum.dat_w.eq(self.checksum.storage ^ self.dram_dma_reader.source.data),
|
||||
@ -209,7 +217,8 @@ class ExchangeWithMem(Module, AutoCSR):
|
||||
req_r_fsm.act("QueueReqToMemory",
|
||||
If(self.fromsbus_req_fifo.writable,
|
||||
self.fromsbus_req_fifo.we.eq(1),
|
||||
self.fromsbus_req_fifo.din.eq(Cat(local_r_addr, dma_r_addr)),
|
||||
fromsbus_req_fifo_din.blkaddress.eq(local_r_addr),
|
||||
fromsbus_req_fifo_din.dmaaddress.eq(dma_r_addr),
|
||||
NextValue(self.last_blk.status, local_r_addr),
|
||||
NextValue(self.last_dma.status, dma_r_addr),
|
||||
NextValue(self.blk_rem.status, self.blk_rem.status - 1),
|
||||
@ -257,16 +266,16 @@ class ExchangeWithMem(Module, AutoCSR):
|
||||
)
|
||||
req_w_fsm.act("Idle",
|
||||
If(self.fromsbus_fifo.readable,
|
||||
self.dram_dma_writer.sink.address.eq(self.fromsbus_fifo.dout[0:blk_addr_width]),
|
||||
self.dram_dma_writer.sink.data.eq(self.fromsbus_fifo.dout[blk_addr_width:(blk_addr_width + data_width_bits)]),
|
||||
self.dram_dma_writer.sink.address.eq(fromsbus_fifo_dout.blkaddress),
|
||||
self.dram_dma_writer.sink.data.eq(fromsbus_fifo_dout.data),
|
||||
self.dram_dma_writer.sink.valid.eq(1),
|
||||
NextValue(self.wr_tosdram.status, self.fromsbus_fifo.dout[0:blk_addr_width]),
|
||||
NextValue(self.wr_tosdram.status, fromsbus_fifo_dout.blkaddress),
|
||||
If(self.dram_dma_writer.sink.ready,
|
||||
self.fromsbus_fifo.re.eq(1),
|
||||
NextValue(self.dma_wrdone.status, self.dma_wrdone.status + 1),
|
||||
If(do_checksum,
|
||||
self.checksum.we.eq(1),
|
||||
self.checksum.dat_w.eq(self.checksum.storage ^ self.fromsbus_fifo.dout[blk_addr_width:(blk_addr_width + data_width_bits)]),
|
||||
self.checksum.dat_w.eq(self.checksum.storage ^ fromsbus_fifo_dout.data),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@ -180,7 +180,7 @@ LED_M_READ = 0x20
|
||||
LED_M_CACHE = 0x40
|
||||
|
||||
class SBusFPGABus(Module):
|
||||
def __init__(self, platform, hold_reset, wishbone_slave, wishbone_master, tosbus_fifo, fromsbus_fifo, fromsbus_req_fifo, version, burst_size = 8, cg3_fb_size = 0, cg3_base=0x8ff00000 ):
|
||||
def __init__(self, soc, platform, hold_reset, wishbone_slave, wishbone_master, tosbus_fifo, fromsbus_fifo, fromsbus_req_fifo, version, burst_size = 8, cg3_fb_size = 0, cg3_base=0x8ff00000 ):
|
||||
self.platform = platform
|
||||
self.hold_reset = hold_reset
|
||||
|
||||
@ -191,6 +191,17 @@ class SBusFPGABus(Module):
|
||||
self.fromsbus_fifo = fromsbus_fifo
|
||||
self.fromsbus_req_fifo = fromsbus_req_fifo
|
||||
|
||||
|
||||
tosbus_fifo_dout = Record(soc.tosbus_layout)
|
||||
self.comb += tosbus_fifo_dout.raw_bits().eq(self.tosbus_fifo.dout)
|
||||
|
||||
fromsbus_req_fifo_dout = Record(soc.fromsbus_req_layout)
|
||||
self.comb += fromsbus_req_fifo_dout.raw_bits().eq(self.fromsbus_req_fifo.dout)
|
||||
|
||||
fromsbus_fifo_din = Record(soc.fromsbus_layout)
|
||||
self.comb += self.fromsbus_fifo.din.eq(fromsbus_fifo_din.raw_bits())
|
||||
|
||||
|
||||
if (cg3_fb_size <= 1*1048576):
|
||||
CG3_UPPER_BITS=12
|
||||
CG3_KEPT_UPPER_BIT=20
|
||||
@ -959,11 +970,11 @@ class SBusFPGABus(Module):
|
||||
NextValue(sbus_oe_master_in, 0), ## ERRs, ACKs are input
|
||||
NextValue(burst_counter, 0),
|
||||
NextValue(burst_limit_m1, burst_size - 1),
|
||||
NextValue(SBUS_3V3_D_o, self.tosbus_fifo.dout[0:32]),
|
||||
NextValue(sbus_master_last_virtual, self.tosbus_fifo.dout[0:32]),
|
||||
NextValue(master_addr, self.tosbus_fifo.dout[2:32]),
|
||||
NextValue(master_data, self.tosbus_fifo.dout[32:64]),
|
||||
NextValue(fifo_buffer, self.tosbus_fifo.dout[32:]),
|
||||
NextValue(SBUS_3V3_D_o, tosbus_fifo_dout.address),
|
||||
NextValue(sbus_master_last_virtual, tosbus_fifo_dout.address),
|
||||
NextValue(master_addr, tosbus_fifo_dout.address[2:32]),
|
||||
NextValue(master_data, tosbus_fifo_dout.data[0:32]),
|
||||
NextValue(fifo_buffer, tosbus_fifo_dout.data),
|
||||
NextValue(master_src, MASTER_SRC_BLKDMAFIFO),
|
||||
self.tosbus_fifo.re.eq(1),
|
||||
Case(burst_size, {
|
||||
@ -995,9 +1006,9 @@ class SBusFPGABus(Module):
|
||||
NextValue(sbus_oe_master_in, 0), ## ERRs, ACKs are input
|
||||
NextValue(burst_counter, 0),
|
||||
NextValue(burst_limit_m1, burst_size - 1),
|
||||
NextValue(SBUS_3V3_D_o, self.fromsbus_req_fifo.dout[blk_addr_width:blk_addr_width+32]),
|
||||
NextValue(sbus_master_last_virtual, self.fromsbus_req_fifo.dout[blk_addr_width:blk_addr_width+32]),
|
||||
NextValue(fifo_blk_addr, self.fromsbus_req_fifo.dout[0:blk_addr_width]),
|
||||
NextValue(SBUS_3V3_D_o, fromsbus_req_fifo_dout.dmaaddress),
|
||||
NextValue(sbus_master_last_virtual, fromsbus_req_fifo_dout.dmaaddress),
|
||||
NextValue(fifo_blk_addr, fromsbus_req_fifo_dout.blkaddress),
|
||||
NextValue(master_src, MASTER_SRC_BLKDMAFIFO),
|
||||
self.fromsbus_req_fifo.re.eq(1),
|
||||
Case(burst_size, {
|
||||
@ -1635,7 +1646,8 @@ class SBusFPGABus(Module):
|
||||
Case(master_src, {
|
||||
MASTER_SRC_BLKDMAFIFO:
|
||||
[fromsbus_fifo.we.eq(1),
|
||||
fromsbus_fifo.din.eq(Cat(fifo_blk_addr, fifo_buffer)),
|
||||
fromsbus_fifo_din.blkaddress.eq(fifo_blk_addr),
|
||||
fromsbus_fifo_din.data.eq(fifo_buffer),
|
||||
],
|
||||
}),
|
||||
NextValue(sbus_oe_data, 0),
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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
|
||||
@ -383,15 +389,33 @@ class SBusFPGA(SoCCore):
|
||||
# burst_size=16 should work on Ultra systems, but then they probably should go for 64-bits ET as well...
|
||||
# Older systems are probably limited to burst_size=4, (it should always be available)
|
||||
burst_size=8
|
||||
self.submodules.tosbus_fifo = ClockDomainsRenamer({"read": "sbus", "write": "sys"})(AsyncFIFOBuffered(width=(32+burst_size*32), depth=burst_size))
|
||||
self.submodules.fromsbus_fifo = ClockDomainsRenamer({"write": "sbus", "read": "sys"})(AsyncFIFOBuffered(width=((30-log2_int(burst_size))+burst_size*32), depth=burst_size))
|
||||
self.submodules.fromsbus_req_fifo = ClockDomainsRenamer({"read": "sbus", "write": "sys"})(AsyncFIFOBuffered(width=((30-log2_int(burst_size))+32), depth=burst_size))
|
||||
|
||||
data_width = burst_size * 4
|
||||
data_width_bits = burst_size * 32
|
||||
blk_addr_width = 32 - log2_int(data_width)
|
||||
|
||||
self.tosbus_layout = [
|
||||
("address", 32),
|
||||
("data", data_width_bits),
|
||||
]
|
||||
self.fromsbus_layout = [
|
||||
("blkaddress", blk_addr_width),
|
||||
("data", data_width_bits),
|
||||
]
|
||||
self.fromsbus_req_layout = [
|
||||
("blkaddress", blk_addr_width),
|
||||
("dmaaddress", 32),
|
||||
]
|
||||
|
||||
self.submodules.tosbus_fifo = ClockDomainsRenamer({"read": "sbus", "write": "sys"})(AsyncFIFOBuffered(width=layout_len(self.tosbus_layout), depth=burst_size))
|
||||
self.submodules.fromsbus_fifo = ClockDomainsRenamer({"write": "sbus", "read": "sys"})(AsyncFIFOBuffered(width=layout_len(self.fromsbus_layout), depth=burst_size))
|
||||
self.submodules.fromsbus_req_fifo = ClockDomainsRenamer({"read": "sbus", "write": "sys"})(AsyncFIFOBuffered(width=layout_len(self.fromsbus_req_layout), depth=burst_size))
|
||||
if (sdram):
|
||||
self.submodules.dram_dma_writer = LiteDRAMDMAWriter(port=self.sdram.crossbar.get_port(mode="write", data_width=burst_size*32),
|
||||
self.submodules.dram_dma_writer = LiteDRAMDMAWriter(port=self.sdram.crossbar.get_port(mode="write", data_width=data_width_bits),
|
||||
fifo_depth=4,
|
||||
fifo_buffered=True)
|
||||
|
||||
self.submodules.dram_dma_reader = LiteDRAMDMAReader(port=self.sdram.crossbar.get_port(mode="read", data_width=burst_size*32),
|
||||
self.submodules.dram_dma_reader = LiteDRAMDMAReader(port=self.sdram.crossbar.get_port(mode="read", data_width=data_width_bits),
|
||||
fifo_depth=4,
|
||||
fifo_buffered=True)
|
||||
|
||||
@ -414,7 +438,8 @@ class SBusFPGA(SoCCore):
|
||||
self.comb += pad_sdram_interrupt.eq(sig_sdram_interrupt)
|
||||
self.comb += sig_sdram_interrupt.eq(~self.exchange_with_mem.irq) ##
|
||||
|
||||
_sbus_bus = SBusFPGABus(platform=self.platform,
|
||||
_sbus_bus = SBusFPGABus(soc=self,
|
||||
platform=self.platform,
|
||||
hold_reset=hold_reset,
|
||||
wishbone_slave=wishbone_slave_sbus,
|
||||
wishbone_master=self.wishbone_master_sbus,
|
||||
@ -469,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))
|
||||
@ -516,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]")
|
||||
@ -530,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),
|
||||
@ -546,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,
|
||||
@ -593,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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user