Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion .github/workflows/codespell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ jobs:
uses: codespell-project/actions-codespell@v2
with:
skip: .git,./IDE,*.der,*.pem
ignore_words_list: inh,inout,keypair,nd,parm,rcv,ser,tha,HSI,TE,UE,Synopsys,synopsys,FRO,ehr
ignore_words_list: inh,inout,keypair,nd,parm,rcv,ser,tha,HSI,TE,UE,Synopsys,synopsys,FRO,ehr,EMAC,emac
9 changes: 9 additions & 0 deletions src/port/pic32mz/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Build artifacts
*.o
app.elf
app.hex
app.map
# MDB / IPE transient files
mdb_flash.cmd
MPLABXLog.*
log.*
110 changes: 110 additions & 0 deletions src/port/pic32mz/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# wolfIP PIC32MZ EF port - build with Microchip XC32
#
# Copyright (C) 2026 wolfSSL Inc. Part of the wolfIP TCP/IP stack (GPLv3).
#
# Phase 0: clocks + UART2 console + heartbeat.
# Phase 1: wolfCrypt PIC32MZ hardware TRNG self-test.
# Phase 2: MDIO + LAN8740 PHY link bring-up.
# (Full Ethernet RX/TX driver + wolfIP core are added in later phases.)
#
# Usage:
# make # build app.hex
# make flash # program over the on-board debugger (v6.20 IPE)
# make clean
# Overridable:
# XC32_BIN= XC32 bin dir (default /opt/microchip/xc32/v5.10/bin)
# DFP= device family pack version dir
# DEVICE= 32MZ2048EFM144
# WOLFSSL_ROOT= path to wolfssl checkout (used from Phase 1 on)
# MDB= MPLAB X MDB CLI (default v6.20; v6.30 dropped the EF SK debugger)

XC32_BIN ?= /opt/microchip/xc32/v5.10/bin
DFP ?= /opt/microchip/mplabx/v6.30/packs/Microchip/PIC32MZ-EF_DFP/1.5.173
DEVICE ?= 32MZ2048EFM144

CC := $(XC32_BIN)/xc32-gcc
BIN2HEX := $(XC32_BIN)/xc32-bin2hex
SIZE := $(XC32_BIN)/xc32-size

# Flashing via MDB (Microchip DeBugger CLI). The headless ipecmd cannot resolve
# device packs ("Unable to locate DFP"), but MDB launches the full platform and
# resolves them like the IDE/IPE GUI does. Default tool is an MPLAB ICD 5 on the
# ICSP header; the EF Starter Kit's flaky on-board debugger (MDB tool type "sk",
# only in v6.20) proved unreliable over USB, so an external debugger is preferred.
MDB ?= /opt/microchip/mplabx/v6.30/mplab_platform/bin/mdb.sh
MDB_DEVICE ?= PIC32MZ2048EFM144
MDB_TOOL ?= icd5

ROOT := ../../..
# Default to a wolfssl checkout sitting beside the wolfip repo.
WOLFSSL_ROOT ?= $(ROOT)/../wolfssl

Comment thread
dgarske marked this conversation as resolved.
# -O1 is available in the free XC32 edition (-O2/-Os/-O3 need a PRO license).
CFLAGS := -mprocessor=$(DEVICE) -mdfp="$(DFP)"
CFLAGS += -O1 -g -Wall -Wextra -ffunction-sections -fdata-sections
CFLAGS += -I. -I$(ROOT) -I$(ROOT)/src
CFLAGS += -DWOLFSSL_USER_SETTINGS -I$(WOLFSSL_ROOT)
CFLAGS += $(EXTRA_CFLAGS)

# Heap for the Hash-DRBG (wc_InitRng allocates the DRBG state).
LDFLAGS := -mprocessor=$(DEVICE) -mdfp="$(DFP)"
LDFLAGS += -Wl,--defsym,_min_heap_size=0x8000
LDFLAGS += -Wl,--gc-sections -Wl,-Map=app.map,--cref

