Add Zynq-7000 PS boot over JTAG (OpenOCD, no FSBL/bitstream)
Boot minos on the real Zynq-7020 PS (Cortex-A9) without Vivado, an FSBL,
a bitstream, or DDR init — loaded straight into on-chip RAM over JTAG.
- link-zynq-ocm.ld: link the ARM build into OCM (0x0, 192 KiB), which is
alive from reset, so no FSBL/ps7_init and no DDR are needed.
- zynq/openocd-zynq.cfg: OpenOCD config for the on-board FT2232H. Its
EEPROM reports a generic 0403:6010 ("Adapt Device"), which Xilinx
hw_server refuses to auto-detect but OpenOCD drives directly; it sees
the full chain (PL boundary-scan 0x23727093 + ARM DAP 0x4ba00477).
- Makefile: 'zynq' builds the OCM ELF; 'run-zynq' halts A9 core0, loads
the image, and resumes.
The one non-obvious step: the on-board boot firmware leaves the core with
MMU + D-cache + I-cache enabled, which shadow the freshly loaded OCM and
make a plain resume run nothing. run-zynq clears SCTLR to 0x08C54C78 and
forces SVC mode before resuming. Halting (not resetting) keeps the
firmware's PS clock setup so the UART stays live.
Verified on hardware: banner once, then live keystroke echo over the
UART console (ttyUSB1 @115200). Same shared C core now boots on real
RISC-V (D1) and real ARM (Zynq) silicon, plus QEMU x86/riscv/arm.
This commit is contained in:
parent
775a02cf3f
commit
d97f0c0757
3 changed files with 102 additions and 0 deletions
46
Makefile
46
Makefile
|
|
@ -106,5 +106,51 @@ run-lichee: build/lichee/minos.bin
|
|||
$(XFEL) exec 0x40000000
|
||||
@echo "== running. Watch /dev/ttyUSB0 @115200 for output. =="
|
||||
|
||||
# --- real hardware: Zynq-7000 PS (Cortex-A9) via JTAG/OpenOCD ----------------
|
||||
# Same ARM sources, re-linked into on-chip RAM (OCM at 0x0) so no FSBL/DDR
|
||||
# init is needed. Loaded over JTAG with OpenOCD (the on-board FT2232H is a
|
||||
# generic 0403:6010 that Xilinx hw_server won't auto-detect, but OpenOCD does).
|
||||
OPENOCD ?= openocd
|
||||
OOCD_CFG := zynq/openocd-zynq.cfg
|
||||
ZYNQ_OBJS := $(patsubst %,build/zynq/%.o,$(basename $(notdir $(arm_SRC))))
|
||||
|
||||
build/zynq/%.o: arch/arm/%.S | build/zynq
|
||||
$(CC) $(arm_TARGET) $(CFLAGS) -c $< -o $@
|
||||
build/zynq/%.o: arch/arm/%.c | build/zynq
|
||||
$(CC) $(arm_TARGET) $(CFLAGS) -c $< -o $@
|
||||
build/zynq/%.o: common/%.c | build/zynq
|
||||
$(CC) $(arm_TARGET) $(CFLAGS) -c $< -o $@
|
||||
build/zynq:
|
||||
mkdir -p $@
|
||||
|
||||
build/zynq/minos.elf: $(ZYNQ_OBJS) arch/arm/link-zynq-ocm.ld
|
||||
$(LD) -m $(arm_LDEMU) -T arch/arm/link-zynq-ocm.ld -nostdlib $(ZYNQ_OBJS) -o $@
|
||||
@echo " [zynq] OCM ELF -> $@"
|
||||
|
||||
.PHONY: zynq run-zynq
|
||||
zynq: build/zynq/minos.elf ## build the Zynq OCM ELF
|
||||
|
||||
# Halt A9 core0, load the ELF into OCM, set PC to _start, resume.
|
||||
# Watch the UART console (ttyUSB1 @115200) for output.
|
||||
#
|
||||
# Critical: the on-board boot firmware leaves the core with MMU + D-cache +
|
||||
# I-cache enabled (SCTLR bits 0/2/12). If we resume like that, the stale
|
||||
# TLB/cache shadow our freshly loaded OCM and nothing runs. So we clear those
|
||||
# bits (SCTLR -> 0x08C54C78) and force SVC mode before resuming. We keep the
|
||||
# firmware's PS clock setup (incl. UART) by halting rather than resetting.
|
||||
run-zynq: build/zynq/minos.elf
|
||||
@echo "== loading minos into Zynq OCM via OpenOCD =="
|
||||
$(OPENOCD) -f $(OOCD_CFG) \
|
||||
-c "init" \
|
||||
-c "targets zynq.cpu0" \
|
||||
-c "halt" \
|
||||
-c "load_image build/zynq/minos.elf" \
|
||||
-c "arm mcr 15 0 1 0 0 0x08C54C78" \
|
||||
-c "reg pc 0x00000000" \
|
||||
-c "reg cpsr 0x000001d3" \
|
||||
-c "resume" \
|
||||
-c "shutdown"
|
||||
@echo "== running. Watch /dev/ttyUSB1 @115200 for output. =="
|
||||
|
||||
clean:
|
||||
rm -rf build
|
||||
|
|
|
|||
40
arch/arm/link-zynq-ocm.ld
Normal file
40
arch/arm/link-zynq-ocm.ld
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* link-zynq-ocm.ld (ARM, Zynq-7000 real hardware via JTAG) —
|
||||
*
|
||||
* On real Zynq the external DDR is NOT usable until an FSBL/ps7_init runs.
|
||||
* The on-chip RAM (OCM), however, is alive from reset: 192 KiB mapped at
|
||||
* 0x00000000..0x0002FFFF. We link minos entirely into that low OCM so it
|
||||
* can be loaded straight over JTAG (OpenOCD) with no FSBL and no DDR init.
|
||||
*
|
||||
* We keep the PS clocks that the on-board boot firmware already configured
|
||||
* by HALTing the A9 (not resetting the whole PS) before loading, so the
|
||||
* UART remains clocked. QEMU still uses link.ld (DDR at 0x00100000). */
|
||||
OUTPUT_FORMAT(elf32-littlearm)
|
||||
ENTRY(_start)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
OCM (rwx) : ORIGIN = 0x00000000, LENGTH = 192K
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x00000000;
|
||||
|
||||
.text : {
|
||||
KEEP(*(.text.boot)) /* _start must be first */
|
||||
*(.text .text.*)
|
||||
} > OCM
|
||||
|
||||
.rodata : { *(.rodata .rodata.*) } > OCM
|
||||
.data : { *(.data .data.*) } > OCM
|
||||
|
||||
. = ALIGN(8);
|
||||
__bss_start = .;
|
||||
.bss : { *(.bss .bss.*) *(COMMON) } > OCM
|
||||
. = ALIGN(8);
|
||||
__bss_end = .;
|
||||
|
||||
. = ALIGN(16);
|
||||
. += 0x4000; /* 16 KiB boot stack */
|
||||
_stack_top = .;
|
||||
}
|
||||
16
zynq/openocd-zynq.cfg
Normal file
16
zynq/openocd-zynq.cfg
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# OpenOCD config for the on-board FT2232H JTAG on this Zynq-7000 board.
|
||||
# The EEPROM identifies as VID:PID 0403:6010 ("Adapt Device"), a generic
|
||||
# FT2232H that Xilinx hw_server refuses to auto-detect but OpenOCD drives
|
||||
# directly. JTAG is FTDI channel 0; channel 1 is the UART console.
|
||||
|
||||
adapter driver ftdi
|
||||
ftdi vid_pid 0x0403 0x6010
|
||||
ftdi channel 0
|
||||
# Standard FT2232H JTAG pin layout (TCK/TDI/TDO/TMS on ADBUS0-3).
|
||||
ftdi layout_init 0x0088 0x008b
|
||||
reset_config none
|
||||
|
||||
adapter speed 1000
|
||||
|
||||
# Zynq-7000 PS (dual Cortex-A9) + PL boundary-scan TAP.
|
||||
source [find target/zynq_7000.cfg]
|
||||
Loading…
Add table
Add a link
Reference in a new issue