Merge pull request #1776 from Dolu1990/nax-smp

core/naxriscv provide a deployable NaxRiscv SMP
This commit is contained in:
enjoy-digital 2023-09-18 09:05:43 +02:00 committed by GitHub
commit 4639c7b39c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 178 additions and 141 deletions

View File

@ -1,4 +1,15 @@
.section .text, "ax", @progbits
.global boot_helper
.global boot_helper
.global smp_lottery_target
.global smp_lottery_lock
.global smp_lottery_args
boot_helper:
sw x10, smp_lottery_args , x14
sw x11, smp_lottery_args+4, x14
sw x12, smp_lottery_args+8, x14
sw x13, smp_lottery_target, x14
fence w, w
li x15, 1
sw x15, smp_lottery_lock, x14
jr x13

View File

@ -50,8 +50,11 @@ class NaxRiscv(CPU):
netlist_name = None
scala_paths = []
xlen = 32
cpu_count = 1
jtag_tap = False
jtag_instruction = False
with_dma = False
litedram_width = 32
# ABI.
@staticmethod
@ -73,7 +76,7 @@ class NaxRiscv(CPU):
# Memory Mapping.
@property
def mem_map(self):
def mem_map(self): # TODO
return {
"rom": 0x0000_0000,
"sram": 0x1000_0000,
@ -103,6 +106,8 @@ class NaxRiscv(CPU):
cpu_group.add_argument("--scala-file", action="append", help="Specify the scala files used to configure NaxRiscv.")
cpu_group.add_argument("--scala-args", action="append", help="Add arguements for the scala run time. Ex : --scala-args 'rvc=true,mmu=false'")
cpu_group.add_argument("--xlen", default=32, help="Specify the RISC-V data width.")
cpu_group.add_argument("--cpu-count", default=1, help="How many NaxRiscv CPU")
cpu_group.add_argument("--with-coherent-dma", action="store_true", help="Enable coherent DMA accesses")
cpu_group.add_argument("--with-jtag-tap", action="store_true", help="Add a embedded JTAG tap for debugging")
cpu_group.add_argument("--with-jtag-instruction", action="store_true", help="Add a JTAG instruction port which implement tunneling for debugging (TAP not included)")
cpu_group.add_argument("--update-repo", default="recommended", choices=["latest","wipe+latest","recommended","wipe+recommended","no"], help="Specify how the NaxRiscv & SpinalHDL repo should be updated (latest: update to HEAD, recommended: Update to known compatible version, no: Don't update, wipe+*: Do clean&reset before checkout)")
@ -114,6 +119,7 @@ class NaxRiscv(CPU):
print(args)
NaxRiscv.jtag_tap = args.with_jtag_tap
NaxRiscv.jtag_instruction = args.with_jtag_instruction
NaxRiscv.with_dma = args.with_coherent_dma
NaxRiscv.update_repo = args.update_repo
NaxRiscv.no_netlist_cache = args.no_netlist_cache
NaxRiscv.with_fpu = args.with_fpu
@ -128,6 +134,8 @@ class NaxRiscv(CPU):
NaxRiscv.data_width = xlen
NaxRiscv.gcc_triple = CPU_GCC_TRIPLE_RISCV64
NaxRiscv.linker_output_format = f"elf{xlen}-littleriscv"
if args.cpu_count:
NaxRiscv.cpu_count = args.cpu_count
def __init__(self, platform, variant):
@ -136,55 +144,97 @@ class NaxRiscv(CPU):
self.human_name = self.human_name
self.reset = Signal()
self.interrupt = Signal(32)
self.ibus = ibus = axi.AXILiteInterface(address_width=32, data_width=32)
self.dbus = dbus = axi.AXILiteInterface(address_width=32, data_width=32)
self.pbus = pbus = axi.AXILiteInterface(address_width=32, data_width=32)
self.periph_buses = [ibus, dbus] # Peripheral buses (Connected to main SoC's bus).
self.periph_buses = [pbus] # Peripheral buses (Connected to main SoC's bus).
self.memory_buses = [] # Memory buses (Connected directly to LiteDRAM).
# # #
self.tracer_valid = Signal()
self.tracer_payload = Signal(8)
# CPU Instance.
self.cpu_params = dict(
# Clk/Rst.
i_clk = ClockSignal("sys"),
i_reset = ResetSignal("sys") | self.reset,
# Interrupt.
i_peripheral_interrupt = self.interrupt, # FIXME: Check what is expected. => interrupt(0) is dummy and should not be used (PLIC stuff), need to reserve interrupt(0)
o_patcher_tracer_valid=self.tracer_valid,
o_patcher_tracer_payload=self.tracer_payload,
# Peripheral Instruction Bus (AXI Lite Slave).
o_peripheral_ibus_arvalid = ibus.ar.valid,
i_peripheral_ibus_arready = ibus.ar.ready,
o_peripheral_ibus_araddr = ibus.ar.addr,
o_peripheral_ibus_arprot = Open(),
i_peripheral_ibus_rvalid = ibus.r.valid,
o_peripheral_ibus_rready = ibus.r.ready,
i_peripheral_ibus_rdata = ibus.r.data,
i_peripheral_ibus_rresp = ibus.r.resp,
# Interrupt.
i_peripheral_externalInterrupts_port = self.interrupt,
# Peripheral Memory Bus (AXI Lite Slave).
o_peripheral_dbus_awvalid = dbus.aw.valid,
i_peripheral_dbus_awready = dbus.aw.ready,
o_peripheral_dbus_awaddr = dbus.aw.addr,
o_peripheral_dbus_awprot = Open(),
o_peripheral_dbus_wvalid = dbus.w.valid,
i_peripheral_dbus_wready = dbus.w.ready,
o_peripheral_dbus_wdata = dbus.w.data,
o_peripheral_dbus_wstrb = dbus.w.strb,
i_peripheral_dbus_bvalid = dbus.b.valid,
o_peripheral_dbus_bready = dbus.b.ready,
i_peripheral_dbus_bresp = dbus.b.resp,
o_peripheral_dbus_arvalid = dbus.ar.valid,
i_peripheral_dbus_arready = dbus.ar.ready,
o_peripheral_dbus_araddr = dbus.ar.addr,
o_peripheral_dbus_arprot = Open(),
i_peripheral_dbus_rvalid = dbus.r.valid,
o_peripheral_dbus_rready = dbus.r.ready,
i_peripheral_dbus_rdata = dbus.r.data,
i_peripheral_dbus_rresp = dbus.r.resp,
o_pBus_awvalid = pbus.aw.valid,
i_pBus_awready = pbus.aw.ready,
o_pBus_awaddr = pbus.aw.addr,
o_pBus_awprot = Open(),
o_pBus_wvalid = pbus.w.valid,
i_pBus_wready = pbus.w.ready,
o_pBus_wdata = pbus.w.data,
o_pBus_wstrb = pbus.w.strb,
i_pBus_bvalid = pbus.b.valid,
o_pBus_bready = pbus.b.ready,
i_pBus_bresp = pbus.b.resp,
o_pBus_arvalid = pbus.ar.valid,
i_pBus_arready = pbus.ar.ready,
o_pBus_araddr = pbus.ar.addr,
o_pBus_arprot = Open(),
i_pBus_rvalid = pbus.r.valid,
o_pBus_rready = pbus.r.ready,
i_pBus_rdata = pbus.r.data,
i_pBus_rresp = pbus.r.resp
)
if NaxRiscv.with_dma:
self.dma_bus = dma_bus = axi.AXIInterface(data_width=64, address_width=32, id_width=4)
self.cpu_params.update(
o_dma_bus_awready=dma_bus.aw.ready,
i_dma_bus_awvalid=dma_bus.aw.valid,
i_dma_bus_awid=dma_bus.aw.id,
i_dma_bus_awaddr=dma_bus.aw.addr,
i_dma_bus_awlen=dma_bus.aw.len,
i_dma_bus_awsize=dma_bus.aw.size,
i_dma_bus_awburst=dma_bus.aw.burst,
i_dma_bus_awlock=dma_bus.aw.lock,
i_dma_bus_awcache=dma_bus.aw.cache,
i_dma_bus_awprot=dma_bus.aw.prot,
i_dma_bus_awqos=dma_bus.aw.qos,
o_dma_bus_wready=dma_bus.w.ready,
i_dma_bus_wvalid=dma_bus.w.valid,
i_dma_bus_wdata=dma_bus.w.data,
i_dma_bus_wstrb=dma_bus.w.strb,
i_dma_bus_wlast=dma_bus.w.last,
i_dma_bus_bready=dma_bus.b.ready,
o_dma_bus_bvalid=dma_bus.b.valid,
o_dma_bus_bid=dma_bus.b.id,
o_dma_bus_bresp=dma_bus.b.resp,
o_dma_bus_arready=dma_bus.ar.ready,
i_dma_bus_arvalid=dma_bus.ar.valid,
i_dma_bus_arid=dma_bus.ar.id,
i_dma_bus_araddr=dma_bus.ar.addr,
i_dma_bus_arlen=dma_bus.ar.len,
i_dma_bus_arsize=dma_bus.ar.size,
i_dma_bus_arburst=dma_bus.ar.burst,
i_dma_bus_arlock=dma_bus.ar.lock,
i_dma_bus_arcache=dma_bus.ar.cache,
i_dma_bus_arprot=dma_bus.ar.prot,
i_dma_bus_arqos=dma_bus.ar.qos,
i_dma_bus_rready=dma_bus.r.ready,
o_dma_bus_rvalid=dma_bus.r.valid,
o_dma_bus_rid=dma_bus.r.id,
o_dma_bus_rdata=dma_bus.r.data,
o_dma_bus_rresp=dma_bus.r.resp,
o_dma_bus_rlast=dma_bus.r.last
)
def set_reset_address(self, reset_address):
self.reset_address = reset_address
@ -206,9 +256,12 @@ class NaxRiscv(CPU):
def generate_netlist_name(reset_address):
md5_hash = hashlib.md5()
md5_hash.update(str(reset_address).encode('utf-8'))
md5_hash.update(str(NaxRiscv.litedram_width).encode('utf-8'))
md5_hash.update(str(NaxRiscv.xlen).encode('utf-8'))
md5_hash.update(str(NaxRiscv.cpu_count).encode('utf-8'))
md5_hash.update(str(NaxRiscv.jtag_tap).encode('utf-8'))
md5_hash.update(str(NaxRiscv.jtag_instruction).encode('utf-8'))
md5_hash.update(str(NaxRiscv.with_dma).encode('utf-8'))
md5_hash.update(str(NaxRiscv.memory_regions).encode('utf-8'))
for args in NaxRiscv.scala_args:
md5_hash.update(args.encode('utf-8'))
@ -235,7 +288,7 @@ class NaxRiscv(CPU):
os.chdir(os.path.join(dir))
wipe_cmd = "&& git clean --force -d -x && git reset --hard" if "wipe" in NaxRiscv.update_repo else ""
checkout_cmd = f"&& git checkout {hash}" if hash is not None else ""
subprocess.check_call(f"cd {dir} {wipe_cmd} && git checkout {branch} && git pull {checkout_cmd}", shell=True)
subprocess.check_call(f"cd {dir} {wipe_cmd} && git checkout {branch} && git submodule init && git pull --recurse-submodules {checkout_cmd}", shell=True)
# Netlist Generation.
@staticmethod
@ -245,14 +298,16 @@ class NaxRiscv(CPU):
sdir = os.path.join(vdir, "ext", "SpinalHDL")
if NaxRiscv.update_repo != "no":
NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git" , "main", "d7213a3f" if (NaxRiscv.update_repo == "recommended") else None)
NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "dev", "912f4b37" if (NaxRiscv.update_repo == "recommended") else None)
NaxRiscv.git_setup("NaxRiscv", ndir, "https://github.com/SpinalHDL/NaxRiscv.git", "coherency", "ee4c6fb7" if NaxRiscv.update_repo=="recommended" else None)
NaxRiscv.git_setup("SpinalHDL", sdir, "https://github.com/SpinalHDL/SpinalHDL.git", "bus-fabric" , "ee95492a" if NaxRiscv.update_repo=="recommended" else None)
gen_args = []
gen_args.append(f"--netlist-name={NaxRiscv.netlist_name}")
gen_args.append(f"--netlist-directory={vdir}")
gen_args.append(f"--reset-vector={reset_address}")
gen_args.append(f"--xlen={NaxRiscv.xlen}")
gen_args.append(f"--cpu-count={NaxRiscv.cpu_count}")
gen_args.append(f"--litedram-width={NaxRiscv.litedram_width}")
for region in NaxRiscv.memory_regions:
gen_args.append(f"--memory-region={region[0]},{region[1]},{region[2]},{region[3]}")
for args in NaxRiscv.scala_args:
@ -263,12 +318,14 @@ class NaxRiscv(CPU):
gen_args.append(f"--with-jtag-instruction")
if(NaxRiscv.jtag_tap or NaxRiscv.jtag_instruction):
gen_args.append(f"--with-debug")
if(NaxRiscv.with_dma) :
gen_args.append(f"--with-dma")
for file in NaxRiscv.scala_paths:
gen_args.append(f"--scala-file={file}")
if(NaxRiscv.with_fpu):
gen_args.append(f"--scala-args=rvf=true,rvd=true")
cmd = f"""cd {ndir} && sbt "runMain naxriscv.platform.LitexGen {" ".join(gen_args)}\""""
cmd = f"""cd {ndir} && sbt "runMain naxriscv.platform.litex.NaxGen {" ".join(gen_args)}\""""
print("NaxRiscv generation command :")
print(cmd)
subprocess.check_call(cmd, shell=True)
@ -277,6 +334,7 @@ class NaxRiscv(CPU):
def add_sources(self, platform):
vdir = get_data_mod("cpu", "naxriscv").data_location
print(f"NaxRiscv netlist : {self.netlist_name}")
if NaxRiscv.no_netlist_cache or not os.path.exists(os.path.join(vdir, self.netlist_name + ".v")):
self.generate_netlist(self.reset_address)
@ -305,33 +363,12 @@ class NaxRiscv(CPU):
soc.bus.add_region("opensbi", SoCRegion(origin=self.mem_map["main_ram"] + 0x00f0_0000, size=0x8_0000, cached=True, linker=True))
# Define ISA.
soc.add_config("CPU_COUNT", NaxRiscv.cpu_count)
soc.add_config("CPU_ISA", NaxRiscv.get_arch())
soc.add_config("CPU_MMU", {32 : "sv32", 64 : "sv39"}[NaxRiscv.xlen])
# Add PLIC Bus (AXILite Slave).
self.plicbus = plicbus = axi.AXILiteInterface(address_width=32, data_width=32)
self.cpu_params.update(
i_peripheral_plic_awvalid = plicbus.aw.valid,
o_peripheral_plic_awready = plicbus.aw.ready,
i_peripheral_plic_awaddr = plicbus.aw.addr,
i_peripheral_plic_awprot = Constant(2),
i_peripheral_plic_wvalid = plicbus.w.valid,
o_peripheral_plic_wready = plicbus.w.ready,
i_peripheral_plic_wdata = plicbus.w.data,
i_peripheral_plic_wstrb = plicbus.w.strb,
o_peripheral_plic_bvalid = plicbus.b.valid,
i_peripheral_plic_bready = plicbus.b.ready,
o_peripheral_plic_bresp = plicbus.b.resp,
i_peripheral_plic_arvalid = plicbus.ar.valid,
o_peripheral_plic_arready = plicbus.ar.ready,
i_peripheral_plic_araddr = plicbus.ar.addr,
i_peripheral_plic_arprot = Constant(2),
o_peripheral_plic_rvalid = plicbus.r.valid,
i_peripheral_plic_rready = plicbus.r.ready,
o_peripheral_plic_rdata = plicbus.r.data,
o_peripheral_plic_rresp = plicbus.r.resp,
)
soc.bus.add_slave("plic", self.plicbus, region=SoCRegion(origin=soc.mem_map.get("plic"), size=0x40_0000, cached=False))
soc.bus.add_region("plic", SoCRegion(origin=soc.mem_map.get("plic"), size=0x40_0000, cached=False, linker=True))
soc.bus.add_region("clint", SoCRegion(origin=soc.mem_map.get("clint"), size= 0x1_0000, cached=False, linker=True))
if NaxRiscv.jtag_tap:
self.jtag_tms = Signal()
@ -390,95 +427,54 @@ class NaxRiscv(CPU):
self.comb += debug_ndmreset_rise.eq(debug_ndmreset & ~debug_ndmreset_last)
self.comb += If(debug_ndmreset_rise, soc.crg.rst.eq(1))
# Add CLINT Bus (AXILite Slave).
self.clintbus = clintbus = axi.AXILiteInterface(address_width=32, data_width=32)
self.cpu_params.update(
i_peripheral_clint_awvalid = clintbus.aw.valid,
o_peripheral_clint_awready = clintbus.aw.ready,
i_peripheral_clint_awaddr = clintbus.aw.addr,
i_peripheral_clint_awprot = Constant(2),
i_peripheral_clint_wvalid = clintbus.w.valid,
o_peripheral_clint_wready = clintbus.w.ready,
i_peripheral_clint_wdata = clintbus.w.data,
i_peripheral_clint_wstrb = clintbus.w.strb,
o_peripheral_clint_bvalid = clintbus.b.valid,
i_peripheral_clint_bready = clintbus.b.ready,
o_peripheral_clint_bresp = clintbus.b.resp,
i_peripheral_clint_arvalid = clintbus.ar.valid,
o_peripheral_clint_arready = clintbus.ar.ready,
i_peripheral_clint_araddr = clintbus.ar.addr,
i_peripheral_clint_arprot = Constant(2),
o_peripheral_clint_rvalid = clintbus.r.valid,
i_peripheral_clint_rready = clintbus.r.ready,
o_peripheral_clint_rdata = clintbus.r.data,
o_peripheral_clint_rresp = clintbus.r.resp,
)
soc.bus.add_slave("clint", clintbus, region=SoCRegion(origin=soc.mem_map.get("clint"), size=0x1_0000, cached=False))
self.soc_bus = soc.bus # FIXME: Save SoC Bus instance to retrieve the final mem layout on finalization.
def add_memory_buses(self, address_width, data_width):
NaxRiscv.litedram_width = data_width
nax_data_width = 64
nax_burst_size = 64
assert data_width >= nax_data_width # FIXME: Only supporting up-conversion for now.
assert data_width <= nax_burst_size*8 # FIXME: AXIUpConverter doing assumptions on minimal burst_size.
ibus = axi.AXIInterface(
data_width = nax_data_width,
mbus = axi.AXIInterface(
data_width = NaxRiscv.litedram_width,
address_width = 32,
id_width = 1,
id_width = 8, #TODO
)
dbus = axi.AXIInterface(
data_width = nax_data_width,
address_width = 32,
id_width = 4,
)
self.memory_buses.append(ibus)
self.memory_buses.append(dbus)
self.memory_buses.append(mbus)
self.cpu_params.update(
# Instruction Memory Bus (Master).
o_ram_ibus_arvalid = ibus.ar.valid,
i_ram_ibus_arready = ibus.ar.ready,
o_ram_ibus_araddr = ibus.ar.addr,
o_ram_ibus_arlen = ibus.ar.len,
o_ram_ibus_arsize = ibus.ar.size,
o_ram_ibus_arburst = ibus.ar.burst,
i_ram_ibus_rvalid = ibus.r.valid,
o_ram_ibus_rready = ibus.r.ready,
i_ram_ibus_rdata = ibus.r.data,
i_ram_ibus_rresp = ibus.r.resp,
i_ram_ibus_rlast = ibus.r.last,
# Data Memory Bus (Master).
o_ram_dbus_awvalid = dbus.aw.valid,
i_ram_dbus_awready = dbus.aw.ready,
o_ram_dbus_awaddr = dbus.aw.addr,
o_ram_dbus_awid = dbus.aw.id,
o_ram_dbus_awlen = dbus.aw.len,
o_ram_dbus_awsize = dbus.aw.size,
o_ram_dbus_awburst = dbus.aw.burst,
o_ram_dbus_wvalid = dbus.w.valid,
i_ram_dbus_wready = dbus.w.ready,
o_ram_dbus_wdata = dbus.w.data,
o_ram_dbus_wstrb = dbus.w.strb,
o_ram_dbus_wlast = dbus.w.last,
i_ram_dbus_bvalid = dbus.b.valid,
o_ram_dbus_bready = dbus.b.ready,
i_ram_dbus_bid = dbus.b.id,
i_ram_dbus_bresp = dbus.b.resp,
o_ram_dbus_arvalid = dbus.ar.valid,
i_ram_dbus_arready = dbus.ar.ready,
o_ram_dbus_araddr = dbus.ar.addr,
o_ram_dbus_arid = dbus.ar.id,
o_ram_dbus_arlen = dbus.ar.len,
o_ram_dbus_arsize = dbus.ar.size,
o_ram_dbus_arburst = dbus.ar.burst,
i_ram_dbus_rvalid = dbus.r.valid,
o_ram_dbus_rready = dbus.r.ready,
i_ram_dbus_rdata = dbus.r.data,
i_ram_dbus_rid = dbus.r.id,
i_ram_dbus_rresp = dbus.r.resp,
i_ram_dbus_rlast = dbus.r.last,
# Memory Bus (Master).
o_mBus_awvalid = mbus.aw.valid,
i_mBus_awready = mbus.aw.ready,
o_mBus_awaddr = mbus.aw.addr,
o_mBus_awid = mbus.aw.id,
o_mBus_awlen = mbus.aw.len,
o_mBus_awsize = mbus.aw.size,
o_mBus_awburst = mbus.aw.burst,
o_mBus_awallStrb = Open(),
o_mBus_wvalid = mbus.w.valid,
i_mBus_wready = mbus.w.ready,
o_mBus_wdata = mbus.w.data,
o_mBus_wstrb = mbus.w.strb,
o_mBus_wlast = mbus.w.last,
i_mBus_bvalid = mbus.b.valid,
o_mBus_bready = mbus.b.ready,
i_mBus_bid = mbus.b.id,
i_mBus_bresp = mbus.b.resp,
o_mBus_arvalid = mbus.ar.valid,
i_mBus_arready = mbus.ar.ready,
o_mBus_araddr = mbus.ar.addr,
o_mBus_arid = mbus.ar.id,
o_mBus_arlen = mbus.ar.len,
o_mBus_arsize = mbus.ar.size,
o_mBus_arburst = mbus.ar.burst,
i_mBus_rvalid = mbus.r.valid,
o_mBus_rready = mbus.r.ready,
i_mBus_rdata = mbus.r.data,
i_mBus_rid = mbus.r.id,
i_mBus_rresp = mbus.r.resp,
i_mBus_rlast = mbus.r.last,
)
def do_finalize(self):

View File

@ -2,6 +2,11 @@
.global isr
.global _start
.global smp_lottery_target
.global smp_lottery_lock
.global smp_lottery_args
.global smp_slave
#define MSTATUS_FS_INITIAL (1 << 13)
#define MSTATUS_FS_CLEAN (2 << 13)
#define MSTATUS_FS_DIRTY (3 << 13)
@ -67,6 +72,24 @@ enable_fpu:
li x1, MSTATUS_FS_INITIAL
csrs mstatus, x1
sw x0, smp_lottery_lock, a1
smp_tyranny:
csrr a0, mhartid
beqz a0, data_init
smp_slave:
lw a0, smp_lottery_lock
beqz a0, smp_slave
fence r, r
.word(0x100F) //i$ flush
lw x10, smp_lottery_args
lw x11, smp_lottery_args+4
lw x12, smp_lottery_args+8
lw x13, smp_lottery_target
jr x13
data_init:
la a0, _fdata
la a1, _edata
@ -96,3 +119,10 @@ bss_done:
call main
infinit_loop:
j infinit_loop
//Initialized to avoid having them set to zero by BSS clear
.bss
smp_lottery_target: .word 0
smp_lottery_args: .word 0; .word 0; .word 0
smp_lottery_lock: .word 0

View File

@ -122,7 +122,7 @@ git_repos = {
"pythondata-cpu-cva6": GitRepo(url="https://github.com/litex-hub/", clone="recursive"),
"pythondata-cpu-ibex": GitRepo(url="https://github.com/litex-hub/", clone="recursive", sha1=0xd3d53df),
"pythondata-cpu-minerva": GitRepo(url="https://github.com/litex-hub/"),
"pythondata-cpu-naxriscv": GitRepo(url="https://github.com/litex-hub/"),
"pythondata-cpu-naxriscv": GitRepo(url="https://github.com/litex-hub/", branch="smp"),
"pythondata-cpu-picorv32": GitRepo(url="https://github.com/litex-hub/"),
"pythondata-cpu-rocket": GitRepo(url="https://github.com/litex-hub/"),
"pythondata-cpu-serv": GitRepo(url="https://github.com/litex-hub/"),