diff --git a/.dockerignore b/.dockerignore index f3bb7aeb..fb0cbbbf 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,6 +3,7 @@ .gitattributes .github/ output/ +toolchain/ installer/output/ *.bin html_data.c diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7097ef48..7d85b74b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,7 +29,12 @@ jobs: - name: Install dependencies run: | apt update - apt install make gcc sdcc xxd python-is-python3 libjson-c-dev zlib1g-dev -y + apt install make gcc g++ bison flex libboost-dev patch bzip2 curl ca-certificates xxd python-is-python3 libjson-c-dev zlib1g-dev -y + - name: Cache the patched SDCC + uses: actions/cache@v4 + with: + path: branch/toolchain + key: sdcc-${{ hashFiles('branch/sdcc/*') }} - name: Run the host-side unit tests run: cd branch && make -C test - name: Check that every machine definition can be compiled @@ -41,7 +46,10 @@ jobs: - name: Make project with the health instrumentation run: cd branch && make clean && make CI=1 MACHINE="KP_9000_6XHML_X2" HEALTH=1 - name: Make main - run: cd main && make CI=1 MACHINE="KP_9000_6XHML_X2" && cp output/KP_9000_6XHML_X2/rtlplayground.map /tmp/main.map + run: | + ln -s ../branch/toolchain main/toolchain + PATH="$(echo "$PWD"/branch/toolchain/sdcc-*/bin):$PATH" + cd main && make CI=1 MACHINE="KP_9000_6XHML_X2" && cp output/KP_9000_6XHML_X2/rtlplayground.map /tmp/main.map - name: Calculate bank growth run: | sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/MAIN_\1=\3/p' /tmp/main.map | sort -u >> "$GITHUB_ENV" diff --git a/.gitignore b/.gitignore index 9f544835..e3793b25 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .idea/ output/ output-main/ +toolchain/ html_data.c html_data.h version.h diff --git a/Dockerfile b/Dockerfile index 8942883f..c0d24e9e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,14 @@ FROM debian:13-slim RUN apt-get update && apt-get install -y \ make \ gcc \ - sdcc \ + g++ \ + bison \ + flex \ + libboost-dev \ + patch \ + bzip2 \ + curl \ + ca-certificates \ xxd \ python3 \ libjson-c-dev \ diff --git a/Makefile b/Makefile index 5754ee08..90fbcebf 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,11 @@ DEFAULT_CONFIG_LOCATION = 454656 CONFIG_LOCATION = 458752 HTML_LOCATION = 262144 +SDCC_PREFIX = toolchain/sdcc-$(shell cat sdcc/* | cksum | cut -d' ' -f1) ifeq ($(origin CC),default) -CC = sdcc +SDCC = $(SDCC_PREFIX)/bin/sdcc +CC = $(SDCC) +ASM = $(SDCC_PREFIX)/bin/sdas8051 endif CC_FLAGS = -mmcs51 -I. -Imachine -Ihttpd -Iuip ASM ?= sdas8051 @@ -72,7 +75,7 @@ all: create_build_dir $(VERSION_HEADER) $(MACHINE_SRC) $(SUBDIRS) $(BUILDDIR)/rt bank_size: tools/bank_occupancy.sh "$(MACHINE)" -create_build_dir: +create_build_dir: $(SDCC) mkdir -p "$(BUILDDIR)" mkdir -p "$(BUILDDIR)/uip" mkdir -p "$(BUILDDIR)/httpd" @@ -175,6 +178,12 @@ clean: $(SUBDIRSCLEAN) distclean: $(SUBDIRSCLEAN) -rm -f html_data.c html_data.h $(VERSION_HEADER) -rm -rf $(BUILDDIR) + -rm -rf toolchain + +ifneq ($(SDCC),) +$(SDCC): + sh sdcc/build.sh $(abspath $(SDCC_PREFIX)) +endif $(SUBDIRSCLEAN): $(MAKE) -C $(@:clean=) clean @@ -223,7 +232,7 @@ MACHINE_DEFS := $(sort $(patsubst machine/%.c,%,$(filter-out machine/%_init.c,$( MACHINE_LESS_CC_FLAGS = $(filter-out -DMACHINE_%,$(CC_FLAGS)) .PHONY: machine_check -machine_check: +machine_check: $(SDCC) @mkdir -p $(BUILDDIR)/tmp @set -eo pipefail; \ for MACHINE in $(MACHINE_DEFS); \ diff --git a/README.md b/README.md index 22d9df5d..25c0a02d 100644 --- a/README.md +++ b/README.md @@ -56,12 +56,19 @@ device simulator is provided, which runs entirely under Linux as a local webserv ## (0) Compiling Requirements -Install the following particular build requisites (Debian 12/13), note that Ubuntu 24.04 -still has an older version of sdcc, but you will need sdcc version 4.5 for the code to compile: +Install the following particular build requisites (Debian 12/13): ``` -sudo apt install make gcc sdcc xxd python-is-python3 libjson-c-dev zlib1g-dev +sudo apt install make gcc g++ bison flex libboost-dev patch bzip2 curl xxd python-is-python3 libjson-c-dev zlib1g-dev ``` +The first `make` downloads SDCC 4.6.0, applies the fixes in `sdcc/` and builds it into +`toolchain/`, which takes a few minutes. Later builds reuse it. The released SDCC 4.5.0 +and 4.6.0 miscompile parts of this code, see [SDCC bug #4153](https://sourceforge.net/p/sdcc/bugs/4153/) +and [#4154](https://sourceforge.net/p/sdcc/bugs/4154/); both fixes are in SDCC trunk since +r17039. The third patch is for [#4070](https://sourceforge.net/p/sdcc/bugs/4070/), where the +assembler drops the top byte of a `__sfr32` address list; it is proposed upstream and lets +`SFR_DATA_U32` be used again. To use an SDCC you installed yourself instead, run `make CC=sdcc ...`. +
If using Docker (click to expand) diff --git a/sdcc/0001-mcs51-positionRegs.patch b/sdcc/0001-mcs51-positionRegs.patch new file mode 100644 index 00000000..e71fda96 --- /dev/null +++ b/sdcc/0001-mcs51-positionRegs.patch @@ -0,0 +1,15 @@ +https://sourceforge.net/p/sdcc/bugs/4153/ + +Index: src/mcs51/ralloc.c +=================================================================== +--- src/mcs51/ralloc.c (revision 17011) ++++ src/mcs51/ralloc.c (working copy) +@@ -1208,7 +1208,7 @@ + int change = 0; + + /* if the result has been spilt then cannot share */ +- if (opsym->isspilt) ++ if (result->isspilt || opsym->isspilt) + return 0; + + for (;;) diff --git a/sdcc/0002-mcs51-spillThis.patch b/sdcc/0002-mcs51-spillThis.patch new file mode 100644 index 00000000..0f9c8d40 --- /dev/null +++ b/sdcc/0002-mcs51-spillThis.patch @@ -0,0 +1,24 @@ +https://sourceforge.net/p/sdcc/bugs/4154/ + +Index: src/mcs51/ralloc.c +=================================================================== +--- src/mcs51/ralloc.c (revision 17011) ++++ src/mcs51/ralloc.c (working copy) +@@ -641,6 +641,7 @@ + spillThis (symbol * sym) + { + int i; ++ bool ownsRegs = bitVectBitValue (_G.regAssigned, sym->key); + /* if this is rematerializable or has a spillLocation + we are okay, else we need to create a spillLocation + for it */ +@@ -658,7 +659,8 @@ + { + if (sym->regs[i]) + { +- freeReg (sym->regs[i]); ++ if (ownsRegs) ++ freeReg (sym->regs[i]); + sym->regs[i] = NULL; + } + } diff --git a/sdcc/0003-sdas-mcs51-sfr32-valmasks.patch b/sdcc/0003-sdas-mcs51-sfr32-valmasks.patch new file mode 100644 index 00000000..fa9c66ae --- /dev/null +++ b/sdcc/0003-sdas-mcs51-sfr32-valmasks.patch @@ -0,0 +1,130 @@ +https://sourceforge.net/p/sdcc/bugs/4070/ + +Index: sdas/asxxsrc/asexpr.c +=================================================================== +--- sdas/asxxsrc/asexpr.c ++++ sdas/asxxsrc/asexpr.c +@@ -863,18 +863,59 @@ + return((n & s_mask) ? (n | ~v_mask) : (n & v_mask)); + } + +-/*)Function void exprmasks(esp) ++/*)Function void exprmasks(n) + * + * int n T Line Bytes in Address + * + * The function exprmasks() configures the assembler +- * for 16, 24, or 32-Bit Data/Addresses. ++ * for 16, 24, or 32-Bit Data/Addresses. The arithmetic ++ * precision follows the address width unless a port ++ * calls valmasks() afterwards. + * + * local variables: + * none + * + * global variables: + * int a_bytes T Line Bytes in Address ++ * ++ * functions called: ++ * void valmasks() asexpr.c ++ * ++ * side effects: ++ * The address width and arithmetic precision ++ * parameters are set. ++ */ ++ ++void ++exprmasks(int n) ++{ ++ switch(n) { ++ default: ++ n = 2; ++ case 2: ++ case 3: ++ case 4: ++ break; ++ } ++ a_bytes = n; ++ valmasks(n); ++} ++ ++/*)Function void valmasks(n) ++ * ++ * int n Bytes of arithmetic precision ++ * ++ * The function valmasks() configures the 16, 24, or ++ * 32-Bit arithmetic precision independently of the ++ * T Line address width. A port whose addresses fit ++ * in 24 bits but whose symbols may hold 32-bit values ++ * (the 8051 __sfr32 address lists, for example) uses ++ * exprmasks(3) followed by valmasks(4). ++ * ++ * local variables: ++ * none ++ * ++ * global variables: + * a_uint a_mask Address mask + * a_uint s_mask Sign mask + * a_uint v_mask Value mask +@@ -885,16 +926,13 @@ + * side effects: + * The arithmetic precision parameters are set. + */ +- ++ + void +-exprmasks(int n) ++valmasks(int n) + { +- a_bytes = n; +- + #ifdef LONGINT +- switch(a_bytes) { ++ switch(n) { + default: +- a_bytes = 2; + case 2: + a_mask = (a_uint) 0x0000FFFFl; + s_mask = (a_uint) 0x00008000l; +@@ -914,9 +952,8 @@ + break; + } + #else +- switch(a_bytes) { ++ switch(n) { + default: +- a_bytes = 2; + case 2: + a_mask = (a_uint) 0x0000FFFF; + s_mask = (a_uint) 0x00008000; +Index: sdas/asxxsrc/asxxxx.h +=================================================================== +--- sdas/asxxsrc/asxxxx.h ++++ sdas/asxxsrc/asxxxx.h +@@ -1354,6 +1354,7 @@ + extern int digit(int c, int r); + extern int is_digit(int c, int r); + extern void exprmasks(int n); ++extern void valmasks(int n); + extern void expr(struct expr *esp, int n); + extern void binop(int c, struct expr *esp, struct expr *re); + extern int is_abs(struct expr *esp); +Index: sdas/as8051/i51mch.c +=================================================================== +--- sdas/as8051/i51mch.c ++++ sdas/as8051/i51mch.c +@@ -782,9 +782,12 @@ + hilo = 1; + + /* +- * Address Space ++ * Address Space: 24-bit addresses in the T lines, ++ * 32-bit arithmetic so that __sfr32 address lists ++ * like 0xa4a5a6a7 keep their most significant byte. + */ +- exprmasks(3); ++ exprmasks(3); ++ valmasks(4); + + /* + * First time only: diff --git a/sdcc/build.sh b/sdcc/build.sh new file mode 100755 index 00000000..a312316e --- /dev/null +++ b/sdcc/build.sh @@ -0,0 +1,26 @@ +#!/bin/sh +set -eu +V=4.6.0 +SHA=5fd6a93e5997ce01756868fe35e441095cfb637894a80c262514a634094973b6 +PREFIX=$1 +D=$(cd "$(dirname "$0")" && pwd) +W=$(mktemp -d) +trap 'rm -rf "$W"' EXIT +curl -fL -o "$W/sdcc.tar.bz2" "https://downloads.sourceforge.net/project/sdcc/sdcc/$V/sdcc-src-$V.tar.bz2" +if command -v sha256sum >/dev/null; then + echo "$SHA $W/sdcc.tar.bz2" | sha256sum -c - +else + echo "$SHA $W/sdcc.tar.bz2" | shasum -a 256 -c - +fi +tar -C "$W" -xjf "$W/sdcc.tar.bz2" +cd "$W/sdcc-$V" +for p in "$D"/*.patch; do + patch -p0 < "$p" +done +off="" +for p in z80 z180 r2k r2ka r3ka r4k r5k r6k sm83 tlcs90 ez80 ez80_z80 z80n r800 ds390 ds400 pic14 pic16 hc08 s08 stm8 pdk13 pdk14 pdk15 mos6502 mos65c02 huc6280 f8 f8l; do + off="$off --disable-$p-port" +done +./configure --prefix="$PREFIX" $off --disable-sdcdb --disable-ucsim --disable-non-free +make -j"$(getconf _NPROCESSORS_ONLN)" +make install