Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/port/versal/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.o
*.elf
*.bin
BOOT.BIN
89 changes: 89 additions & 0 deletions src/port/versal/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Xilinx Versal Gen 1 (VMK180, Cortex-A72) wolfIP bare-metal port
#
# Build: make CROSS_COMPILE=aarch64-none-elf-
#
# Toolchain: ARM GNU aarch64-none-elf-gcc (tested with 14.3.rel1).
#
# UNTESTED ON HARDWARE -- structural scaffold mirroring src/port/zcu102/.

CROSS_COMPILE ?= aarch64-none-elf-
CC := $(CROSS_COMPILE)gcc
OBJCOPY := $(CROSS_COMPILE)objcopy
SIZE := $(CROSS_COMPILE)size

ROOT := ../../..

# Cortex-A72, AArch64, EL3 single-EL bare-metal. No SIMD/FP in the
# wolfIP/driver paths - keep -mgeneral-regs-only to catch any
# accidental FP use and make the ABI deterministic for cert.
CFLAGS := -mcpu=cortex-a72 -mgeneral-regs-only
CFLAGS += -Os -ffreestanding -fno-builtin -fno-common
CFLAGS += -fdata-sections -ffunction-sections
CFLAGS += -g -Wall -Wextra -Werror -Wno-unused-parameter
CFLAGS += -std=gnu99
CFLAGS += -I. -I$(ROOT) -I$(ROOT)/src -I$(ROOT)/src/port
CFLAGS += -DVERSAL -DXILINX_AARCH64
# Append extra defines for investigation builds, e.g.:
# make CFLAGS_EXTRA="-DDEBUG_GIC -DDEBUG_GEM -DDEBUG_PHY"
CFLAGS += $(CFLAGS_EXTRA)

ASFLAGS := -mcpu=cortex-a72

# Layout selector. Default ocm keeps the OCM-only layout that the JTAG
# iteration scripts depend on (everything in OCM @ 0xFFFC0000). Pass
# LAYOUT=ddr to relink for DDR @ 0x10000000 -- which is what wolfBoot
# uses (WOLFBOOT_LOAD_ADDRESS in zynqmp.config also applies to Versal
# when adapted).
LAYOUT ?= ocm
ifeq ($(LAYOUT),ddr)
LDSCRIPT := target_ddr.ld
CFLAGS += -DVERSAL_LAYOUT_DDR
else ifeq ($(LAYOUT),ocm)
LDSCRIPT := target.ld
CFLAGS += -DVERSAL_LAYOUT_OCM
else
$(error LAYOUT must be 'ocm' or 'ddr')
endif

LDFLAGS := -nostdlib -nostartfiles -T $(LDSCRIPT) -Wl,-gc-sections
# Replace newlib's aarch64 memset/memcpy (which use 'dc zva' and may
# hang on a similar Cortex-A72 setup; the safe pattern is to override
# them as we did on ZCU102).
LDFLAGS += -Wl,--wrap=memset -Wl,--wrap=memcpy

LOCAL_C := main.c uart.c mmu.c gic.c gem.c phy_dp83867.c entropy.c
LOCAL_S := startup.S
LOCAL_OBJS := $(LOCAL_C:.c=.o) $(LOCAL_S:.S=.o)

WOLFIP_OBJ := wolfip.o
OBJS := $(LOCAL_OBJS) $(WOLFIP_OBJ)

all: app.elf
@echo "Built: app.elf"
@$(SIZE) app.elf

app.elf: $(OBJS) $(LDSCRIPT)
$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) \
-Wl,--start-group -lc -lgcc -Wl,--end-group -o $@

$(WOLFIP_OBJ): $(ROOT)/src/wolfip.c
$(CC) $(CFLAGS) -Wno-zero-length-bounds -Wno-type-limits -c $< -o $@

%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@

%.o: %.S
$(CC) $(ASFLAGS) -c $< -o $@

clean:
rm -f $(OBJS) app.elf BOOT.BIN

.PHONY: all clean help

help:
@echo "Versal Gen 1 wolfIP build (scaffold, untested):"
@echo " make - build app.elf (OCM layout)"
@echo " make LAYOUT=ddr - DDR layout for wolfBoot"
@echo " make clean - remove artifacts"
@echo ""
@echo "Override CROSS_COMPILE if your toolchain prefix differs."
47 changes: 47 additions & 0 deletions src/port/versal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# wolfIP port: Xilinx Versal Gen 1 (VMK180)

**STATUS: UNTESTED ON HARDWARE.** Structural scaffold mirroring `src/port/zcu102/`. The code compiles cleanly with `aarch64-none-elf-gcc` but has not been brought up on a real VMK180 board. Lab verification is a Phase 3 milestone once the bench is available.

## What this port is

Bare-metal wolfIP port for the AMD/Xilinx Versal ACAP Gen 1, demoed on the VMK180 dev board. Cortex-A72 APU 0 at EL3, GCC bare-metal, no Xilinx Standalone BSP, no FreeRTOS. Targets the same deterministic UDP/IPv4 profile as the ZCU102 port for DO-178C DAL-C qualification.

