diff options
| author | 2026-10-12 08:46:23 +0330 | |
|---|---|---|
| committer | 2026-10-12 08:46:23 +0330 | |
| commit | ecc350ca5c2eb50be8309c5f14f8bf0d87db9a02 (patch) | |
| tree | 70e0af76a1b13affff7c6cc8aac7b3e6ef960478 /src/baremetal/run.sh | |
a
Diffstat (limited to 'src/baremetal/run.sh')
| -rwxr-xr-x | src/baremetal/run.sh | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/src/baremetal/run.sh b/src/baremetal/run.sh new file mode 100755 index 0000000..d6ac333 --- /dev/null +++ b/src/baremetal/run.sh @@ -0,0 +1,104 @@ +#!/bin/bash +# Build a freestanding microcore and boot it on qemu-system-*. +# src/baremetal/run.sh ready riscv|aarch64 +# src/baremetal/run.sh riscv|aarch64 run examples/hello.zc +# src/baremetal/run.sh riscv|aarch64 io examples/echo.zc +# src/baremetal/run.sh riscv|aarch64 compile examples/hello.zc +# run: the program is compiled into the image. nothing is read. +# io: the same image, but stdin is the program's input and 0x04 ends it. +# compile: the default 1,048,576-word genome. the source, a backtick, and +# 0x04 are written to the UART. the backtick ends the unit; the +# 0x04 is what eof() waits for after that. +# Prints the program's UART output and nothing else. Exits 0 on a clean +# power-off. A missing toolchain exits 0 from `ready` and 1 otherwise. +set -euo pipefail +cd "$(dirname "$0")/../.." + +ready() { + case "$1" in + riscv) command -v riscv64-linux-gnu-gcc >/dev/null && command -v qemu-system-riscv64 >/dev/null ;; + aarch64) command -v aarch64-linux-gnu-gcc >/dev/null && command -v qemu-system-aarch64 >/dev/null ;; + *) return 1 ;; + esac +} + +if [ "${1:-}" = ready ]; then + ready "${2:-}" + exit $? +fi +if [ $# -ne 3 ]; then + echo "usage: src/baremetal/run.sh riscv|aarch64 run|io|compile FILE" >&2 + exit 2 +fi +target=$1 mode=$2 src=$3 +ready "$target" || { echo "baremetal: missing toolchain for $target" >&2; exit 1; } +[ -f "$src" ] || { echo "baremetal: no $src" >&2; exit 1; } + +case "$target" in +riscv) + cc=riscv64-linux-gnu-gcc + qemu=qemu-system-riscv64 + cflags="-march=rv64gc -mabi=lp64d -mcmodel=medany -mno-relax" + asm=src/baremetal/start_riscv.S + ld=src/baremetal/link_riscv.ld + def=-DBARE_RISCV + qargs=(-machine virt -bios none -cpu rv64 -m 64) + ;; +aarch64) + cc=aarch64-linux-gnu-gcc + qemu=qemu-system-aarch64 + cflags="-march=armv8-a" + asm=src/baremetal/start_aarch64.S + ld=src/baremetal/link_aarch64.ld + def=-DBARE_AARCH64 + qargs=(-machine virt -cpu cortex-a57 -m 64 -semihosting-config enable=on,target=native) + ;; +*) echo "baremetal: unknown target $target" >&2; exit 2 ;; +esac + +D=$(mktemp -d) +trap 'rm -rf "$D"' EXIT +common="$cflags -ffreestanding -fno-pic -fno-pie -fno-builtin -fno-unwind-tables -fno-asynchronous-unwind-tables -O2 -Wall -Wextra" + +if [ "$mode" = run ] || [ "$mode" = io ]; then + # the map is sized to the program, so a bigger runtime or program just gets a bigger board + gcc -O2 -w src/tools/genmap.c -o "$D/genmap" + GENMAP="$D/genmap" bash src/tools/automap.sh run "$D/img" src/runtime/run.zc "$src" >"$D/genmap.log" 2>&1 || { cat "$D/genmap.log" >&2; exit 1; } + cp src/micro/micro.c src/micro/micro_port.h src/core/fops.h src/core/bops.h src/core/stack.h "$D/img/" + "$cc" $common $def -I"$D/img" -c "$D/img/micro.c" -o "$D/micro.o" + if [ "$mode" = io ]; then + "$cc" $common $def -DBARE_INPUT=1 -I"$D/img" -c src/baremetal/port.c -o "$D/port.o" + timeout=60 + else + "$cc" $common $def -DBARE_INPUT=0 -I"$D/img" -c src/baremetal/port.c -o "$D/port.o" + timeout=120 + fi +elif [ "$mode" = compile ]; then + cp src/micro/micro.c src/micro/micro_port.h src/core/memmap.h src/core/genome.h src/core/fops.h src/core/bops.h src/core/stack.h "$D/" + "$cc" $common $def -I"$D" -c "$D/micro.c" -o "$D/micro.o" + "$cc" $common $def -DBARE_INPUT=1 -I"$D" -c src/baremetal/port.c -o "$D/port.o" + timeout=90 +else + echo "baremetal: mode is run, io or compile" >&2 + exit 2 +fi +"$cc" $common $def -c "$asm" -o "$D/start.o" +"$cc" $common $def -nostdlib -static -Wl,--build-id=none -Wl,--no-warn-rwx-segments -T "$ld" -o "$D/bare.elf" "$D/start.o" "$D/port.o" "$D/micro.o" +if [ "${BARE_SIZE:-}" = 1 ]; then + size=$(wc -c < "$D/bare.elf") + text=$(size "$D/bare.elf" | awk 'NR==2{print $1+$2}') + bss=$(size "$D/bare.elf" | awk 'NR==2{print $3}') + echo "elf $size bytes, text+data $text, bss $bss" >&2 +fi + +# -serial stdio is the UART. The monitor stays off so it cannot eat bytes. +runq() { + timeout "$timeout" "$qemu" "${qargs[@]}" -nographic -monitor none -serial stdio -kernel "$D/bare.elf" +} +if [ "$mode" = compile ]; then + (cat "$src"; printf '`\004') | runq +elif [ "$mode" = io ]; then + (cat; printf '\004') | runq +else + runq </dev/null +fi |
