Skip to content

Commit 45d9a78

Browse files
committed
Zynq-7000 port scaffold (Cortex-A9 ARMv7-A, GICv2, Cadence GEM) - untested
1 parent e88aec8 commit 45d9a78

20 files changed

Lines changed: 2753 additions & 0 deletions

src/port/zynq7000/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.o
2+
*.elf
3+
*.bin
4+
BOOT.BIN

src/port/zynq7000/Makefile

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Xilinx Zynq-7000 (Cortex-A9, ARMv7-A 32-bit) wolfIP bare-metal port
2+
#
3+
# Build: make CROSS_COMPILE=arm-none-eabi-
4+
#
5+
# Toolchain: ARM GNU arm-none-eabi-gcc (tested with 13.2).
6+
#
7+
# UNTESTED ON HARDWARE -- structural scaffold mirroring src/port/zcu102/.
8+
9+
CROSS_COMPILE ?= arm-none-eabi-
10+
CC := $(CROSS_COMPILE)gcc
11+
OBJCOPY := $(CROSS_COMPILE)objcopy
12+
SIZE := $(CROSS_COMPILE)size
13+
14+
ROOT := ../../..
15+
16+
# Cortex-A9, ARMv7-A 32-bit, no NEON in cert paths.
17+
CFLAGS := -mcpu=cortex-a9 -marm
18+
CFLAGS += -Os -ffreestanding -fno-builtin -fno-common
19+
CFLAGS += -fdata-sections -ffunction-sections
20+
CFLAGS += -g -Wall -Wextra -Werror -Wno-unused-parameter
21+
CFLAGS += -std=gnu99
22+
CFLAGS += -I. -I$(ROOT) -I$(ROOT)/src -I$(ROOT)/src/port
23+
CFLAGS += -DZYNQ7000 -DXILINX_ARMV7
24+
CFLAGS += $(CFLAGS_EXTRA)
25+
26+
ASFLAGS := -mcpu=cortex-a9 -marm
27+
28+
LDSCRIPT := target.ld
29+
LDFLAGS := -nostdlib -nostartfiles -T $(LDSCRIPT) -Wl,-gc-sections
30+
# Override newlib's memset/memcpy with bytewise variants in main.c
31+
# (the same "fast memset uses an instruction the bare-metal setup
32+
# does not tolerate" pattern we hit on the AArch64 port).
33+
LDFLAGS += -Wl,--wrap=memset -Wl,--wrap=memcpy
34+
35+
LOCAL_C := main.c uart.c mmu.c gic.c gem.c phy_dp83867.c entropy.c
36+
LOCAL_S := startup.S
37+
LOCAL_OBJS := $(LOCAL_C:.c=.o) $(LOCAL_S:.S=.o)
38+
39+
WOLFIP_OBJ := wolfip.o
40+
OBJS := $(LOCAL_OBJS) $(WOLFIP_OBJ)
41+
42+
all: app.elf
43+
@echo "Built: app.elf"
44+
@$(SIZE) app.elf
45+
46+
app.elf: $(OBJS) $(LDSCRIPT)
47+
$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) \
48+
-Wl,--start-group -lc -lgcc -Wl,--end-group -o $@
49+
50+
$(WOLFIP_OBJ): $(ROOT)/src/wolfip.c
51+
$(CC) $(CFLAGS) -Wno-zero-length-bounds -Wno-type-limits -c $< -o $@
52+
53+
%.o: %.c
54+
$(CC) $(CFLAGS) -c $< -o $@
55+
56+
%.o: %.S
57+
$(CC) $(ASFLAGS) -c $< -o $@
58+
59+
clean:
60+
rm -f $(OBJS) app.elf BOOT.BIN
61+
62+
.PHONY: all clean help
63+
64+
help:
65+
@echo "Zynq-7000 wolfIP build (scaffold, untested):"
66+
@echo " make - build app.elf"
67+
@echo " make clean - remove artifacts"
68+
@echo ""
69+
@echo "Override CROSS_COMPILE if your toolchain prefix differs."

