NuBusFPGA/nubus-to-ztex-gateware/goblin_accel.py

334 lines
16 KiB
Python

from migen import *
from migen.genlib.fifo import *
from litex.soc.interconnect.csr import *
from litex.soc.interconnect import wishbone
from litedram.common import LiteDRAMNativePort
from litedram.frontend.wishbone import LiteDRAMWishbone2Native
class GoblinAccel(Module): # AutoCSR ?
def __init__(self, soc):
platform = soc.platform
# reg access
self.bus = bus = wishbone.Interface()
self.COORD_BITS = COORD_BITS = 14 # need enough bytes for 32-bits depth and widest resolution ; should be <= 15 otherwise the INIT code will need to strip the upper bit from some parameters
reg_status = Signal(32) # 0
reg_cmd = Signal(32) # 1
reg_r5_cmd = Signal(32) # 2, to communicate with Vex
reg_op = Signal(8) # 3, X11 op or (0x80 | Render op)
reg_width = Signal(COORD_BITS) # 4
reg_height = Signal(COORD_BITS) # 5
reg_fgcolor = Signal(32) # 6
reg_depth = Signal(8) # 7, depth (0 is native)
reg_bitblt_src_x = Signal(COORD_BITS) # 8
reg_bitblt_src_y = Signal(COORD_BITS) # 9
reg_bitblt_dst_x = Signal(COORD_BITS) # 10
reg_bitblt_dst_y = Signal(COORD_BITS) # 11
reg_src_stride = Signal(COORD_BITS) # 12
reg_dst_stride = Signal(COORD_BITS) # 13
reg_src_ptr = Signal(32) # 14
reg_dst_ptr = Signal(32) # 15
reg_bitblt_msk_x = Signal(COORD_BITS) # 16
reg_bitblt_msk_y = Signal(COORD_BITS) # 17
reg_msk_stride = Signal(COORD_BITS) # 18
reg_msk_ptr = Signal(32) # 19
# do-some-work flags
do_blit = Signal()
do_fill = Signal()
do_patt = Signal()
do_rsmsk8dst32 = Signal()
do_rsrc32msk32dst32 = Signal()
do_rsrc32dst32 = Signal()
# cmd register reg_cmd
DO_BLIT_BIT = 0
DO_FILL_BIT = 1
DO_PATT_BIT = 2
DO_RSMSK8DST32_BIT = 3
DO_RSRC32MSK32DST32_BIT = 4
DO_RSRC32DST32_BIT = 5
# global status register reg_status
WORK_IN_PROGRESS_BIT = 0
# replicate all registers in both endianess
# we want to avoid byte-reversal on either the host or the Vex
bus_dat_w_endian = Signal(32)
bus_dat_r_endian = Signal(32)
self.comb += [
If(bus.adr[9], # 9 on bus is 11 for host
bus_dat_w_endian[24:32].eq(bus.dat_w[ 0: 8]),
bus_dat_w_endian[16:24].eq(bus.dat_w[ 8:16]),
bus_dat_w_endian[ 8:16].eq(bus.dat_w[16:24]),
bus_dat_w_endian[ 0: 8].eq(bus.dat_w[24:32]),
bus.dat_r[24:32].eq(bus_dat_r_endian[ 0: 8]),
bus.dat_r[16:24].eq(bus_dat_r_endian[ 8:16]),
bus.dat_r[ 8:16].eq(bus_dat_r_endian[16:24]),
bus.dat_r[ 0: 8].eq(bus_dat_r_endian[24:32]),
).Else(
bus_dat_w_endian.eq(bus.dat_w),
bus.dat_r.eq(bus_dat_r_endian),
)
]
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:9], { # bit 9 is used for endianess, so not there
"default": [ ],
# 0: reg_status R/O
0: [ NextValue(reg_status, bus_dat_w_endian) ], # debug, remove me
1: [ NextValue(reg_cmd, bus_dat_w_endian),
NextValue(do_blit, bus_dat_w_endian[DO_BLIT_BIT] & ~reg_status[WORK_IN_PROGRESS_BIT]),
NextValue(do_fill, bus_dat_w_endian[DO_FILL_BIT] & ~reg_status[WORK_IN_PROGRESS_BIT]),
NextValue(do_patt, bus_dat_w_endian[DO_PATT_BIT] & ~reg_status[WORK_IN_PROGRESS_BIT]),
NextValue(do_rsmsk8dst32, bus_dat_w_endian[DO_RSMSK8DST32_BIT] & ~reg_status[WORK_IN_PROGRESS_BIT]),
NextValue(do_rsrc32msk32dst32, bus_dat_w_endian[DO_RSRC32MSK32DST32_BIT] & ~reg_status[WORK_IN_PROGRESS_BIT]),
NextValue(do_rsrc32dst32, bus_dat_w_endian[DO_RSRC32DST32_BIT] & ~reg_status[WORK_IN_PROGRESS_BIT]),
],
2: [ NextValue(reg_r5_cmd, bus_dat_w_endian) ],
3: [ NextValue(reg_op, bus_dat_w_endian) ],
4: [ NextValue(reg_width, bus_dat_w_endian) ],
5: [ NextValue(reg_height, bus_dat_w_endian) ],
6: [ NextValue(reg_fgcolor, bus_dat_w_endian) ],
7: [ NextValue(reg_depth, bus_dat_w_endian) ],
8: [ NextValue(reg_bitblt_src_x, bus_dat_w_endian) ],
9: [ NextValue(reg_bitblt_src_y, bus_dat_w_endian) ],
10: [ NextValue(reg_bitblt_dst_x, bus_dat_w_endian) ],
11: [ NextValue(reg_bitblt_dst_y, bus_dat_w_endian) ],
12: [ NextValue(reg_src_stride, bus_dat_w_endian) ],
13: [ NextValue(reg_dst_stride, bus_dat_w_endian) ],
14: [ NextValue(reg_src_ptr, bus_dat_w_endian) ],
15: [ NextValue(reg_dst_ptr, bus_dat_w_endian) ],
16: [ NextValue(reg_bitblt_msk_x, bus_dat_w_endian) ],
17: [ NextValue(reg_bitblt_msk_y, bus_dat_w_endian) ],
18: [ NextValue(reg_msk_stride, bus_dat_w_endian) ],
19: [ NextValue(reg_msk_ptr, bus_dat_w_endian) ],
}),
NextValue(bus.ack, 1),
).Elif(bus.cyc & bus.stb & ~bus.we & ~bus.ack, #read
Case(bus.adr[0:9], { # bit 9 is used for endianess, so not there
"default": [ NextValue(bus_dat_r_endian, 0xDEADBEEF) ],
0: [ NextValue(bus_dat_r_endian, reg_status) ],
1: [ NextValue(bus_dat_r_endian, reg_cmd) ],
2: [ NextValue(bus_dat_r_endian, reg_r5_cmd) ],
3: [ NextValue(bus_dat_r_endian, reg_op) ],
4: [ NextValue(bus_dat_r_endian, reg_width) ],
5: [ NextValue(bus_dat_r_endian, reg_height) ],
6: [ NextValue(bus_dat_r_endian, reg_fgcolor) ],
7: [ NextValue(bus_dat_r_endian, reg_depth) ],
8: [ NextValue(bus_dat_r_endian, reg_bitblt_src_x) ],
9: [ NextValue(bus_dat_r_endian, reg_bitblt_src_y) ],
10: [ NextValue(bus_dat_r_endian, reg_bitblt_dst_x) ],
11: [ NextValue(bus_dat_r_endian, reg_bitblt_dst_y) ],
12: [ NextValue(bus_dat_r_endian, reg_src_stride) ],
13: [ NextValue(bus_dat_r_endian, reg_dst_stride) ],
14: [ NextValue(bus_dat_r_endian, reg_src_ptr) ],
15: [ NextValue(bus_dat_r_endian, reg_dst_ptr) ],
16: [ NextValue(bus_dat_r_endian, reg_bitblt_msk_x) ],
17: [ NextValue(bus_dat_r_endian, reg_bitblt_msk_y) ],
18: [ NextValue(bus_dat_r_endian, reg_msk_stride) ],
19: [ NextValue(bus_dat_r_endian, reg_msk_ptr) ],
}),
NextValue(bus.ack, 1),
).Else(
NextValue(bus.ack, 0),
)
)
# also in blit.c, for r5-cmd
FUN_DONE_BIT = 31
FUN_BLIT_BIT = 0
FUN_FILL_BIT = 1
FUN_PATT_BIT = 2
FUN_RSMSK8DST32_BIT = 3
FUN_RSRC32MSK32DST32_BIT = 4
FUN_RSRC32DST32_BIT = 5
# to hold the Vex in reset
self.local_reset = local_reset = Signal(reset = 1)
self.sync += [
If(reg_r5_cmd[FUN_DONE_BIT],
reg_r5_cmd.eq(0),
reg_status[WORK_IN_PROGRESS_BIT].eq(0),
local_reset.eq(1),
#timeout.eq(timeout_rst),
).Elif(do_blit & ~reg_status[WORK_IN_PROGRESS_BIT],
do_blit.eq(0),
reg_r5_cmd[FUN_BLIT_BIT].eq(1),
reg_status[WORK_IN_PROGRESS_BIT].eq(1),
local_reset.eq(0),
#timeout.eq(timeout_rst),
).Elif(do_fill & ~reg_status[WORK_IN_PROGRESS_BIT],
do_fill.eq(0),
reg_r5_cmd[FUN_FILL_BIT].eq(1),
reg_status[WORK_IN_PROGRESS_BIT].eq(1),
local_reset.eq(0),
#timeout.eq(timeout_rst),
).Elif(do_patt & ~reg_status[WORK_IN_PROGRESS_BIT],
do_patt.eq(0),
reg_r5_cmd[FUN_PATT_BIT].eq(1),
reg_status[WORK_IN_PROGRESS_BIT].eq(1),
local_reset.eq(0),
#timeout.eq(timeout_rst),
).Elif(do_rsmsk8dst32 & ~reg_status[WORK_IN_PROGRESS_BIT],
do_rsmsk8dst32.eq(0),
reg_r5_cmd[FUN_RSMSK8DST32_BIT].eq(1),
reg_status[WORK_IN_PROGRESS_BIT].eq(1),
local_reset.eq(0),
#timeout.eq(timeout_rst),
).Elif(do_rsrc32msk32dst32 & ~reg_status[WORK_IN_PROGRESS_BIT],
do_rsrc32msk32dst32.eq(0),
reg_r5_cmd[FUN_RSRC32MSK32DST32_BIT].eq(1),
reg_status[WORK_IN_PROGRESS_BIT].eq(1),
local_reset.eq(0),
#timeout.eq(timeout_rst),
).Elif(do_rsrc32dst32 & ~reg_status[WORK_IN_PROGRESS_BIT],
do_rsrc32dst32.eq(0),
reg_r5_cmd[FUN_RSRC32DST32_BIT].eq(1),
reg_status[WORK_IN_PROGRESS_BIT].eq(1),
local_reset.eq(0),
#timeout.eq(timeout_rst),
)
]
self.ibus = ibus = wishbone.Interface()
#self.dbus = dbus = wishbone.Interface()
vex_reset = Signal()
dbus_raw = wishbone.Interface(data_width=128, adr_width=28) # wide interface from the Vex, master
dbus_sys = wishbone.Interface(data_width=128, adr_width=28) # wide interface to system wishbone
dbus_mem = wishbone.Interface(data_width=128, adr_width=28) # wide interface for direct memory access
self.dbus = dbus_sys
#masters = {}
#masters["VexRiscv_AccelFB"] = dbus_raw
##slaves["VexSystemAccess"] = dbus
##regions["VexSystemAccess"] = SoCRegion(origin=soc.mem_map.get("goblin_bt", None), size=0x00100000, cached=False)
##slaves["VexMemoryAccess"] = dbus_mem
##regions["VexSystemAccess"] = SoCRegion(origin=soc.mem_map.get("main_ram", None), size=0x10000000, cached=True)
#function_VexSystemAccess = lambda x: (x[24:28] != 0x8)
#function_VexMemoryAccess = lambda x: (x[24:28] == 0x8)
##function_VexSystemAccess = lambda x: (True)
##function_VexMemoryAccess = lambda x: (False)
#slaves = [
# (function_VexSystemAccess, dbus_sys),
# (function_VexMemoryAccess, dbus_mem),
#]
#self.submodules.crossbar = wishbone.Crossbar(
# masters = masters.values(),
# slaves = slaves,
# register = False,
# timeout_cycles = None
#)
#self.submodules.shared = wishbone.InterconnectShared(
# masters = masters.values(),
# slaves = slaves,
# register = False,
# timeout_cycles = None
#)
self.comb += [
If((dbus_raw.adr[24:28] == 0x8),
dbus_sys.cyc.eq(0),
dbus_sys.stb.eq(0),
dbus_mem.cyc.eq(dbus_raw.cyc),
dbus_mem.stb.eq(dbus_raw.stb),
dbus_raw.ack.eq(dbus_mem.ack),
dbus_raw.err.eq(dbus_mem.err),
dbus_raw.dat_r.eq(dbus_mem.dat_r),
).Else(
dbus_sys.cyc.eq(dbus_raw.cyc),
dbus_sys.stb.eq(dbus_raw.stb),
dbus_mem.cyc.eq(0),
dbus_mem.stb.eq(0),
dbus_raw.ack.eq(dbus_sys.ack),
dbus_raw.err.eq(dbus_sys.err),
dbus_raw.dat_r.eq(dbus_sys.dat_r),
),
dbus_sys.dat_w.eq(dbus_raw.dat_w),
dbus_mem.dat_w.eq(dbus_raw.dat_w),
dbus_sys.we.eq(dbus_raw.we),
dbus_mem.we.eq(dbus_raw.we),
dbus_sys.adr.eq(dbus_raw.adr),
dbus_mem.adr.eq(dbus_raw.adr),
dbus_sys.sel.eq(dbus_raw.sel),
dbus_mem.sel.eq(dbus_raw.sel),
dbus_sys.cti.eq(dbus_raw.cti),
dbus_mem.cti.eq(dbus_raw.cti),
dbus_sys.bte.eq(dbus_raw.bte),
dbus_mem.bte.eq(dbus_raw.bte),
]
# now connect the memory
# memory port
port = soc.sdram.crossbar.get_port()
assert(port.data_width == 128)
self.submodules.wb2native = LiteDRAMWishbone2Native(
wishbone = dbus_mem,
port = port,
base_address = soc.bus.regions["main_ram"].origin
)
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_raw.cyc,
o_dBusWishbone_STB = dbus_raw.stb,
i_dBusWishbone_ACK = dbus_raw.ack,
o_dBusWishbone_WE = dbus_raw.we,
o_dBusWishbone_ADR = dbus_raw.adr,
i_dBusWishbone_DAT_MISO = dbus_raw.dat_r,
o_dBusWishbone_DAT_MOSI = dbus_raw.dat_w,
o_dBusWishbone_SEL = dbus_raw.sel,
i_dBusWishbone_ERR = dbus_raw.err,
o_dBusWishbone_CTI = dbus_raw.cti,
o_dBusWishbone_BTE = dbus_raw.bte,)
self.add_sources(platform)
def get_netlist_name(self):
return "VexRiscv"
class GoblinAccelNuBus(GoblinAccel):
def add_sources(self, platform):
platform.add_source("/home/dolbeau/NuBusFPGA/nubus-to-ztex-gateware/VexRiscv_GoblinAccel_NuBus.v", "verilog")
class GoblinAccelSBus(GoblinAccel):
def add_sources(self, platform):
led0 = platform.request("SBUS_DATA_OE_LED")
self.comb += [ led0.eq(~self.local_reset), ]
platform.add_source("/home/dolbeau/NuBusFPGA/nubus-to-ztex-gateware/VexRiscv_GoblinAccel_SBus.v", "verilog")