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")