-
Notifications
You must be signed in to change notification settings - Fork 550
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix AXI version of the Zynq7000 busses and add mapped connect fuction #1989
base: master
Are you sure you want to change the base?
Conversation
The absence of WID signal in AXI4 when compared to AXI3 can sometimes cause problems.
It allows connecting two different busses that has different memory mappings. Usefull when softcore in PL of Zynq7000 wants to access the DDR memory of the PS7 block.
Add connect_mapped function
Hi, |
I think this was used to remap the memory space :
|
I would love to see such functions so we can utilize PS memory as main_ram and debug soft-core from PS side. |
I use it like this, this is part of my board target file: cpu_cls = cpu.CPUS["zynq7000"]
zynq = cpu_cls(self.platform, "standard") # zynq7000 has no variants
zynq.set_ps7(name="ps", config = platform.ps7_config)
#axi_M_GP0 = zynq.add_axi_gp_master() # Uncomment only if you want the ARM cores to have access to the IO bus
#self.bus.add_master(master=axi_M_GP0) # of the softcore, otherwise having it commented gains better timings
axi_S_HP0 = zynq.add_axi_hp_slave(clock_domain = self.crg.cd_sys.name)
axi_S_HP1 = zynq.add_axi_hp_slave(clock_domain = self.crg.cd_sys.name)
axi_S_HP2 = zynq.add_axi_hp_slave(clock_domain = self.crg.cd_sys.name)
axi_S_HP3 = zynq.add_axi_hp_slave(clock_domain = self.crg.cd_sys.name)
axi_S_GP0 = zynq.add_axi_gp_slave(clock_domain = self.crg.cd_sys.name)
hp_ports = [axi_S_HP0, axi_S_HP1, axi_S_HP2, axi_S_HP3]
# PS7 DDR3 Interface -----------------------------
ddr_addr = self.cpu.mem_map["main_ram"]
map_fct_ddr = lambda sig : sig - ddr_addr + 0x0010_0000
sdram_size = 0x4000_0000
if hasattr(self.cpu, "add_memory_buses"):
self.cpu.add_memory_buses(address_width = 32, data_width = 64)
if len(self.cpu.memory_buses): # if CPU has dedicated memory bus
print("--------Connecting DDR to direct RAM port of the softcore using HP bus.--------")
for mem_bus in self.cpu.memory_buses:
i = 0
axi_ddr = axi.AXIInterface(hp_ports[i].data_width, hp_ports[i].address_width, "byte", hp_ports[i].id_width, "axi3")
self.comb += axi_ddr.connect_mapped(hp_ports[i], map_fct_ddr)
data_width_ratio = int(axi_ddr.data_width/mem_bus.data_width)
print("Connecting: ", str(mem_bus), " to ", str(axi_ddr))
print("CPU memory bus data width: ", mem_bus.data_width, " bits")
print("DDR bus data width: ", axi_ddr.data_width, " bits")
print("CPU memory bus address width: ", mem_bus.address_width, " bits")
print("DDR bus address width: ", axi_ddr.address_width, " bits")
print("CPU memory bus id width: ", mem_bus.id_width, " bits")
print("DDR bus id width: ", axi_ddr.id_width, " bits")
# Connect directly
if data_width_ratio == 1:
print("Direct connection")
self.comb += mem_bus.connect(axi_ddr)
# UpConvert
elif data_width_ratio > 1:
print("UpConversion")
axi_port = axi.AXIInterface(data_width = axi_ddr.data_width, addressing="byte", id_width = len(mem_bus.aw.id))
self.submodules += axi.AXIUpConverter(axi_from = mem_bus, axi_to = axi_port,)
self.comb += axi_port.connect(axi_ddr)
# DownConvert
else:
print("DownConversion")
axi_port = axi.AXIInterface(data_width = axi_ddr.data_width, addressing="byte", id_width = len(mem_bus.aw.id))
self.submodules += axi.AXIDownConverter(axi_from = mem_bus, axi_to = axi_port,)
self.comb += axi_port.connect(axi_ddr)
i = i + 1
# Add SDRAM region
origin = None
main_ram_region = SoCRegion(
origin = self.mem_map.get("main_ram", origin),
size = sdram_size,
mode = "rwx")
self.bus.add_region("main_ram", main_ram_region)
else:
print("--------Connecting DDR to general bus of the softcore using GP bus.--------")
axi_ddr = axi.AXIInterface(axi_S_GP0.data_width, axi_S_GP0.address_width, "byte", axi_S_GP0.id_width)
self.comb += axi_ddr.connect_mapped(axi_S_GP0, map_fct_ddr)
self.bus.add_slave(
name="main_ram",slave=axi_ddr,
region=SoCRegion(
origin=ddr_addr,
size=sdram_size,
mode="rwx"
)
)
print("---------------------------- End ----------------------------------------------")
self.submodules += zynq Very basic approach, this functionality can be merged into litex itself tho, so the argument "--with-sdram" would check if board is Zynq based or not. If no then it will create LiteDRAM, if yes than it will use that function and this code to connect the memory bus/general bus of the softCPU to the PS7 block. Sorry for the late answer, I wasnt at home because of work. If you have any questions dont hesitate to ask. And yes, the ARM cores in the PS7 and the softCPU can share the RAM with no speed bottleneck on either side and like that create a heterogenous computing system. Or having a litex_server running on the cores is also awesome idea. Please let me know. |
This PR fixes the bugs I was encountering while playing around with PS7 block connected to the soft SoC, it also adds a way to connect the softcore to the PS7 using the connect_mapped function. The AXI4 lacks WID which is needed in AXI3 in some rare cases. PR to litex-boards will also be created with the files for any Zynq7000 board to have a way to use the PS7 blocks DDR as MAIN_RAM for the soft SoC. I successfully use it to boot Debian on RV64GC softcores.