src/port/zynq7000/README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# wolfIP port: Xilinx Zynq-7000 (Cortex-A9, ARMv7-A 32-bit)
2+
3+
**STATUS: UNTESTED ON HARDWARE.** Structural scaffold mirroring `src/port/zcu102/`. The code compiles cleanly with `arm-none-eabi-gcc` but has not been brought up on a real Zynq-7000 board.
4+
5+
## What this port is
6+
7+
Bare-metal wolfIP port for the Xilinx Zynq-7000 family (Z-7020 etc., e.g. ZC702 / ZedBoard / MicroZed dev boards). Cortex-A9 in SVC mode, GCC bare-metal, no Xilinx Standalone BSP, no FreeRTOS. Targets the same deterministic UDP/IPv4 profile as the ZCU102 port.
8+
9+
## What differs from ZCU102
10+
11+
| Subsystem | ZCU102 (ZynqMP) | Zynq-7000 | Where it lives |
12+
|-----------|-----------------|-----------|----------------|
13+
| Architecture | ARMv8-A AArch64 | ARMv7-A 32-bit | toolchain prefix |
14+
| CPU core | Cortex-A53 | Cortex-A9 | `Makefile` (-mcpu) |
15+
| Bootloader handoff | FSBL -> EL3 | FSBL -> SVC | `startup.S` |
16+
| Toolchain | `aarch64-none-elf-gcc` | `arm-none-eabi-gcc` | `Makefile` |
17+
| Exception model | EL3 vectors | ARMv7 exception modes | `startup.S` rewritten |
18+
| MMU | 4-level long descriptor | 1-level short descriptor | `mmu.c` rewritten |
19+
| Cache ops | DC CVAC / DC IVAC | MCR p15 c7 (DCCMVAC/DCIMVAC) | `gem.c` |
20+
| Generic timer | `mrs cntpct_el0` | `mrrc p15, 0, ..., c14` | `timer.h`, `entropy.c` |
21+
| GIC | GIC-400 (GICv2) | GIC-390 (GICv2) | `gic.c` (same driver, different base) |
22+
| GIC base addrs | `0xF901xxxx` | `0xF8F0xxxx` | `board.h` |
23+
| UART | Cadence at 0xFF000000 | Cadence at 0xE0000000 | `board.h` (same driver) |
24+
| Clock + reset | CRL_APB at 0xFF5E0000 | SLCR at 0xF8000000 | `board.h` (gem.c clock helper needs rewrite) |
25+
| GEM count | 4 (GEM0-3) | 2 (GEM0-1) | `board.h` |
26+
| On-board RJ45 | GEM3 (INTID 95) | GEM0 (INTID 54) | `board.h` |
27+
| BD format | 8-byte (DMACR[30]=0) | 8-byte (no 64-bit option) | `gem.c` (unchanged) |
28+
29+
## Build
30+
31+
```
32+
cd src/port/zynq7000
33+
make CROSS_COMPILE=arm-none-eabi-
34+
```
35+
36+
Output: `app.elf`.
37+
38+
## Known unknowns (to validate on hardware)
39+
40+
- `gem.c` still has `NWCFG_DWIDTH_64` available; it must not be set on Zynq-7000 (the A9 AXI master path is 32-bit; the older GEM revision does not implement that bit). Confirm `GEM_NWCFG` bit 21 stays clear during bring-up.
41+
- `gem.c` clock + reset code references `SLCR_GEM0_CLK_CTRL` / `SLCR_GEM_RST_CTRL`. The actual sequence will need an unlock (`SLCR_UNLOCK = 0xDF0D`) wrapper that does not exist in the AArch64 port.
42+
- DP83867 MDIO address on Zynq-7000 boards varies (ZedBoard uses a Marvell 88E1518; ZC702 / MicroZed differ). The shipped `phy_dp83867.c` only covers DP83867; confirm the actual on-board PHY before flashing.
43+
- `entropy.c` uses ARMv7 `MRRC p15, 1, ..., c14` for `cntvct_el0` (virtual counter). Cortex-A9 implements the generic timer differently from later cores; if `CNTFRQ` reads 0 the fallback (333 MHz) may be way off, causing `delay_us` to misbehave. Check `CNTFRQ` first thing during bring-up.
44+
- ARMv7 IRQ trampoline in `startup.S` uses `srsdb` + `rfeia` -- standard but assumes the IRQ-mode stack is reachable; an early IRQ before SVC stack init would fault. The current code disables IRQ until `irq_enable` is called after wolfIP/GEM init, which avoids the race.
45+
- `mmu.c` uses 1 MB sections (16 KB L1 table). All of DDR (1 GB) is mapped Normal-WB cacheable; the OCM high mapping at 0xFFFC0000 is in section 0xFFF mapped Normal-WB. PS peripherals are Device. The DMA carve-out logic from the AArch64 port is dropped because cache_clean/cache_inval handles coherency; reintroduce if the GEM exhibits coherency issues.
46+
47+
## What was reused unchanged from ZCU102
48+
49+
- `gem.c` core logic (BD ring, ISR, eth_send, eth_poll, MDIO) -- only the cache ops were rewritten for ARMv7 CP15.
50+
- `phy_dp83867.c` -- the DP83867 driver is host-architecture-independent.
51+
- `main.c` -- mostly identical; the AArch64-specific `exception_report` was dropped, the DEBUG_GIC self-test was `#if 0`-ed pending ARMv7 equivalents.
52+
- `entropy.c` -- only the timer-read primitive was rewritten.
53+
54+
## Files
55+
56+
Same layout as `src/port/zcu102/`. See that port's README for per-file responsibilities.