## What differs from ZCU102

| Subsystem | ZCU102 | Versal Gen 1 | Where it lives |
|-----------|--------|--------------|----------------|
| APU core | Cortex-A53 | Cortex-A72 | `Makefile` (-mcpu) |
| Bootloader handoff | FSBL -> EL3 | PLM -> BL31 -> EL3 (or EL2) | `startup.S` |
| GIC | GIC-400 (GICv2) | GIC-600 (GICv3) | `gic.c` rewritten for GICv3 system regs + GICR |
| UART | Cadence | ARM PL011 | `uart.c` rewritten |
| GEM count | 4 (GEM0-3) | 2 (GEM0-1) | `board.h` |
| On-board RJ45 | GEM3 (INTID 95) | GEM0 (INTID 88) | `board.h` |
| GEM IP | Cadence GEM3 | Cadence GEM3 | `gem.c` unchanged (just base addr / INTID) |
| PHY | DP83867 RGMII | DP83867 RGMII (VMK180) | `phy_dp83867.c` unchanged |
| MMU | EL3 ARMv8 | EL3 ARMv8 | `mmu.c` unchanged |
| RNG | memuse entropy | memuse entropy | `entropy.c` unchanged |

The reused 90% (`gem.c`, `phy_dp83867.c`, `mmu.c`, `entropy.c`, `main.c`, `target.ld`, `target_ddr.ld`) is identical to the ZCU102 port; only `board.h`, `uart.c`, `gic.c`, and the startup/Makefile breadcrumbs are Versal-specific.

## Build

```
cd src/port/versal
make CROSS_COMPILE=aarch64-none-elf- # OCM layout (default)
make CROSS_COMPILE=aarch64-none-elf- LAYOUT=ddr # DDR layout for wolfBoot
```

Output: `app.elf`. Size info is printed at the end of the build.

## Known unknowns (to validate on hardware)

- `gic.c` `gic_init` order may need rework if BL31 owns the distributor on Versal -- the safer path is to skip distributor init entirely and only set up the redistributor + CPU interface. The current code re-initialises the distributor defensively; this may be redundant or actively wrong depending on BL31 settings.
- `CRL_APB_GEM0_REF_CTRL` offset in `board.h` is a placeholder (0x50). Cross-check against the Versal LPD clock register map before bring-up.
- The on-board PHY MDIO address on VMK180 needs confirmation; the ZCU102 used `0x0C`, VMK180 may be different.
- PL011 baud assumes `UARTCLK = 100 MHz`. Versal PLM typically configures this but the rate could differ; confirm from the LPD clock tree.
- `SCR_EL3` routing convention (set `IRQ`+`FIQ`+`EA` bits) is carried over from the ZCU102 fix. Cortex-A72 may not require it; harmless to leave for now.
- DDR DAP write reliability on Versal (the issue we hit on ZCU102 for JTAG iteration to DDR) may behave differently -- VMK180 uses LPDDR4 with PLM-controlled training. Expect SD/QSPI boot to be the easier first test path.

## Files

Identical layout to `src/port/zcu102/`. See that port's README for per-file responsibilities. The differences listed in the table above are the only substantive Versal-specific code.
108 changes: 108 additions & 0 deletions src/port/versal/board.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/* board.h
*
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfIP TCP/IP stack.
*
* wolfIP is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfIP is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*
* Xilinx Versal Gen 1 (VCxxxx / VMK180 board) PS register base
* addresses and GIC SPI IDs. Values are derived from the Versal ACAP
* Technical Reference Manual (AM011), the VMK180 board user guide,
* and the published `versal.dtsi` device tree. No Xilinx BSP header
* (xparameters.h) or xilstandalone code is referenced.
*
* UNTESTED ON HARDWARE -- code-only scaffold while the lab board is
* unavailable. The structure mirrors src/port/zcu102/. Key
* differences from ZynqMP are:
* - Cortex-A72 (not A53), with PLM handoff at EL2
* - GICv3 distributor + redistributor (no GICv2 legacy GICC)
* - ARM PL011 UART (not Cadence)
* - 2 GEMs (GEM0/GEM1) instead of 4; on-board RJ45 is GEM0 on VMK180
*/
#ifndef VERSAL_BOARD_H
#define VERSAL_BOARD_H

#include <stdint.h>

/* ---------------------------------------------------------------------
* Memory map (Versal PS)
* ------------------------------------------------------------------- */
#define DDR_BASE 0x00000000UL
#define DDR_SIZE 0x80000000UL /* 2 GB lower bank */

/* OCM on Versal lives at 0xFFFC0000 (256 KB). Same as ZynqMP. */
#define OCM_BASE 0xFFFC0000UL
#define OCM_SIZE 0x00040000UL

/* ---------------------------------------------------------------------
* PS peripherals
* ------------------------------------------------------------------- */
#define UART0_BASE 0xFF000000UL /* PL011 */
#define UART1_BASE 0xFF010000UL /* PL011 */

#define GEM0_BASE 0xFF0C0000UL /* on-board GEM (VMK180) */
#define GEM1_BASE 0xFF0D0000UL

