1
0
mirror of synced 2026-03-08 03:19:24 +00:00

proto CG6

This commit is contained in:
Romain Dolbeau
2021-10-15 22:38:27 +02:00
parent d552b1cd52
commit 5b8124b939
14 changed files with 8634 additions and 54 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
OUTPUT_ARCH( "riscv" )
SECTIONS
{
. = 0x00410000;
.text : { *(.text) }
}

View File

@@ -0,0 +1,22 @@
#!/bin/bash -x
GCCDIR=~/LITEX/riscv64-unknown-elf-gcc-10.1.0-2020.08.2-x86_64-linux-ubuntu14
GCCPFX=riscv64-unknown-elf-
#GCCDIR=/opt/rv32bk
#GCCPFX=riscv32-buildroot-linux-gnu-
#GCCDIR=~dolbeau/LITEX/buildroot-32SF/output/host
#GCCPFX=riscv32-buildroot-linux-gnu-
GCC=${GCCDIR}/bin/${GCCPFX}gcc
OBJCOPY=${GCCDIR}/bin/${GCCPFX}objcopy
if test "x$1" == "xASM"; then
$GCC -Os -o blit -march=rv32ib -mabi=ilp32 -T blit.lds -nostartfiles blit.s &&
$OBJCOPY -O binary -j .text blit blit.raw
else
$GCC -Os -S blit.c -march=rv32ib -mabi=ilp32 -mstrict-align -fno-builtin-memset -nostdlib -ffreestanding -nostartfiles &&
$GCC -Os -o blit -march=rv32ib -mabi=ilp32 -T blit.lds -nostartfiles blit.s &&
$OBJCOPY -O binary -j .text blit blit.raw
fi

View File

@@ -16,7 +16,7 @@
h# SBUSFPGA_CG3_WIDTH
;
h# 400000 constant cg3-off-dac
h# sbusfpga_regionaddr_cg3_bt constant cg3-off-dac
h# 20 constant /cg3-off-dac
h# 800000 constant cg3-off-fb
@@ -86,7 +86,7 @@ headerless
" cgthree" device-name
" display" device-type
" SUNW,501-1415" model
" RDOL,sbusfpga" model
: qemu-cg3-driver-install ( -- )
cg3-dac -1 = if

View File