# Port + application sources (strict warnings)
APP_SRCS := device_config.c clock_init.c uart_console.c timebase.c \
wolf_compat.c rng_selftest.c pic32mz_eth.c phy_lan8740.c main.c
APP_OBJS := $(patsubst %.c,%.o,$(APP_SRCS))

# wolfcrypt sources for the RNG self-test (compiled with relaxed warnings).
# Pulled directly from the sibling wolfssl checkout, no copy.
WC_SRC := $(WOLFSSL_ROOT)/wolfcrypt/src
WC_NAMES := random sha256 hash wc_port logging memory error
WC_OBJS := $(addsuffix .o,$(addprefix wc_,$(WC_NAMES)))
CFLAGS_WC := -mprocessor=$(DEVICE) -mdfp="$(DFP)" -O1 -g \
-ffunction-sections -fdata-sections \
-DWOLFSSL_USER_SETTINGS -I. -I$(WOLFSSL_ROOT)

# wolfIP core stack (relaxed warnings; does not need wolfssl).
CFLAGS_CORE := -mprocessor=$(DEVICE) -mdfp="$(DFP)" -O1 -g \
-ffunction-sections -fdata-sections -I. -I$(ROOT) -I$(ROOT)/src

ALL_OBJS := $(APP_OBJS) wolfip.o $(WC_OBJS)

all: app.hex
@echo "Built PIC32MZ wolfIP port"
@$(SIZE) app.elf

app.elf: $(ALL_OBJS)
$(CC) $(CFLAGS) $(ALL_OBJS) $(LDFLAGS) -o $@

app.hex: app.elf
$(BIN2HEX) $<

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

wc_%.o: $(WC_SRC)/%.c
$(CC) $(CFLAGS_WC) -c $< -o $@

wolfip.o: $(ROOT)/src/wolfip.c
$(CC) $(CFLAGS_CORE) -c $< -o $@

# Program the hex over an MPLAB ICD 5 (on the ICSP/debug header) via MDB. Close
# the MPLAB X IPE/IDE GUI first so it isn't holding the tool. Command script:
# set programoptions.eraseb4program true -> full chip erase before program
# hwtool icd5 -p -> connect the ICD 5 for programming
# program <app.hex> / Reset -> program, then release from reset
# The trailing "Reset" is required: -p alone leaves the target held in reset.
# The ICD 5 connects to the target's ICSP/debug header; select a different
# supported tool with MDB_TOOL= (e.g. icd4, pickit4, snap). See Microchip's
# MPLAB ICD 5 User's Guide for connection and wiring details.
flash: app.hex
@printf 'device %s\nset programoptions.eraseb4program true\nhwtool %s -p\nprogram %s\nReset\nquit\n' \
"$(MDB_DEVICE)" "$(MDB_TOOL)" "$(CURDIR)/app.hex" > mdb_flash.cmd
cd $(dir $(MDB)) && sh ./$(notdir $(MDB)) $(CURDIR)/mdb_flash.cmd

clean:
rm -f *.o app.elf app.hex app.map mdb_flash.cmd MPLABXLog.* log.*

.PHONY: all clean flash
81 changes: 81 additions & 0 deletions src/port/pic32mz/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# wolfIP PIC32MZ EF Port

Bare-metal [wolfIP](../../../README.md) port for the **Microchip PIC32MZ EF**
(PIC32MZ2048EFM144, MIPS32 M-class) with a **LAN8740** PHY over RMII. Built
with the Microchip XC32 toolchain; no MPLAB X project or Harmony framework
required. Also exercises wolfCrypt's built-in hardware TRNG
(`WOLFSSL_PIC32MZ_RNG`).

## Hardware

- **MCU:** PIC32MZ2048EFM144 (200 MHz, 2 MB flash, 512 KB RAM), EF Starter Kit.
- **PHY:** LAN8740 daughter board over RMII (PHY drives the 50 MHz reference clock).
- **Console:** UART2, `U2TX` on RPB14 / `U2RX` on RPG6, 115200 8N1.
- **Programmer:** MPLAB ICD 5 on the ICSP/debug header; program with `make flash` (see the Makefile `flash` target, which drives the ICD 5 over MDB).

## Layout

| File | Purpose |
|------|---------|
| `device_config.c` | DEVCFG config words: 200 MHz PLL (POSC EC 24 MHz), RMII, watchdog off. |
| `clock_init.c/.h` | Flash wait-states + prefetch. Reusable early bring-up (wolfBoot). |
| `cache.h` | MIPS KSEG0/KSEG1 + virtual/physical helpers for DMA memory. |
| `uart_console.c/.h` | UART2 console + XC32 `_mon_putc` `printf` retarget. |
| `timebase.c/.h` | 64-bit `millis()` from the CP0 core timer. |
| `pic32mz_eth.c/.h` | EMAC + RMII + MDIO bring-up, DMA descriptor rings, `poll`/`send`. |
| `phy_lan8740.c/.h` | MAC-agnostic clause-22 LAN8740 driver (scan, autoneg, link). |
| `rng_selftest.c/.h` | wolfCrypt hardware-TRNG self-test. |
| `user_settings.h` | wolfCrypt configuration (`WOLFSSL_MICROCHIP_PIC32MZ`). |
| `config.h` | wolfIP profile (MTU, socket counts, DHCP). |
| `main.c` | TRNG self-test, DHCP, and a TCP echo / throughput server. |

## Build

Requires XC32 (>= v5.10) and the PIC32MZ-EF DFP, plus a wolfssl checkout beside
the wolfip repo (override with `WOLFSSL_ROOT=`).

```sh
make # -> app.hex
make SPEED_TEST=1 EXTRA_CFLAGS=-DSPEED_TEST # throughput server on port 9
make flash # program over MPLAB ICD 5 (MDB)
make clean
```

Overridable: `XC32_BIN`, `DFP`, `DEVICE`, `WOLFSSL_ROOT`, `MDB`, `MDB_TOOL`.

## Test

Console at 115200 8N1. On boot the firmware prints the banner, the RNG
self-test result, the resolved PHY link, and (once bound) the DHCP address:

```
=== wolfIP PIC32MZ EF port ===
[RNG] self-test: PASS
Ethernet init (LAN8740 over RMII)...
DHCP bound: 10.0.4.x
TCP service listening on port 7
```

Then, from a host on the same network:

```sh
ping <ip>
echo hello | nc <ip> 7 # echo (default build)
dd if=/dev/zero bs=1460 count=700 | nc <ip> 9 # RX throughput (SPEED_TEST build)
nc <ip> 9 </dev/null | pv >/dev/null # TX throughput (SPEED_TEST build)
```

## Notes

- DMA descriptors/buffers use XC32 `__attribute__((coherent))` (uncached), so
no cache maintenance is needed; the EMAC is given physical addresses.
- The Ethernet module needs PBCLK5 enabled and `PMD6.ETHMD` cleared before any
EMAC register access — `pic32mz_emac_mii_init()` does this first.
- The PIC32 Ethernet DMA descriptor is 4 words (16 bytes): header, buffer
address, and two words the DMA writes back. The received frame length comes
from the status word (`status & 0xFFFF`), not the header.
- The echo server holds transfers in the per-socket buffers
(`RXBUF_SIZE`/`TXBUF_SIZE`), so a single burst larger than that will stall
the simple echo callback; raise the buffers or use the throughput server
(`-DSPEED_TEST`) for large streams.
- Build with `EXTRA_CFLAGS=-DPIC32_ETH_TRACE` to trace the EMAC bring-up.
38 changes: 38 additions & 0 deletions src/port/pic32mz/board.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* board.h
*
* Board constants for the PIC32MZ EF Starter Kit (DM320007) + LAN8740 PHY DB.
*
* 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
*/
#ifndef PIC32MZ_BOARD_H
#define PIC32MZ_BOARD_H

/* Clock tree (set by DEVCFG config words at reset; see device_config.c) */
#define SYS_CLK_FREQ 200000000ul /* SYSCLK from SPLL */
#define PBCLK2_FREQ 100000000ul /* peripheral bus 2 (UART) = SYSCLK/2 */
#define PBCLK5_FREQ 100000000ul /* peripheral bus 5 (EMAC) = SYSCLK/2 */

/* Console UART: U2TX on RPB14, U2RX on RPG6 (external MCP2221 USB-UART) */
#define CONSOLE_BAUD 115200u

/* On-board LEDs LED1/LED2/LED3 on RH0/RH1/RH2 (active high) */
#define LED_MASK 0x0007u
#define LED_HEARTBEAT 0x0001u /* LED1 = RH0 */

#endif /* PIC32MZ_BOARD_H */
51 changes: 51 additions & 0 deletions src/port/pic32mz/cache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* cache.h
*
* MIPS KSEG segment helpers for DMA-coherent access on PIC32MZ.
*
* 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
*/
#ifndef PIC32MZ_CACHE_H
#define PIC32MZ_CACHE_H

#include <stdint.h>

/* The PIC32MZ Ethernet controller (EMAC) is not cache-coherent and programs
* its descriptor base/buffer pointers with PHYSICAL addresses. The simplest
* coherent scheme on MIPS is to access all descriptor rings and DMA buffers
* through KSEG1 (uncached) virtual aliases and hand the EMAC the physical
* address. This avoids per-operation cache clean/invalidate entirely.
*
* Equivalent to XC32 <sys/kmem.h> KVA0_TO_KVA1 / KVA_TO_PA / PA_TO_KVA1, but
* kept self-contained so the early bare-metal layer can be lifted into
* wolfBoot without pulling in the XC32 system headers.
*/

/* Cached KSEG0 virtual address -> uncached KSEG1 virtual address */
#define PIC32_KVA0_TO_KVA1(v) (((uint32_t)(v)) | 0x20000000u)

/* Any KSEG0/KSEG1 virtual address -> physical address (for the EMAC) */
#define PIC32_KVA_TO_PA(v) (((uint32_t)(v)) & 0x1FFFFFFFu)

/* Physical address -> uncached KSEG1 virtual address */
#define PIC32_PA_TO_KVA1(pa) (((uint32_t)(pa)) | 0xA0000000u)

/* Pointer helper: uncached view of a normally-allocated object */
#define PIC32_UNCACHED(p) ((void *)PIC32_KVA0_TO_KVA1(p))

#endif /* PIC32MZ_CACHE_H */
37 changes: 37 additions & 0 deletions src/port/pic32mz/clock_init.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* clock_init.c
*
* 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
*/
#include <xc.h>
#include "clock_init.h"

void clock_init(void)
{
/* Flash wait-states + prefetch for 200 MHz SYSCLK.
* PFMWS = 2 wait-states is required above ~134 MHz on PIC32MZ EF.
* PREFEN = 3 enables predictive prefetch for cacheable and
* non-cacheable regions. PRECON is not lock-protected. */
PRECONbits.PFMWS = 2;
PRECONbits.PREFEN = 3;

/* Peripheral buses PBCLK2 (UART) and PBCLK5 (EMAC) remain at their
* reset default of SYSCLK/2 = 100 MHz, which is what this port targets.
* The L1 cache and KSEG0 coherency are enabled by the XC32 reset
* startup code, so nothing is done here for v1. */
}
30 changes: 30 additions & 0 deletions src/port/pic32mz/clock_init.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* clock_init.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
*/
#ifndef PIC32MZ_CLOCK_INIT_H
#define PIC32MZ_CLOCK_INIT_H

/* Configure flash wait-states / prefetch for 200 MHz operation.
* The PLL itself is brought up at reset from the DEVCFG config words
* (FNOSC=SPLL), so by the time main() runs SYSCLK is already 200 MHz.
* Bare-metal reusable (intended to be lifted into a future wolfBoot port). */
void clock_init(void);

#endif /* PIC32MZ_CLOCK_INIT_H */
Loading
Loading