src/port/zynq7000/board.h

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/* board.h
2+
*
3+
* Copyright (C) 2026 wolfSSL Inc.
4+
*
5+
* This file is part of wolfIP TCP/IP stack.
6+
*
7+
* wolfIP is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfIP is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*
21+
* Xilinx Zynq-7000 (Cortex-A9, ARMv7-A 32-bit) PS register base
22+
* addresses and GIC interrupt IDs. Derived from the Zynq-7000 TRM
23+
* (UG585). No Xilinx Standalone BSP header is required.
24+
*
25+
* UNTESTED ON HARDWARE -- code-only scaffold while the lab board is
26+
* unavailable. Mirrors src/port/zcu102/ structurally. Key differences:
27+
* - Cortex-A9 (not A53), ARMv7-A 32-bit (not AArch64)
28+
* - SLCR replaces ZynqMP's CRL_APB
29+
* - GIC-390 (GICv2) inside the SCU at different base addresses
30+
* - Cadence UART (same IP as ZynqMP; different base address)
31+
* - Cadence GEM (older revision; 32-bit BD format default)
32+
* - 2 GEMs (GEM0 / GEM1); on-board RJ45 is typically GEM0
33+
*/
34+
#ifndef ZYNQ7000_BOARD_H
35+
#define ZYNQ7000_BOARD_H
36+
37+
#include <stdint.h>
38+
39+
/* ---------------------------------------------------------------------
40+
* Memory map (Zynq-7000 PS)
41+
* ------------------------------------------------------------------- */
42+
#define DDR_BASE 0x00000000UL
43+
#define DDR_SIZE 0x40000000UL /* 1 GB typical, e.g. ZC702 */
44+
45+
/* OCM is mappable to 0x00000000 (low) or 0xFFFC0000 (high). Most
46+
* bare-metal apps use the high mapping; FSBL configures the OCM
47+
* address filter via SLCR.OCM_CFG. We assume the high mapping. */
48+
#define OCM_BASE 0xFFFC0000UL
49+
#define OCM_SIZE 0x00040000UL /* 256 KB */
50+
51+
/* ---------------------------------------------------------------------
52+
* PS peripherals
53+
* ------------------------------------------------------------------- */
54+
#define UART0_BASE 0xE0000000UL /* Cadence */
55+
#define UART1_BASE 0xE0001000UL
56+
57+
#define GEM0_BASE 0xE000B000UL /* on-board RJ45 typical */
58+
#define GEM1_BASE 0xE000C000UL
59+
60+
#define SLCR_BASE 0xF8000000UL /* clock + reset */
61+
62+
/* GIC-390 (ARMv7 GICv2 compatible). Distributor + CPU IF are in the
63+
* SCU (Snoop Control Unit) memory region on Zynq-7000. */
64+
#define GICD_BASE 0xF8F01000UL
65+
#define GICC_BASE 0xF8F00100UL
66+
67+
/* ---------------------------------------------------------------------
68+
* GIC interrupt IDs (raw GIC INTIDs, not GIC_SPI offsets).
69+
* Per Zynq-7000 TRM Table 7-3:
70+
* GEM0: INTID 54
71+
* GEM1: INTID 77
72+
* ------------------------------------------------------------------- */
73+
#define IRQ_GEM0 54
74+
#define IRQ_GEM1 77
75+
76+
/* ---------------------------------------------------------------------
77+
* SLCR clock and reset registers
78+
* ------------------------------------------------------------------- */
79+
#define SLCR_LOCK (SLCR_BASE + 0x004)
80+
#define SLCR_UNLOCK (SLCR_BASE + 0x008)
81+
#define SLCR_GEM0_CLK_CTRL (SLCR_BASE + 0x140)
82+
#define SLCR_GEM1_CLK_CTRL (SLCR_BASE + 0x144)
83+
#define SLCR_GEM_RST_CTRL (SLCR_BASE + 0x214)
84+
85+
#define SLCR_UNLOCK_KEY 0xDF0D /* per TRM */
86+
87+
/* ---------------------------------------------------------------------
88+
* Cadence UART0 baud
89+
* ------------------------------------------------------------------- */
90+
#define UART_BAUD 115200
91+
92+
/* MAC address for eth0. Locally-administered, even first octet. */
93+
#ifndef WOLFIP_MAC_0
94+
#define WOLFIP_MAC_0 0x02
95+
#endif
96+
#ifndef WOLFIP_MAC_1
97+
#define WOLFIP_MAC_1 0x00
98+
#endif
99+
#ifndef WOLFIP_MAC_2
100+
#define WOLFIP_MAC_2 0x5A
101+
#endif
102+
#ifndef WOLFIP_MAC_3
103+
#define WOLFIP_MAC_3 0x11
104+
#endif
105+
#ifndef WOLFIP_MAC_4
106+
#define WOLFIP_MAC_4 0x22
107+
#endif
108+
#ifndef WOLFIP_MAC_5
109+
#define WOLFIP_MAC_5 0x33
110+
#endif
111+
112+
#endif /* ZYNQ7000_BOARD_H */

