Skip to content

firmware: GEOS boot code copies read flash, not a DTCM copy - #97

Merged
SensoriumEmbedded merged 1 commit into
SensoriumEmbedded:mainfrom
kfox:geos128-boot-rom-flash
Nov 10, 2026
Merged

SensoriumEmbedded merged 1 commit into
SensoriumEmbedded:mainfrom
kfox:geos128-boot-rom-flash

Conversation

@kfox

@kfox kfox commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

GeosBoot.h copies three PROGMEM arrays with a plain memcpy: the GEOS 128 boot ROML (245 bytes), its vectors (7) and the TR probe (12). GCC turns a memcpy of a whole const array it can see into a copy of that array in .rodata, which the Teensy linker script places in DTCM, so all 264 bytes sat in RAM1 in every main image whether or not GEOS was used. The three copies now go through GeosCopyFromFlash(), which hides the source pointer from the optimizer with an empty __asm__, so the bytes stay in flash only. (__asm__ rather than asm because the GEOS host harnesses compile this header as -std=c99.)

Verification

Main image, Docker linux/amd64, Teensyduino 1.61.0, main (ac24701) vs this branch:

TR+ before TR+ after TR before TR after
FLASH code 285884 285924 252940 253068
FLASH data 1455196 1455452 1442976 1443232
RAM1 variables 215044 215044 204932 204932
RAM1 code 203576 203576 190472 190472
RAM1 padding 25800 25800 6136 6136
RAM1 free for local variables 79868 79868 122748 122748
RAM2 unchanged unchanged

The reported RAM1 figures don't move: .data keeps its size on both targets, because the freed bytes fall inside the padding before its next alignment step. That padding grows by 272 bytes on TR+ and 264 on TR, which is headroom before the next change costs a 4 KiB step of free-for-locals.

  • Before, the three byte patterns are in .data on both targets and none is in .text.progmem. After, none is in .data, and nm shows Geos128BootRoml and Geos128BootVectors in flash.
  • npm test: pass. Shortening the copy by one byte fails 5 GEOS boot tests, so the tests reach all three copies.
  • TR+ on an NTSC C128, main image at this commit: GEOS 128 from the Utilities menu reaches the DeskTop with Special IO set to GeoRAM (2 of 2 launches) and with REU+USB Mouse/Disk and no REU preload file (3 of 3). Not run on the TR.

Reviewed at low (13 changed code lines), no findings.

GCC turns a memcpy of a whole const array it can see into a copy of the
array in .rodata, which the Teensy linker script places in DTCM. So the
GEOS 128 boot ROML (245 bytes), its vectors (7) and the TR probe (12)
cost RAM1 in every main image even though they are PROGMEM. Copying
through a pointer GCC cannot see through keeps them in flash only.
@kfox
kfox marked this pull request as ready for review November 10, 2026 16:16

@SensoriumEmbedded SensoriumEmbedded left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for chasing these bytes back into flash, nice find!

I reviewed this merged onto main (ac24701) and built both targets.

Memory: it matches your numbers. .data content drops 272 bytes on TR+ and 264 on TR, ITCM is unchanged, and flash grows by 256 bytes of progmem plus 40 (TR+) / 128 (TR) bytes of code.

Nothing to change from my side.

Hardware testing: Just to document. I'll hit these at some point, not a request or requirement! :)

Your GEOS 128 launches on the TR+ cover the boot ROM copies.

  • A first launch from a fresh stock disk image, so the CONFIGURE probe gets patched
  • One GEOS 128 launch on a plain TR

Thank you!

@SensoriumEmbedded
SensoriumEmbedded merged commit 93de51a into SensoriumEmbedded:main Nov 10, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants