diff --git a/sbus-to-ztex-gateware-migen/bw2.fth b/sbus-to-ztex-gateware-migen/bw2.fth new file mode 100644 index 0000000..8aeacbc --- /dev/null +++ b/sbus-to-ztex-gateware-migen/bw2.fth @@ -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 diff --git a/sbus-to-ztex-gateware-migen/bw2_fb.py b/sbus-to-ztex-gateware-migen/bw2_fb.py new file mode 100644 index 0000000..759873a --- /dev/null +++ b/sbus-to-ztex-gateware-migen/bw2_fb.py @@ -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), + ) + ) diff --git a/sbus-to-ztex-gateware-migen/bw2_init.fth b/sbus-to-ztex-gateware-migen/bw2_init.fth new file mode 100644 index 0000000..332455e --- /dev/null +++ b/sbus-to-ztex-gateware-migen/bw2_init.fth @@ -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 +; diff --git a/sbus-to-ztex-gateware-migen/cg3_fb.py b/sbus-to-ztex-gateware-migen/cg3_fb.py index 20d1565..2ca16db 100644 --- a/sbus-to-ztex-gateware-migen/cg3_fb.py +++ b/sbus-to-ztex-gateware-migen/cg3_fb.py @@ -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), ], diff --git a/sbus-to-ztex-gateware-migen/cg6_accel.py b/sbus-to-ztex-gateware-migen/cg6_accel.py index f066f5b..49f5916 100644 --- a/sbus-to-ztex-gateware-migen/cg6_accel.py +++ b/sbus-to-ztex-gateware-migen/cg6_accel.py @@ -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) diff --git a/sbus-to-ztex-gateware-migen/cg6_fb.py b/sbus-to-ztex-gateware-migen/cg6_fb.py index 7dcb3c6..c336ffd 100644 --- a/sbus-to-ztex-gateware-migen/cg6_fb.py +++ b/sbus-to-ztex-gateware-migen/cg6_fb.py @@ -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), ], diff --git a/sbus-to-ztex-gateware-migen/sbus_to_fpga_blk_dma.py b/sbus-to-ztex-gateware-migen/sbus_to_fpga_blk_dma.py index bb30fd1..1c563ca 100644 --- a/sbus-to-ztex-gateware-migen/sbus_to_fpga_blk_dma.py +++ b/sbus-to-ztex-gateware-migen/sbus_to_fpga_blk_dma.py @@ -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), ) ) ) diff --git a/sbus-to-ztex-gateware-migen/sbus_to_fpga_fsm.py b/sbus-to-ztex-gateware-migen/sbus_to_fpga_fsm.py index 880a9b4..c8bffc8 100644 --- a/sbus-to-ztex-gateware-migen/sbus_to_fpga_fsm.py +++ b/sbus-to-ztex-gateware-migen/sbus_to_fpga_fsm.py @@ -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), diff --git a/sbus-to-ztex-gateware-migen/sbus_to_fpga_prom.py b/sbus-to-ztex-gateware-migen/sbus_to_fpga_prom.py index 60fe25d..e4a90e1 100644 --- a/sbus-to-ztex-gateware-migen/sbus_to_fpga_prom.py +++ b/sbus-to-ztex-gateware-migen/sbus_to_fpga_prom.py @@ -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): diff --git a/sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py b/sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py index c83faae..06173ea 100644 --- a/sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py +++ b/sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py @@ -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,