src/port/zynq7000/config.h

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/* config.h
2+
*
3+
* Copyright (C) 2026 wolfSSL Inc.
4+
*
5+
* This file is part of wolfIP TCP/IP stack.
6+
*
7+
* wolfIP is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfIP is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*
21+
* wolfIP configuration for Xilinx ZCU102 (UltraScale+ MPSoC, A53-0 EL3
22+
* bare-metal). UDP-only profile aimed at deterministic DAL-C use.
23+
*/
24+
#ifndef WOLF_CONFIG_H
25+
#define WOLF_CONFIG_H
26+
27+
#ifndef CONFIG_IPFILTER
28+
#define CONFIG_IPFILTER 0
29+
#endif
30+
31+
#define ETHERNET
32+
#define LINK_MTU 1536
33+
34+
/* UDP-only profile in intent: the application does not call
35+
* wolfIP_sock_socket() with IPSTACK_SOCK_STREAM. MAX_TCPSOCKETS is set
36+
* to a small non-zero value only because core wolfIP currently sizes
37+
* its timer heap via MAX_TIMERS = MAX_TCPSOCKETS * 3, and DHCP / ARP
38+
* aging need timers. With MAX_TCPSOCKETS=0 the timer-heap insert path
39+
* is permanently full and DHCP cannot schedule its retransmit timer.
40+
* A core wolfIP follow-up should decouple MAX_TIMERS from
41+
* MAX_TCPSOCKETS so DAL-C builds can truly opt TCP code out at
42+
* compile time. */
43+
#define MAX_TCPSOCKETS 2
44+
#define MAX_UDPSOCKETS 4
45+
#define MAX_ICMPSOCKETS 1
46+
#define RXBUF_SIZE (LINK_MTU * 4)
47+
#define TXBUF_SIZE (LINK_MTU * 4)
48+
49+
#define MAX_NEIGHBORS 16
50+
51+
#ifndef WOLFIP_MAX_INTERFACES
52+
#define WOLFIP_MAX_INTERFACES 1
53+
#endif
54+
55+
#ifndef WOLFIP_ENABLE_FORWARDING
56+
#define WOLFIP_ENABLE_FORWARDING 0
57+
#endif
58+
59+
#ifndef WOLFIP_ENABLE_LOOPBACK
60+
#define WOLFIP_ENABLE_LOOPBACK 0
61+
#endif
62+
63+
#ifndef WOLFIP_ENABLE_DHCP
64+
#define WOLFIP_ENABLE_DHCP 1
65+
#endif
66+
67+
/* Static IP fallback (used if DHCP is disabled or times out). */
68+
#define WOLFIP_IP "192.168.1.100"
69+
#define WOLFIP_NETMASK "255.255.255.0"
70+
#define WOLFIP_GW "192.168.1.1"
71+
#define WOLFIP_STATIC_DNS_IP "8.8.8.8"
72+
73+
#if WOLFIP_ENABLE_DHCP
74+
#define DHCP
75+
#define DHCP_DISCOVER_RETRIES 2
76+
#define DHCP_REQUEST_RETRIES 2
77+
#endif
78+
79+
/* Hardware debug: define for verbose GEM / MDIO / DHCP logging. */
80+
/* #define DEBUG_HW */
81+
82+
#endif /* WOLF_CONFIG_H */

0 commit comments

Comments
 (0)