@@ -32,7 +32,7 @@ def cg3_rounded_size(hres, vres):
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):
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))
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}")
@@ -46,8 +46,29 @@ class VideoFrameBuffer256c(Module, AutoCSR):
upd_clut_fifo.re.eq(0),
)
]
self.vtg_sink = vtg_sink = stream.Endpoint(video_timing_layout)
if (hwcursor):
self.vtg_sink = vtg_sink = stream.Endpoint(video_timing_hwcursor_layout)
overlay = Array(Array(Array(Signal(1) for x in range(0,32)) for y in range(0,32)) for i in range(0, 2))
omap = Array(Array(Signal(8, reset = (255-i)) for i in range(0, 4)) for j in range(0, 3))
vga_sync += [
If(upd_overlay_fifo.readable,
upd_overlay_fifo.re.eq(1),
[ overlay[upd_overlay_fifo.dout[0]][upd_overlay_fifo.dout[1:6]][x].eq(upd_overlay_fifo.dout[6+x]) for x in range(0, 32)],
).Else(
upd_overlay_fifo.re.eq(0),
)
]
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]),
).Else(
upd_omap_fifo.re.eq(0),
)
]
else:
self.vtg_sink = vtg_sink = stream.Endpoint(video_timing_layout)
self.source = source = stream.Endpoint(video_data_layout)
self.underflow = Signal()
@@ -107,7 +128,11 @@ class VideoFrameBuffer256c(Module, AutoCSR):
vtg_sink.ready.eq(source.valid & source.ready),
),
vtg_sink.connect(source, keep={"de", "hsync", "vsync"}),
If(vtg_sink.de,
If(vtg_sink.hwcursor & (overlay[0][vtg_sink.hwcursory][vtg_sink.hwcursorx] | overlay[1][vtg_sink.hwcursory][vtg_sink.hwcursorx]),
source.r.eq(omap[0][Cat(overlay[0][vtg_sink.hwcursory][vtg_sink.hwcursorx], overlay[1][vtg_sink.hwcursory][vtg_sink.hwcursorx])]),
source.g.eq(omap[0][Cat(overlay[0][vtg_sink.hwcursory][vtg_sink.hwcursorx], overlay[1][vtg_sink.hwcursory][vtg_sink.hwcursorx])]),
source.b.eq(omap[0][Cat(overlay[0][vtg_sink.hwcursory][vtg_sink.hwcursorx], overlay[1][vtg_sink.hwcursory][vtg_sink.hwcursorx])]),
).Elif(vtg_sink.de,
source.r.eq(clut[0][video_pipe_source.data]),
source.g.eq(clut[1][video_pipe_source.data]),
source.b.eq(clut[2][video_pipe_source.data])
@@ -197,9 +222,9 @@ class cg3(Module, AutoCSR):
fbc_cursor_end = Signal(8) # 0x13 ?
fbc_vcontrol = Array(Signal(8) for a in range(0, 3))
# current cmap logic for the CG3.
# the CG6 takes 32 bits write but only use the top 8 bits, for bt_addr & bt_cmap
# alto it uses the BT HW cursor (though probably not in the console?)
# current cmap logic for the CG3
# (the CG6 takes 32 bits write but only use the top 8 bits, for bt_addr & bt_cmap
# also it uses the BT HW cursor (though probably not in the console?) )
self.submodules.wishbone_fsm = wishbone_fsm = FSM(reset_state = "Reset")
wishbone_fsm.act("Reset",

View File

@@ -0,0 +1,149 @@
\ simplified version of the OpenBIOS cgthree code
\ ... for the cg6
: openbios-video-width
h# SBUSFPGA_CG3_WIDTH
;
: openbios-video-height
h# SBUSFPGA_CG3_HEIGHT
;
: depth-bits
h# 8
;
: line-bytes
h# SBUSFPGA_CG3_WIDTH
;
sbusfpga_regionaddr_cg6_bt constant cg6-off-dac
h# 20 constant /cg6-off-dac
h# 800000 constant cg6-off-fb
h# SBUSFPGA_CG3_BUFSIZE constant /cg6-off-fb
: >cg6-reg-spec ( offset size -- encoded-reg )
>r 0 my-address d+ my-space encode-phys r> encode-int encode+
;
: cg6-reg
\ A real cg6 rom appears to just map the entire region with a
\ single entry
h# 0 h# 1000000 >cg6-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 cg6-dac
-1 value fb-addr
: dac! ( data reg# -- )
cg6-dac + l!
;
external
: color! ( r g b c# -- )
h# 18 << 0 dac! ( r g b )
swap rot ( b g r )
h# 18 << 4 dac! ( b g )
h# 18 << 4 dac! ( b )
h# 18 << 4 dac! ( )
;
headerless
\
\ Mapping
\
: dac-map
cg6-off-dac /cg6-off-dac do-map-in to cg6-dac
;
: fb-map
cg6-off-fb /cg6-off-fb do-map-in to fb-addr
;
: map-regs
dac-map fb-map
;
fload fbc_init.fth
\
\ Installation
\
" cgsix" device-name
" display" device-type
" RDOL,sbusfpga" model
: qemu-cg6-driver-install ( -- )
cg6-dac -1 = if
map-regs
map-in-fbc
init-fbc
\ Initial pallette taken from Sun's "Writing FCode Programs"
h# ff h# ff h# ff h# 0 color! \ Background white
h# 0 h# 0 h# 0 h# ff color! \ Foreground black
h# 64 h# 41 h# b4 h# 1 color! \ SUN-blue logo
fb-addr to frame-buffer-adr
default-font set-font
frame-buffer-adr encode-int " address" property
openbios-video-width openbios-video-height over char-width / over char-height /
fb8-install
['] cg6-blink-screen is blink-screen
['] cg6-reset-screen is reset-screen
['] cg6-draw-char is draw-character
['] cg6-toggle-cursor is toggle-cursor
['] cg6-invert-screen is invert-screen
['] cg6-insert-characters is insert-characters
['] cg6-delete-characters is delete-characters
['] fbc-erase-screen is erase-screen
['] fbc-delete-lines is delete-lines
['] fbc-insert-lines is insert-lines
then
;
: qemu-cg6-driver-init
cg6-reg
openbios-video-height encode-int " height" property
openbios-video-width encode-int " width" 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# 5 encode-int " monitor-sense" property
" RDOL" encode-string " manufacturer" property
" ISO8859-1" encode-string " character-set" property
h# c encode-int " cursorshift" property
h# SBUSFPGA_CG3_BUFSIZE encode-int " fbmapped" property
['] qemu-cg6-driver-install is-install
;
qemu-cg6-driver-init

View File

@@ -0,0 +1,344 @@
from migen import *
from migen.genlib.fifo import *
from litex.soc.interconnect.csr import *
from litex.soc.interconnect import wishbone
class CG6Accel(Module): # AutoCSR ?
def __init__(self, platform):
# for FBC and TEC - where we just ignore TEC
self.bus = bus = wishbone.Interface()
fbc_config = Signal(32, reset = (0x60000000)) # bit 11-12 are for resolution, see the GX manual
fbc_mode = Signal(32)
fbc_clip = Signal(32)
fbc_s = Signal(32)
#fbc_font = Signal(32)
fbc_x = Array(Signal(32) for a in range(0, 4))
fbc_y = Array(Signal(32) for a in range(0, 4))
fbc_offx = Signal(32)
fbc_offy = Signal(32)
fbc_incx = Signal(32)
fbc_incy = Signal(32)
fbc_clipminx = Signal(32)
fbc_clipminy = Signal(32)
fbc_clipmaxx = Signal(32)
fbc_clipmaxy = Signal(32)
fbc_fg = Signal(32)
fbc_bg = Signal(32)
fbc_alu = Signal(32)
fbc_arectx = Signal(32)
fbc_arecty = Signal(32)
# extra stuff for compatibility
fbc_arectx_prev = Signal(32) # after fbc_arecty (600) - R/O
fbc_arecty_prev = Signal(32) # after fbc_arectx_prev (601) - R/O
fbc_r5_cmd = Signal(32) # to communicate with Vex (602)
fbc_r5_status = Array(Signal(32) for a in range(0, 4))
fbc_next_font = Signal(32)
fbc_next_x0 = Signal(12)
fbc_next_x1 = Signal(12)
fbc_next_y0 = Signal(12)
fbc_do_draw = Signal()
fbc_do_blit = Signal()
font_layout = [
("font", 32),
("x0", 12),
("x1", 12),
("y0", 12),
]
# depth is because the current 'font' is a bit slow, so we need to buffer a lot...
self.submodules.fbc_fifo_font = SyncFIFOBuffered(width=layout_len(font_layout),depth=1024)
fbc_fifo_font_in = Record(font_layout)
fbc_fifo_font_out = Record(font_layout)
self.comb += [
self.fbc_fifo_font.din.eq(fbc_fifo_font_in.raw_bits()),
fbc_fifo_font_out.raw_bits().eq(self.fbc_fifo_font.dout)
]
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
Case(bus.adr[0:10], {
"default": [ ],
# 0: fbc_config R/O
1: [ NextValue(fbc_mode, bus.dat_w) ],
2: [ NextValue(fbc_clip, bus.dat_w) ],
# 3: <nothing>, pad2
4: [ NextValue(fbc_s, bus.dat_w) ], # 0x010
# 5: fbc_draw R/O
# 6: fbc_blit R/O
7: [ self.fbc_fifo_font.we.eq(1),
fbc_fifo_font_in.font.eq(bus.dat_w),
fbc_fifo_font_in.x0.eq(fbc_x[0][0:12]),
fbc_fifo_font_in.x1.eq(fbc_x[1][0:12]),
fbc_fifo_font_in.y0.eq(fbc_y[0][0:12]),
NextValue(fbc_x[0], fbc_x[0] + fbc_incx),
NextValue(fbc_x[1], fbc_x[1] + fbc_incx),
NextValue(fbc_y[0], fbc_y[0] + fbc_incy),
#NextValue(fbc_y[1], fbc_y[1] + fbc_incy),
],
# 8-31: <nothing>, pad3
32: [ NextValue(fbc_x[0], bus.dat_w) ],
33: [ NextValue(fbc_y[0], bus.dat_w) ],
#34: presumably fbc_z0
36: [ NextValue(fbc_x[1], bus.dat_w) ],
37: [ NextValue(fbc_y[1], bus.dat_w) ],
#38: presumably fbc_z1
40: [ NextValue(fbc_x[2], bus.dat_w) ],
41: [ NextValue(fbc_y[2], bus.dat_w) ],
#42: presumably fbc_z2
44: [ NextValue(fbc_x[3], bus.dat_w) ],
45: [ NextValue(fbc_y[3], bus.dat_w) ],
#46: presumably fbc_z3
48: [ NextValue(fbc_offx, bus.dat_w) ],
49: [ NextValue(fbc_offy, bus.dat_w) ],
52: [ NextValue(fbc_incx, bus.dat_w) ],
53: [ NextValue(fbc_incy, bus.dat_w) ],
# 54-55: pad81
56: [ NextValue(fbc_clipminx, bus.dat_w) ],
57: [ NextValue(fbc_clipminy, bus.dat_w) ],
# 58-59: pad9
60: [ NextValue(fbc_clipmaxx, bus.dat_w) ],
61: [ NextValue(fbc_clipmaxy, bus.dat_w) ],
# 62-63: pad10
64: [ NextValue(fbc_fg, bus.dat_w) ],
65: [ NextValue(fbc_bg, bus.dat_w) ],
66: [ NextValue(fbc_alu, bus.dat_w) ],
# 67: planemask reg
# 68: pixelmask reg
# 69-70: <nothing>
# 71: pattalign reg
# 72-79: pattern0-7
# 80-543: big empty space ?
# 544-546, 548-550: itri[abs,rel][xyz]
# 560-562, 564-566: iquad[abs,rel][xyz]
576: [ NextValue(fbc_arectx_prev, fbc_arectx), # 900
NextValue(fbc_arectx, bus.dat_w),
],
577: [ NextValue(fbc_arecty_prev, fbc_arecty),
NextValue(fbc_arecty, bus.dat_w),
],
# 578: fbc_arectz
# 579: <nothing>
# 580-582: fbc_relrect[xyz] -> update absolute
580: [ NextValue(fbc_arectx_prev, fbc_arectx),
NextValue(fbc_arectx, fbc_arectx + bus.dat_w),
],
581: [ NextValue(fbc_arecty_prev, fbc_arecty),
NextValue(fbc_arecty, fbc_arecty + bus.dat_w),
],
# 600-601: fbc_arect[xy]next, not directly writable
602: [ NextValue(fbc_r5_cmd, bus.dat_w) ],
604: [ NextValue(fbc_r5_status[0], bus.dat_w) ], # 0x970
605: [ NextValue(fbc_r5_status[1], bus.dat_w) ], # 0x971
606: [ NextValue(fbc_r5_status[2], bus.dat_w) ], # 0x972
607: [ NextValue(fbc_r5_status[3], bus.dat_w) ], # 0x973
# 608: fbc_next_font, R/O
}),
NextValue(bus.ack, 1),
).Elif(bus.cyc & bus.stb & ~bus.we & ~bus.ack, #read
Case(bus.adr[0:10], {
"default": [ NextValue(bus.dat_r, 0xDEADBEEF) ],
0: [ NextValue(bus.dat_r, fbc_config) ],
1: [ NextValue(bus.dat_r, fbc_mode) ],
2: [ NextValue(bus.dat_r, fbc_clip) ],
# 3: pad2
4: [ NextValue(bus.dat_r, fbc_s) ],
# 5: fbc_draw R/O -> start a "draw" on R
5: [ NextValue(fbc_do_draw, 1),
NextValue(bus.dat_r, 0)
],
# 6: fbc_blit R/O -> start a "blit" on R
6: [ NextValue(fbc_do_blit, 1),
NextValue(bus.dat_r, 0)
],
# 7: fbc_font W/O -> start a "font" on W
# 7: [ NextValue(bus.dat_r, fbc_font) ],
# 8-31: pad3
32: [ NextValue(bus.dat_r, fbc_x[0]) ], # 0x080
33: [ NextValue(bus.dat_r, fbc_y[0]) ],
36: [ NextValue(bus.dat_r, fbc_x[1]) ], # 0x090
37: [ NextValue(bus.dat_r, fbc_y[1]) ],
40: [ NextValue(bus.dat_r, fbc_x[2]) ], # 0x0a0
41: [ NextValue(bus.dat_r, fbc_y[2]) ],
44: [ NextValue(bus.dat_r, fbc_x[3]) ], # 0x0b0
45: [ NextValue(bus.dat_r, fbc_y[3]) ], # 0x0b4
48: [ NextValue(bus.dat_r, fbc_offx) ],
49: [ NextValue(bus.dat_r, fbc_offy) ],
52: [ NextValue(bus.dat_r, fbc_incx) ], # 0x0d0
53: [ NextValue(bus.dat_r, fbc_incy) ],
# 54-55: pad81
56: [ NextValue(bus.dat_r, fbc_clipminx) ],
57: [ NextValue(bus.dat_r, fbc_clipminy) ],
# 58-59: pad9
60: [ NextValue(bus.dat_r, fbc_clipmaxx) ],
61: [ NextValue(bus.dat_r, fbc_clipmaxy) ],
# 62-63: pad10
64: [ NextValue(bus.dat_r, fbc_fg) ], # 0x100
65: [ NextValue(bus.dat_r, fbc_bg) ], # 0x104
66: [ NextValue(bus.dat_r, fbc_alu) ],
576: [ NextValue(bus.dat_r, fbc_arectx),
],
577: [ NextValue(bus.dat_r, fbc_arecty),
],
600: [ NextValue(bus.dat_r, fbc_arectx_prev), # 0x960
],
601: [ NextValue(bus.dat_r, fbc_arecty_prev),
],
602: [ NextValue(bus.dat_r, fbc_r5_cmd), # 0x968
],
# 603
604: [ NextValue(bus.dat_r, fbc_r5_status[0]), # 0x970
],
605: [ NextValue(bus.dat_r, fbc_r5_status[1]), # 0x971
],
606: [ NextValue(bus.dat_r, fbc_r5_status[2]), # 0x972
],
607: [ NextValue(bus.dat_r, fbc_r5_status[3]), # 0x973
],
608: [ NextValue(bus.dat_r, fbc_next_font),
],
609: [ NextValue(bus.dat_r, Cat(fbc_next_x0, Signal(20, reset = 0))),
],
610: [ NextValue(bus.dat_r, Cat(fbc_next_x1, Signal(20, reset = 0))),
],
611: [ NextValue(bus.dat_r, Cat(fbc_next_y0, Signal(20, reset = 0))),
],
}),
NextValue(bus.ack, 1),
).Else(
NextValue(bus.ack, 0),
)
)
# also in blit.c, for r5-cmd
FUN_MASK = 0x0000000F
FUN_DRAW = 0x00000001
FUN_BLIT = 0x00000002
FUN_FONT = 0x40000004 # include FUN_FONT_NEXT_RDY_BIT
FUN_DONE_BIT = 31
FUN_FONT_NEXT_RDY_BIT = 30
FUN_FONT_NEXT_REQ_BIT = 29
FUN_FONT_NEXT_DONE_BIT = 28
# for GX global status register
#GX_FULL_BIT = 29
GX_INPROGRESS_BIT = 28
# to hold the Vex in reset
# could be sent to fbc_s[GX_INPROGRESS_BIT] ?
local_reset = Signal(reset = 1)
#timeout_rst = 0xFFFFFFF
#timeout = Signal(28, reset = timeout_rst)
#pad_SBUS_DATA_OE_LED = platform.request("SBUS_DATA_OE_LED")
#self.comb += pad_SBUS_DATA_OE_LED.eq(~local_reset);
self.sync += [
self.fbc_fifo_font.re.eq(0),
If(fbc_r5_cmd[FUN_DONE_BIT],
fbc_r5_cmd.eq(0),
fbc_s[GX_INPROGRESS_BIT].eq(0),
#fbc_s[GX_FULL_BIT].eq(0),
local_reset.eq(1),
#timeout.eq(timeout_rst),
).Elif(self.fbc_fifo_font.readable & fbc_s[GX_INPROGRESS_BIT] & fbc_r5_cmd[FUN_FONT_NEXT_REQ_BIT] & (fbc_r5_cmd[0:4] == 0x4),
# the font code request the next line, and one is available: give it
self.fbc_fifo_font.re.eq(1),
fbc_next_font.eq(fbc_fifo_font_out.font),
fbc_next_x0.eq(fbc_fifo_font_out.x0),
fbc_next_x1.eq(fbc_fifo_font_out.x1),
fbc_next_y0.eq(fbc_fifo_font_out.y0),
fbc_r5_cmd[FUN_FONT_NEXT_REQ_BIT].eq(0),
fbc_r5_cmd[FUN_FONT_NEXT_RDY_BIT].eq(1),
#timeout.eq(timeout_rst),
).Elif(~self.fbc_fifo_font.readable & fbc_s[GX_INPROGRESS_BIT] & fbc_r5_cmd[FUN_FONT_NEXT_REQ_BIT] & (fbc_r5_cmd[0:4] == 0x4),
# the font code request the next line, but none is available; stop
fbc_r5_cmd[FUN_FONT_NEXT_REQ_BIT].eq(0),
fbc_r5_cmd[FUN_FONT_NEXT_DONE_BIT].eq(1),
#timeout.eq(timeout_rst),
).Elif(self.fbc_fifo_font.readable & ~fbc_s[GX_INPROGRESS_BIT],
self.fbc_fifo_font.re.eq(1),
fbc_next_font.eq(fbc_fifo_font_out.font),
fbc_next_x0.eq(fbc_fifo_font_out.x0),
fbc_next_x1.eq(fbc_fifo_font_out.x1),
fbc_next_y0.eq(fbc_fifo_font_out.y0),
fbc_r5_cmd.eq(FUN_FONT), # includes FUN_FONT_NEXT_RDY_BIT
fbc_s[GX_INPROGRESS_BIT].eq(1),
#fbc_s[GX_FULL_BIT].eq(1),
local_reset.eq(0),
#timeout.eq(timeout_rst),
).Elif(fbc_do_draw & ~fbc_s[GX_INPROGRESS_BIT],
fbc_do_draw.eq(0),
fbc_r5_cmd.eq(FUN_DRAW),
fbc_s[GX_INPROGRESS_BIT].eq(1),
#fbc_s[GX_FULL_BIT].eq(1),
local_reset.eq(0),
#timeout.eq(timeout_rst),
).Elif(fbc_do_blit & ~fbc_s[GX_INPROGRESS_BIT],
fbc_do_blit.eq(0),
fbc_r5_cmd.eq(FUN_BLIT),
fbc_s[GX_INPROGRESS_BIT].eq(1),
#fbc_s[GX_FULL_BIT].eq(1),
local_reset.eq(0),
#timeout.eq(timeout_rst),
)
#).Elif((timeout == 0) & fbc_s[GX_INPROGRESS_BIT], # OUPS
# fbc_r5_cmd.eq(0),
# fbc_s[GX_INPROGRESS_BIT].eq(0),
# #fbc_s[GX_FULL_BIT].eq(0),
# local_reset.eq(1),
# timeout.eq(timeout_rst),
#),
#If(fbc_s[GX_INPROGRESS_BIT] & (timeout != 0),
# timeout.eq(timeout - 1)
#)
]
self.ibus = ibus = wishbone.Interface()
self.dbus = dbus = wishbone.Interface()
vex_reset = Signal()
self.comb += vex_reset.eq(ResetSignal("sys") | local_reset)
self.specials += Instance(self.get_netlist_name(),
i_clk = ClockSignal("sys"),
i_reset = vex_reset,
o_iBusWishbone_CYC = ibus.cyc,
o_iBusWishbone_STB = ibus.stb,
i_iBusWishbone_ACK = ibus.ack,
o_iBusWishbone_WE = ibus.we,
o_iBusWishbone_ADR = ibus.adr,
i_iBusWishbone_DAT_MISO = ibus.dat_r,
o_iBusWishbone_DAT_MOSI = ibus.dat_w,
o_iBusWishbone_SEL = ibus.sel,
i_iBusWishbone_ERR = ibus.err,
o_iBusWishbone_CTI = ibus.cti,
o_iBusWishbone_BTE = ibus.bte,
o_dBusWishbone_CYC = dbus.cyc,
o_dBusWishbone_STB = dbus.stb,
i_dBusWishbone_ACK = dbus.ack,
o_dBusWishbone_WE = dbus.we,
o_dBusWishbone_ADR = dbus.adr,
i_dBusWishbone_DAT_MISO = dbus.dat_r,
o_dBusWishbone_DAT_MOSI = dbus.dat_w,
o_dBusWishbone_SEL = dbus.sel,
i_dBusWishbone_ERR = dbus.err,
o_dBusWishbone_CTI = dbus.cti,
o_dBusWishbone_BTE = dbus.bte,)
self.add_sources(platform)
def get_netlist_name(self):
return "VexRiscv"
def add_sources(self, platform):
platform.add_source("/home/dolbeau/SBusFPGA/sbus-to-ztex-gateware-migen/VexRiscv_FbAccel.v", "verilog")

View File

@@ -0,0 +1,191 @@
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;
# 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
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_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))
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], hwcursor=True)
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"CG6: 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"CG6: using {hres} x {vres}, {freq/1e6} MHz pixclk")
vfb = cg3_fb.VideoFrameBuffer256c(dram_port = soc.sdram.crossbar.get_port(),
upd_clut_fifo = upd_cmap_fifo,
hres = hres,
vres = vres,
base = base,
clock_domain = clock_domain,
clock_faster_than_sys = (vtg.video_timings["pix_clk"] > soc.sys_clk_freq),
hwcursor = True,
upd_overlay_fifo = upd_overlay_fifo,
upd_omap_fifo = upd_omap_fifo)
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)
# cg6 ramdac registers - same as cg3, but used a bit differently...
# struct bt_regs {
# u_int bt_addr; /* map address register */
# u_int bt_cmap; /* colormap data register */
# u_int bt_ctrl; /* control register */
# u_int bt_omap; /* overlay (cursor) map register */
# };
# for BT
self.bus = bus = wishbone.Interface()
bt_addr = Signal(8)
bt_cmap_state = Signal(2)
# the CG6 takes 32 bits write but only use the top 8 bits, for bt_addr & bt_cmap
# alto it uses the BT HW cursor (though probably not in the console?)
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 & upd_cmap_fifo.writable, #write
# FIXME: should check for prefix?
Case(bus.adr[0:3], {
# bt_addr
0: [ NextValue(bt_addr, bus.dat_w[24:32]),
NextValue(bt_cmap_state, 0),
],
# 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])),
Case(bt_cmap_state, {
0: [ NextValue(bt_cmap_state, 1), ],
1: [ NextValue(bt_cmap_state, 2), ],
2: [ NextValue(bt_cmap_state, 0), NextValue(bt_addr, (bt_addr+1) & 0xFF), ],
"default": NextValue(bt_cmap_state, 0),
}),
],
# bt_ctrl
# NetBSD driver adds 0x03<<24 to enable the cursor
2: [],
# 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])),
Case(bt_cmap_state, {
0: [ NextValue(bt_cmap_state, 1), ],
1: [ NextValue(bt_cmap_state, 2), ],
2: [ NextValue(bt_cmap_state, 0), NextValue(bt_addr, (bt_addr+1) & 0xFF), ],
"default": NextValue(bt_cmap_state, 0),
}),
],
"default": [],
}),
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)],
"default": [],
}),
NextValue(bus.ack, 1),
).Else(
NextValue(bus.ack, 0),
)
)
# for FHC/THC
# fhc @ 0x300000
# thc @ 0x301000
# thc_cursxy # 0x8fc from THC
# thc_cursmask[32] @ 0x900 from THC
# thc_cursbits[32] @ 0x980 from THC
hwcursor_x = Signal(12)
hwcursor_y = Signal(12)
self.comb += vtg.hwcursor_x.eq(hwcursor_x)
self.comb += vtg.hwcursor_y.eq(hwcursor_y)
pad_SBUS_DATA_OE_LED = soc.platform.request("SBUS_DATA_OE_LED")
self.comb += pad_SBUS_DATA_OE_LED.eq((hwcursor_x < 1280) & (hwcursor_y < 1024));
self.bus2 = bus2 = wishbone.Interface()
self.submodules.wishbone_fsm2 = wishbone_fsm2 = FSM(reset_state = "Reset")
wishbone_fsm2.act("Reset",
NextValue(bus2.ack, 0),
NextState("Idle"))
wishbone_fsm2.act("Idle",
If(bus2.cyc & bus2.stb & bus2.we & ~bus2.ack, #write
Case(bus2.adr[0:11], {
"default": [ ],
1599: [ NextValue(hwcursor_x, bus2.dat_w[16:28]),
NextValue(hwcursor_y, bus2.dat_w[ 0:12]),
],
}),
Case(bus2.adr[5:11], {
"default": [ ],
50 : [ upd_overlay_fifo.we.eq(1), # 50*32 = 1600..1631
upd_overlay_fifo.din.eq(Cat(Signal(1, reset = 0), 31-bus2.adr[0:5], bus2.dat_w))
],
51 : [ upd_overlay_fifo.we.eq(1), # 51*32 = 1632..1663
upd_overlay_fifo.din.eq(Cat(Signal(1, reset = 1), 31-bus2.adr[0:5], bus2.dat_w))
],
}),
NextValue(bus2.ack, 1),
).Elif(bus2.cyc & bus2.stb & ~bus2.we & ~bus2.ack, #read
Case(bus2.adr[0:10], {
"default": [ NextValue(bus2.dat_r, 0xDEADBEEF) ],
0: [ NextValue(bus2.dat_r, 0x60500000) ], # claim revision 5
}),
NextValue(bus2.ack, 1),
).Else(
NextValue(bus2.ack, 0),
)
)

View File

@@ -0,0 +1,24 @@
: cg6_vid_fb_vtg_enable_rd ( -- csr_value)
cg6-virt h# 0000 + l@
;
: cg6_vid_fb_dma_enable_rd ( -- csr_value)
cg6-virt h# 002c + l@
;
: cg6_vid_fb_vtg_enable_wr ( value -- )
cg6-virt h# 0000 + l!
;
: cg6_vid_fb_dma_enable_wr ( value -- )
cg6-virt h# 002c + l!
;
: cg6_init!
map-in-cg6extraregs
0 cg6_vid_fb_vtg_enable_wr
0 cg6_vid_fb_dma_enable_wr
1 cg6_vid_fb_vtg_enable_wr
1 cg6_vid_fb_dma_enable_wr
map-out-cg6extraregs
;

View File

@@ -0,0 +1,425 @@
-1 instance value fbc-virt
: map-in-fbc ( -- ) my-sbus-address sbusfpga_regionaddr_cg6_fbc + my-sbus-space h# 2000 map-in is fbc-virt ;
: map-out-fbc ( -- ) fbc-virt h# 2000 map-out ;
: fbc! ( val off -- )
fbc-virt + l!
;
: fbc@ ( off -- val )
fbc-virt + l@
;
\ a.k.a. 'rasterops'
: fbc_alu! ( val -- )
h# 108 fbc!
;
\ a.k.a. 'misc'
: fbc_mode! ( val -- )
h# 4 fbc!
;
: fbc_clip! ( val -- )
h# 8 fbc!
;
: fbc_offx! ( val -- )
h# c0 fbc!
;
: fbc_offy! ( val -- )
h# c4 fbc!
;
: fbc_x0! ( val -- )
h# 80 fbc!
;
: fbc_y0! ( val -- )
h# 84 fbc!
;
: fbc_x1! ( val -- )
h# 90 fbc!
;
: fbc_y1! ( val -- )
h# 94 fbc!
;
: fbc_x2! ( val -- )
h# a0 fbc!
;
: fbc_y2! ( val -- )
h# a4 fbc!
;
: fbc_x3! ( val -- )
h# b0 fbc!
;
: fbc_y3! ( val -- )
h# b4 fbc!
;
: fbc_incx! ( val -- )
h# d0 fbc!
;
: fbc_incy! ( val -- )
h# d4 fbc!
;
: fbc_clipminx! ( val -- )
h# e0 fbc!
;
: fbc_clipminy! ( val -- )
h# e4 fbc!
;
: fbc_clipmaxx! ( val -- )
h# f0 fbc!
;
: fbc_clipmaxy! ( val -- )
h# f4 fbc!
;
: fbc_fg! ( val -- )
h# 100 fbc!
;
: fbc_bg! ( val -- )
h# 104 fbc!
;
: fbc_arectx! ( val --)
h# 900 fbc!
;
: fbc_arecty! ( val --)
h# 904 fbc!
;
: fbc_s@ ( -- val )
h# 10 fbc@
;
: fbc_draw@ ( -- val )
h# 14 fbc@
;
: fbc_blit@ ( -- val )
h# 18 fbc@
;
h# ff constant fground-color
h# 00 constant bground-color
: init-fbc
h# 0 fbc_clip!
h# 0 fbc_offx!
h# 0 fbc_offy!
h# 0 fbc_incx!
h# 0 fbc_incy!
h# 0 fbc_clipminx!
h# 0 fbc_clipmaxy!
openbios-video-width 1 - fbc_clipmaxx!
openbios-video-height 1 - fbc_clipmaxy!
h# ff fbc_fg!
h# 0 fbc_bg!
\ a9806c60 = 1010_1001__1000_0000__0110_1100__0110_0000
\ from the doc:
\ 31-30 Override Plane Mask Select
\ (OO=Ignore, Ol=Use zeroes, 10=Use ones, ll=Use PLANEMASK)
\ 29-28 Override Pixel Mask Select
\ (OO=Ignore, 01-Use zeroes, 10=Use ones, ll=Use PIXELMASK)
\ 27-26 Override Pattern Select
\ (OO=Ignore, Ol=Use zeroes, 10=Use ones, ll=Use PATTERN)
\ 25-24 Polygon Draw Select
\ (OO=Ignore, 01=0verlapping, lO=Nonoverlapping, Il=Illegal)
\ 23-22 UNSUPPORTED-ATTR
\ (OO=Ignore, Ol=Unsupported, lO=Supported, ll=Illegal)
\ 17 Rasterop Mode (()=BOOLEAN, l=LINEAR)
\ 16 Plot/Unplot Mode (O=PLOT, l=UNPLOT)
\ 15-12 Rasterop used when FCOLOR[p]=l and BCOLOR[pl=l
\ 11-8 Rasterop used when FCOLOR[p]=l and BCOLOR[pl=O
\ 7-4 Rasterop used when FCOLOR[p]=O and BCOLOR[pl=l
\ 3-0 Rasterop used when FCOLOR[p]=O and BCOLOR[p]=O
\
\ so: => all 3 override are 'use 1'
\ polygon draw => overlapping
\ unsup attr => supported
\ rop mode => boolean
\ plot/unplot => plot
\ rops => four groups of <whatever> (still don't understand it)
h# a9806c60 fbc_alu!
\ ff for planemask (unimp)
\ ffffffff for pixelmask (unimp)
\ 0 for patalign (unimp)
\ ffffffff for pattern0-7 (unimp)
\ 229540 = 0000_0000__0010_0010__1001_0101__0100_0000
\ from the doc:
\ 31-22 0000_0000_00
\ 21-20 BLIT-SRC-CHK
\ (OO=ignore, 01-Exclude Src, lO=Include Src, ll=Illegal)
\ 19 VBLANK OCCURED (l=VBLANK has occurred)
\ 18-17 Anti-Aliasing/Color Mode Select
\ (00=ignore, Ol=COLOR8, lO=COLORl, ll=HRMONO)
\ 16-15 Render/Pick Mode Select
\ (OO=ignore, Ol=RENDER, 10=PICK, 11-Illegal)
\ 14-13 Buffer 0 Write Enable
\ (OO=ignore, Ol=Enable, lO=Disable, ll=Illegal)
\ 12-11 Buffer 1 Write Enable
\ (00-ignore, Ol=Enable, lO-Disable, ll=Illegal)
\ 10-9 Buffer Read Enable
\ (OO=ignore, 01-Read from BufferO, lO=Read Bufferl, ll=Illegal)
\ 8-7 Buffer Display Enable
\ (OO=ignore, Ol=Display BufferO, lO=Display Bufferl, ll=Illegal)
\ 6 Modify Address INDEX (l=Modify Address Index)
\ 5-4 Address INDEX
\ 3-0 0000
\
\ so: BLIT-SRC-CHECK => include src
\ VBLANK => no (guessig this is RO?)
\ aa/color: => COLOR8
\ render/pick => render
\ buf 0 wr ena => ignore
\ buf 1 wr ena => disable
\ buf read ena => buffer 1
\ buf dis ena => buffer 1
\ mod. addr inx => 1 (always)
\ addr idx => 0
h# 229540 fbc_mode!
;
\ this reads 'draw' until no longer full
\ (we're never full..)
: fbc-draw-wait ( -- )
begin
fbc_draw@
h# 20000000
and
0=
until
;
\ this reads 'blit' until no longer full
\ (we're never full..)
: fbc-blit-wait ( -- )
begin
fbc_blit@
h# 20000000
and
0=
until
;
\ busy-wait on PROGRESS in 's(tatus)'
: fbc-busy-wait ( -- )
begin
fbc_s@
h# 10000000
and
0=
until
;
\ convert char pos to pixel pos
: >pixel ( cx cy -- px py )
swap
char-width
*
window-left
+
swap
char-height
*
window-top
+
;
: fbc-rect-fill ( x0 y0 x1 y1 fg_color -- )
fbc-busy-wait
fbc_fg!
\ fix the registers to what we currently expect
h# a980ff00 fbc_alu!
h# 00220000 fbc_mode!
\ we start with x0/y0
2swap
fbc_arecty!
fbc_arectx!
fbc_arecty!
fbc_arectx!
fbc-draw-wait
fbc-busy-wait
\ reset fg_color
fground-color fbc_fg!
;
: fbc-blit ( cx0 cy0 cx1 cy1 cx2 cy2 cx3 cy3 -- )
fbc-busy-wait
\ fix the registers to what we currently expect
h# a980cccc fbc_alu!
h# 00220000 fbc_mode!
>pixel
1
-
fbc_y3!
1
-
fbc_x3!
>pixel
fbc_y2!
fbc_x2!
>pixel
1
-
fbc_y1!
1
-
fbc_x1!
>pixel
fbc_y0!
fbc_x0!
fbc-blit-wait
fbc-busy-wait
;
\ fill a rectangle of char with background-color
: fbc-char-fill ( cw0 ch0 cw1 ch1 -- )
2swap
>pixel
2swap
>pixel
bground-color
fbc-rect-fill
;
: fbc-erase-screen ( -- )
\ x0
0
\ y0
0
\ x1
openbios-video-width 1 -
\ y1
openbios-video-height 1 -
\ fg_col
bground-color
fbc-rect-fill
;
: fbc-delete-lines ( n -- )
\ check if we move the whole screen
dup #lines < if
>r
0
line#
r@
+
#columns
#lines
0
line#
#columns
#lines
r@
-
line#
\ check if there's some lines at the bottom to blit
r@ + #lines < if
fbc-blit
else
2drop
2drop
2drop
2drop
then
0
#lines
r>
-
#columns
#lines
fbc-char-fill
else
0
swap
#lines
swap
-
#columns
#lines
fbc-char-fill
then
;
: fbc-insert-lines ( n -- )
dup #lines < if
>r
0
line#
#columns
#lines
r@
-
0
line#
r@
+
#columns
#lines
fbc-blit
0
line#
#columns
line#
r>
+
fbc-char-fill
else
0
swap
line#
swap
#columns
swap
line#
swap
+
fbc-char-fill
then
;
\ unaccelerated placeholders, we need to wait before drawing
: cg6-blink-screen
\ FIXME
;
: cg6-reset-screen
\ FIXME
;
: cg6-draw-char
fbc-busy-wait
fb8-draw-character
;
: cg6-toggle-cursor
fbc-busy-wait
fb8-toggle-cursor
;
: cg6-invert-screen
fbc-busy-wait
fb8-invert-screen
;
: cg6-erase-screen
fbc-busy-wait
fb8-erase-screen
;
: cg6-insert-characters
fbc-busy-wait
fb8-insert-characters
;
: cg6-delete-characters
fbc-busy-wait
fb8-delete-characters
;
: cg6-delete-lines
fbc-busy-wait
fb8-delete-lines
;
: cg6-insert-lines
fbc-busy-wait
fb8-insert-lines
;

View File

@@ -31,7 +31,12 @@ USBOHCI_ADDR_PFX = Signal(12, reset = 0x008)
SRAM_ADDR_PFX = Signal(12, reset = 0x009) # unmapped ; LE
ENGINE_ADDR_PFXA = Signal(12, reset = 0x00a)
ENGINE_ADDR_PFXB = Signal(12, reset = 0x00b)
CG3_REGISTERS_ADDR_PFX = Signal(12, reset = 0x040)
CG6_BT_ADDR_PFX = Signal(12, reset = 0x020)
CG6_FHC_ADDR_PFX = Signal(12, reset = 0x030)
CG3_BT_ADDR_PFX = Signal(12, reset = 0x040)
FBC_ROM_ADDR_PFX = Signal(12, reset = 0x041)
#FBC_RAM_ADDR_PFX = Signal(12, reset = 0x042)
CG6_FBC_ADDR_PFX = Signal(12, reset = 0x070)
ADDR_BIGPFX_HIGH = ADDR_PHYS_HIGH
ADDR_BIGPFX_LOW = 20 ## 1 MiB per bigprefix
@@ -464,11 +469,15 @@ class SBusFPGABus(Module):
NextState("Slave_Error")
).Elif(((SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == ROM_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == WISHBONE_CSR_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == FBC_ROM_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG6_FBC_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == USBOHCI_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == SRAM_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == ENGINE_ADDR_PFXA) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == ENGINE_ADDR_PFXB) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_REGISTERS_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG6_BT_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG6_FHC_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_BT_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR_BIGPFX) |
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR2_BIGPFX)),
NextValue(SBUS_3V3_ACKs_o, ACK_IDLE), # need to wait for data, don't ACK yet
@@ -532,7 +541,7 @@ class SBusFPGABus(Module):
NextValue(sbus_oe_master_in, 1),
If(((SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == ROM_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == SRAM_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_REGISTERS_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_BT_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR_BIGPFX) |
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR2_BIGPFX)),
NextValue(SBUS_3V3_ACKs_o, ACK_IDLE), # need to wait for data, don't ACK yet
@@ -602,7 +611,7 @@ class SBusFPGABus(Module):
NextState("Slave_Error")
).Elif(((SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == ROM_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == SRAM_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_REGISTERS_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_BT_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR_BIGPFX) |
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR2_BIGPFX)),
NextValue(SBUS_3V3_ACKs_o, ACK_IDLE), # need to wait for data, don't ACK yet
@@ -679,11 +688,15 @@ class SBusFPGABus(Module):
NextValue(stat_slave_early_error_counter, stat_slave_early_error_counter + 1),
NextState("Slave_Error")
).Elif(((SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == WISHBONE_CSR_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == FBC_ROM_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG6_FBC_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == USBOHCI_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == SRAM_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == ENGINE_ADDR_PFXA) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == ENGINE_ADDR_PFXB) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_REGISTERS_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG6_BT_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG6_FHC_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_BT_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR_BIGPFX) |
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR2_BIGPFX)),
NextValue(sbus_wishbone_le,
@@ -729,7 +742,7 @@ class SBusFPGABus(Module):
(SBUS_3V3_PPRD_i == 0)),
NextValue(sbus_oe_master_in, 1),
If(((SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == SRAM_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_REGISTERS_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_BT_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR_BIGPFX) |
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR2_BIGPFX)),
NextValue(sbus_wishbone_le,
@@ -781,7 +794,7 @@ class SBusFPGABus(Module):
NextValue(stat_slave_early_error_counter, stat_slave_early_error_counter + 1),
NextState("Slave_Error")
).Elif(((SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == SRAM_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_REGISTERS_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_PFX_LOW:ADDR_PFX_LOW+ADDR_PFX_LENGTH] == CG3_BT_ADDR_PFX) |
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR_BIGPFX) |
(SBUS_3V3_PA_i[ADDR_BIGPFX_LOW:ADDR_BIGPFX_LOW+ADDR_BIGPFX_LENGTH] == CG3_PIXELS_ADDR2_BIGPFX)),
NextValue(sbus_wishbone_le,

View File

@@ -7,6 +7,7 @@ from sysconfig import get_platform
from migen import *
import cg3_fb
import cg6_fb
def get_header_map_stuff(gname, name, size, type="csr", reg=True):
@@ -75,6 +76,7 @@ def get_prom(soc,
engine=False,
i2c=False,
cg3=False,
cg6=False,
cg3_res=None):
r = "fcode-version2\nfload prom_csr_{}.fth\n".format(version.replace(".", "_"))
@@ -97,7 +99,7 @@ def get_prom(soc,
r += " map-out-trng\n"
r += ";\n"
r += "disabletrng!\n"
if (usb or sdram or engine or i2c or cg3):
if (usb or sdram or engine or i2c or cg3 or cg6):
r += "finish-device\nnew-device\n"
if (usb):
@@ -117,14 +119,14 @@ def get_prom(soc,
r += " map-out-usb_host_ctrl\n"
r += ";\n"
r += "my-reset!\n"
if (sdram or engine or i2c or cg3):
if (sdram or engine or i2c or cg3 or cg6):
r += "finish-device\nnew-device\n"
if (sdram):
r += "\" RDOL,sdram\" device-name\n"
r += get_header_map3_stuff("mregs", "ddrphy", "sdram", "exchange_with_mem", 4096, 4096, 4096)
r += "fload sdram_init.fth\ninit!\n"
if (engine or i2c or cg3):
if (engine or i2c or cg3 or cg6):
r += "finish-device\nnew-device\n"
if (engine):
@@ -132,21 +134,24 @@ 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_map3_stuff("curve25519engine", "curve25519engine-regs", "curve25519engine-microcode", "curve25519engine-regfile", 4096, 4096, 65536, type2="region", type3="region")
if (i2c or cg3):
if (i2c or cg3 or cg6):
r += "finish-device\nnew-device\n"
if (i2c):
r += "\" RDOL,i2c\" device-name\n"
r += get_header_map_stuff("i2c", "i2c", 64)
if (cg3):
if (cg3 or cg6):
r += "finish-device\nnew-device\n"
if (cg3):
if (cg3 or cg6):
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", "")
cg3_file = open("cg3.fth")
if (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)
for line in cg3_lines:
@@ -154,10 +159,13 @@ def get_prom(soc,
#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"
r += get_header_map_stuff("cg3extraregs", "cg3", 4096, reg=False)
r += "fload cg3_init.fth\ncg3_init!\n"
if (cg3):
r += get_header_map_stuff("cg3extraregs", "cg3", 4096, reg=False)
r += "fload cg3_init.fth\ncg3_init!\n"
if (cg6):
r += get_header_map_stuff("cg6extraregs", "cg6", 4096, reg=False)
r += "fload cg6_init.fth\ncg6_init!\n"
r += "end0\n"

View File

@@ -37,6 +37,8 @@ import sbus_to_fpga_prom;
from litex.soc.cores.video import VideoVGAPHY
import cg3_fb;
import cg6_fb;
import cg6_accel;
#import cgtrois;
# CRG ----------------------------------------------------------------------------------------------
@@ -209,7 +211,7 @@ class SBusFPGA(SoCCore):
#if self.irq.enabled:
#self.irq.add(name, use_loc_if_exists=True)
def __init__(self, version, sys_clk_freq, usb, sdram, engine, i2c, cg3, cg3_res, **kwargs):
def __init__(self, version, sys_clk_freq, usb, sdram, engine, i2c, cg3, cg6, cg3_res, **kwargs):
print(f"Building SBusFPGA for board version {version}")
kwargs["cpu_type"] = "None"
@@ -221,14 +223,14 @@ class SBusFPGA(SoCCore):
self.platform = platform = ztex213_sbus.Platform(variant="ztex2.13a", version = version)
if (cg3 and (version == "V1.2")):
if ((cg3 or cg6) and (version == "V1.2")):
platform.add_extension(ztex213_sbus._vga_pmod_io_v1_2)
if (cg3):
if (cg3 or cg6):
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)
print(f"Reserving {cg3_fb_size} bytes ({cg3_fb_size//1048576} MiB) for the CG3")
print(f"Reserving {cg3_fb_size} bytes ({cg3_fb_size//1048576} MiB) for the CG3/CG6")
else:
hres = 0
vres = 0
@@ -252,22 +254,27 @@ class SBusFPGA(SoCCore):
# the virtual address space used by NetBSD DMA allocators
# (themselves constrained by the SBus MMU capabilities)
self.wb_mem_map = wb_mem_map = {
"prom": 0x00000000, # 256 Kib ought to be enough for anybody (we're using < 2.5 Kib now...)
"prom": 0x00000000, # 256 Kib ought to be enough for anybody (we're using < 8 Kib now...)
"csr" : 0x00040000,
"usb_host": 0x00080000, # OHCI registers are here, not in CSR
#"usb_shared_mem": 0x00090000, # unused ATM
"curve25519engine": 0x000a0000, # includes microcode (4 KiB@0) and registers (16 KiB @ 64 KiB)
"cg3_registers": 0x00400000, # required for compatibility
"fb_accel_rom": 0x00410000,
"fb_accel_ram": 0x00420000,
#"cg6_fbc": 0x00700000, # required for compatibility
"cg3_pixels": 0x00800000, # required for compatibility, 1-2 MiB for now (2nd MiB is 0x00900000)
"cg6_bt": 0x00200000, # required for compatibility, bt_regs for cg6
#"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
"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 MiB for now (2nd MiB is 0x00900000) (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, # FIXME
"usb_fake_dma": 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, sdram=sdram, engine=engine, cg3=cg3, 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, sdram=sdram, engine=engine, cg3=(cg3 or cg6), 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
@@ -319,7 +326,7 @@ class SBusFPGA(SoCCore):
#for i in range(len(prom)):
# print(hex(prom[i]))
#print("\n****************************************\n")
self.add_ram("prom", origin=self.mem_map["prom"], size=2**16, contents=prom_data, mode="r")
self.add_ram("prom", origin=self.mem_map["prom"], size=2**14, contents=prom_data, mode="r") ### FIXME: round up the prom_data size & check for <= 2**16!
#getattr(self,"prom").mem.init = prom_data
#getattr(self,"prom").mem.depth = 2**14
@@ -337,7 +344,7 @@ class SBusFPGA(SoCCore):
else:
avail_sdram = 0
if (cg3):
if (cg3 or cg6):
if (avail_sdram >= cg3_fb_size):
avail_sdram = avail_sdram - cg3_fb_size
else:
@@ -435,19 +442,26 @@ class SBusFPGA(SoCCore):
if (i2c):
self.submodules.i2c = i2c.RTLI2C(platform, pads=platform.request("i2c"))
if (cg3):
if (cg3 or cg6):
self.submodules.videophy = VideoVGAPHY(platform.request("vga"), clock_domain="vga")
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_registers", self.cg3.bus, SoCRegion(origin=self.mem_map.get("cg3_registers", None), size=0x1000, cached=False))
##self.submodules.cgtrois = ClockDomainsRenamer({"eng_clk":"clk50", "rf_clk":"clk200", "mul_clk":"clk100_gated"})(cgtrois.CGTrois(platform=platform,prefix=self.mem_map.get("curve25519engine", None), hres=hres, vres=vres, base=(self.wb_mem_map["main_ram"] + avail_sdram)))
##self.add_video_framebuffer(phy=self.videophy, timings=cg3_res, clock_domain="vga")
pad_SBUS_DATA_OE_LED = platform.request("SBUS_DATA_OE_LED")
#self.comb += pad_SBUS_DATA_OE_LED.eq(~self.cg3.video_framebuffer.dma.source.valid)
#self.comb += pad_SBUS_DATA_OE_LED.eq(~self.cg3.video_framebuffer.conv.source.valid)
#self.comb += pad_SBUS_DATA_OE_LED.eq(~self.cg3.video_framebuffer.cdc.source.valid)
self.comb += pad_SBUS_DATA_OE_LED.eq(~self.cg3.video_framebuffer_vtg.source.valid)
#self.comb += pad_SBUS_DATA_OE_LED.eq(self.cg3.video_framebuffer.underflow)
##self.comb += pad_SBUS_DATA_OE_LED.eq(self.video_framebuffer.underflow)
if (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(self.platform)
self.bus.add_slave("cg6_fbc", self.cg6_accel.bus, SoCRegion(origin=self.mem_map.get("cg6_fbc", None), size=0x2000, cached=False))
self.bus.add_slave("cg6_fhc", self.cg6.bus2, SoCRegion(origin=self.mem_map.get("cg6_fhc", None), size=0x2000, cached=False))
self.bus.add_master(name="cg6_accel_r5_i", master=self.cg6_accel.ibus)
self.bus.add_master(name="cg6_accel_r5_d", master=self.cg6_accel.dbus)
cg6_rom_file = "blit.raw"
cg6_rom_data = soc_core.get_mem_data(cg6_rom_file, "little")
self.add_ram("cg6_accel_rom", origin=self.mem_map["cg6_accel_rom"], size=2**12, contents=cg6_rom_data, mode="r")
self.add_ram("cg6_accel_ram", origin=self.mem_map["cg6_accel_ram"], size=2**12, mode="rw")
print("IRQ to Device map:\n")
print(platform.irq_device_map)
@@ -474,7 +488,8 @@ def main():
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("--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 resolution")
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]")
builder_args(parser)
vivado_build_args(parser)
args = parser.parse_args()
@@ -486,8 +501,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 and (args.version == "V1.0")):
print(" ***** ERROR ***** : VGA not supported on V.10\n")
if ((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")
assert(False)
soc = SBusFPGA(**soc_core_argdict(args),
@@ -498,6 +516,7 @@ def main():
engine=args.engine,
i2c=args.i2c,
cg3=args.cg3,
cg6=args.cg6,
cg3_res=args.cg3_res)
#soc.add_uart(name="uart", baudrate=115200, fifo_depth=16)
@@ -542,6 +561,7 @@ def main():
engine=args.engine,
i2c=args.i2c,
cg3=args.cg3,
cg6=args.cg6,
cg3_res=args.cg3_res)
write_to_file(os.path.join(f"prom_{version_for_filename}.fth"), prom_content)