#define CRL_APB_BASE 0xFF5E0000UL /* LPD clock & reset */
#define IOU_SLCR_BASE 0xFF180000UL

/* GICv3: distributor + redistributor */
#define GICD_BASE 0xF9000000UL
#define GICR_BASE 0xF9080000UL /* per-CPU redistributors */

/* ---------------------------------------------------------------------
* GIC SPI numbers as GIC INTIDs (ARM GIC numbering: SPI N -> INTID 32+N).
* Versal versal.dtsi:
* GEM0: GIC_SPI 56 -> INTID 88
* GEM1: GIC_SPI 58 -> INTID 90
* ------------------------------------------------------------------- */
#define IRQ_GEM0 (32 + 56) /* GIC_SPI 56 -> INTID 88,
* on-board VMK180 RJ45 */
#define IRQ_GEM1 (32 + 58) /* GIC_SPI 58 -> INTID 90 */

/* ---------------------------------------------------------------------
* CRL_APB clock and reset registers (LPD). Versal keeps the ZynqMP
* layout for the LPD clocks; the GEM clock control register names match.
* ------------------------------------------------------------------- */
#define CRL_APB_GEM0_REF_CTRL (CRL_APB_BASE + 0x50) /* offset TBD */
#define CRL_APB_RST_LPD_IOU0 (CRL_APB_BASE + 0x230) /* GEM bits 0-1 */

/* ---------------------------------------------------------------------
* PL011 UART0 - on-board USB-UART on VMK180
* ------------------------------------------------------------------- */
#define UART_BAUD 115200

/* MAC address for eth0. Locally-administered, even first octet. */
#ifndef WOLFIP_MAC_0
#define WOLFIP_MAC_0 0x02
#endif
#ifndef WOLFIP_MAC_1
#define WOLFIP_MAC_1 0x00
#endif
#ifndef WOLFIP_MAC_2
#define WOLFIP_MAC_2 0x5A
#endif
#ifndef WOLFIP_MAC_3
#define WOLFIP_MAC_3 0x11
#endif
#ifndef WOLFIP_MAC_4
#define WOLFIP_MAC_4 0x22
#endif
#ifndef WOLFIP_MAC_5
#define WOLFIP_MAC_5 0x33
#endif

#endif /* VERSAL_BOARD_H */
82 changes: 82 additions & 0 deletions src/port/versal/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/* config.h
*
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfIP TCP/IP stack.
*
* wolfIP is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfIP is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*
* wolfIP configuration for Xilinx ZCU102 (UltraScale+ MPSoC, A53-0 EL3
* bare-metal). UDP-only profile aimed at deterministic DAL-C use.
*/
#ifndef WOLF_CONFIG_H
#define WOLF_CONFIG_H

#ifndef CONFIG_IPFILTER
#define CONFIG_IPFILTER 0
#endif

#define ETHERNET
#define LINK_MTU 1536

/* UDP-only profile in intent: the application does not call
* wolfIP_sock_socket() with IPSTACK_SOCK_STREAM. MAX_TCPSOCKETS is set
* to a small non-zero value only because core wolfIP currently sizes
* its timer heap via MAX_TIMERS = MAX_TCPSOCKETS * 3, and DHCP / ARP
* aging need timers. With MAX_TCPSOCKETS=0 the timer-heap insert path
* is permanently full and DHCP cannot schedule its retransmit timer.
* A core wolfIP follow-up should decouple MAX_TIMERS from
* MAX_TCPSOCKETS so DAL-C builds can truly opt TCP code out at
* compile time. */
#define MAX_TCPSOCKETS 2
#define MAX_UDPSOCKETS 4
#define MAX_ICMPSOCKETS 1
#define RXBUF_SIZE (LINK_MTU * 4)
#define TXBUF_SIZE (LINK_MTU * 4)

#define MAX_NEIGHBORS 16

#ifndef WOLFIP_MAX_INTERFACES
#define WOLFIP_MAX_INTERFACES 1
#endif

#ifndef WOLFIP_ENABLE_FORWARDING
#define WOLFIP_ENABLE_FORWARDING 0
#endif

#ifndef WOLFIP_ENABLE_LOOPBACK
#define WOLFIP_ENABLE_LOOPBACK 0
#endif

#ifndef WOLFIP_ENABLE_DHCP
#define WOLFIP_ENABLE_DHCP 1
#endif

/* Static IP fallback (used if DHCP is disabled or times out). */
#define WOLFIP_IP "192.168.1.100"
#define WOLFIP_NETMASK "255.255.255.0"
#define WOLFIP_GW "192.168.1.1"
#define WOLFIP_STATIC_DNS_IP "8.8.8.8"

#if WOLFIP_ENABLE_DHCP
#define DHCP
#define DHCP_DISCOVER_RETRIES 2
#define DHCP_REQUEST_RETRIES 2
#endif

/* Hardware debug: define for verbose GEM / MDIO / DHCP logging. */
/* #define DEBUG_HW */

#endif /* WOLF_CONFIG_H */
Loading
Loading