Repository navigation
GEOS 128 launches from the TR on a C128 with the USB mouse, no disk drive - #76
Conversation
Each GEOS target now names its own TR disk driver, the start-up runs that set its date and time, and where its boot file keeps the C128 reset key. GeosBuildBootImage reads the boot file, swaps the transport, breaks the reset key and sets the clock. GeosBuildBootPrg wraps that image in GEOS 64's BASIC stub, as before. GEOS 128 sets the clock and the date in one 44-byte run, behind a store of zero that the patched run takes over to load X. Its 1581 driver keeps NewDisk after ReadBlock. The transport swap no longer requires the routines it replaces to lie inside the run it overwrites, since one left outside is only unused. The checks that nothing it leaves alone points into the run stay. CONFIGURE is turned off for any auto-exec file whose name contains CONFIG, which catches GEOS 128's "128 CONFIGURE", "128 CONFIG 2.0r" and "64 CONFIG 2.0r". GEOS 64's boot PRG and patched disk are byte-identical to before on the stock GEOS 64 D81.
SensoriumEmbedded
left a comment
There was a problem hiding this comment.
Thank you for GEOS 128, booting it straight from the SD card over the TR block device with the mouse working in both column modes is a real milestone, and the function ROM running under the emulator in the test suite is a lovely touch.
Memory: +1,632 B of RAM1 code (ITCM) on the TR+ and +1,696 B on the TR, nearly all of it GEOS helpers that stopped inlining once they gained a second caller (item 2). Variables, free-for-locals and RAM2 are unchanged on both boards; flash grows by 2.5 KB on the TR+ and 3.5 KB on the TR. MinimalBoot and the extension image are unchanged.
There are 2 things I'd like you to look at before merging. Inline suggestions are attached for everything except GeosReadFile, whose line isn't in this PR's diff.
1. Let the GEOS 128 row show on every machine (Source/Teensy/Teensy.ino:560, Source/Teensy/MainMenuItems.h:190)
I'd rather not hide the row on a C64, for four reasons:
- It's one more thing to remember on menu edits:
TeensyDirItemCountdrops whatever row is last indirUtilities, and only the comment keeps GEOS 128 there. A row added below it would swap places with it silently. - The remote and NFC paths can still reach it: a remote launch by name goes through
RemoteControl.ino:257, which counts the table's full size, so the listing isn't really a barrier. - There's already a catch behind it for non-128 systems:
LaunchGeosrefuses with "GEOS 128 needs a C128" and the menu stays where it was. - It's advertising: a C64 owner browsing Utilities gets to see that the TR does GEOS 128.
Suggested fix: remove TeensyDirItemCount and put its three call sites (DriveDirLoad.ino, FileTransfer.ino, nfcScan.ino) back to Size/sizeof(StructMenuItem), drop the "last: hidden" comment and the NFC-count test in menu-selection.test.js (the SetMenu test stays), and keep HostIsC128 for the launcher gate. Then name the row the way the other setup-specific rows are named, with the suffix aligned like +SwiftLink and +REU: "GEOS 128 +C128". The two sentences in the description about the row being hidden would go with it.
Feel free to argue your point to keep it, I'm flexible. :)
2. Three GEOS helpers moved from flash to ITCM (Source/Teensy/GEOS/GeosBoot.h:113, :278, :348)
GeosBuildBootImage (876 B), GeosReadFile (352 B) and Geos128SetClock (316 B) were inlined into FLASHMEM callers before this PR. With GeosBuildC128Boot as a second caller they're emitted out of line, and none carries FLASHMEM, so all three sit in ITCM on both boards: 1,544 B.
Suggested fix: FLASHMEM static ... on each. All three run from the launcher in the main loop, never from an interrupt, and the host harnesses already see an empty FLASHMEM from GeosDiskPatch.h. Saves 1,544 B of ITCM on each board and brings the PR's ITCM cost under 200 B.
Hardware testing still to do, all low risk and low priority: for one of us to possibly get to before release, not gates, and anything I noted that isn't listed is covered by your follow-ups or fine as it is
Your runs on the NTSC C128 cover a lot: DeskTop in 40 and 80 columns with the USB mouse in both, GeoWrite 128 saving and reopening after a reset and relaunch, 10 launches in a row without a power cycle, a C128 cartridge booting afterwards, GEOS 64 still booting, and the row hidden on a C64.
- A PAL C128.
- A plain TeensyROM (not +) in a C128.
- The DeskTop showing the TR's date and time. The patched start-up run ends with X at 0 where the stock code left X alone, and the DeskTop clock is the quickest way to see that nothing after the run minds.
- Saving and reloading in 80 columns, with the 2 MHz clock in play around the driver's 1 MHz switch.
- A remote launch of GEOS 128 from the app on a C128.
- The failure paths: no card, no /GEOS128, a D81 without the boot files, and a second launch after a successful one.
- Mouse replug and a card pull during a GEOS 128 session.
- After item 1: GEOS 128 picked on a C64 from the menu, the app and an NFC tag shows the refusal and leaves the menu usable; the renamed row launches on a C128.
- After item 2: GEOS 64 and GEOS 128 both still launch.
Travis's review of SensoriumEmbedded#75: the GEOS 64 clock helpers keep FLASHMEM now that they are reached through function pointers.
trdrive.asm assembled with C128 defined brings I/O in through the MMU ($FF00=$7E) instead of $01, and holds the CPU at 1 MHz ($D030) while it talks to the block window. DoneWithIO puts both back. trdrive.py --c128 emits it as TRDriver128.h. The GEOS 64 build and TRDriver.h are unchanged.
…image BOOT ($05) reads page ADDR1:ADDR0 of a boot image into the window as READ does, padding a short last page with zeros. Past the end it fails with $E2, and with no boot image with $E1. TRBlockMount takes the boot image with the disk image, and it goes with that image. GEOS 64 starts from a PRG and mounts none.
geos128boot.asm is SensoriumEmbedded#63's ROM stub without the unpacker. The cold start takes SEI first and copies the loader into the RAM both banks share. The loader pulls the boot image page by page through BOOT into bank 1 at 1 MHz, with the screen off, then enters it as GEOS's own ROM loader does. If the image cannot be read, the border flashes. The top of ROMH holds the CPU vectors: IRQ restarts the cold start and NMI returns. geos128boot.mjs emits Geos128Boot.h with the offsets where the firmware writes the load address, page count and entry.
The GEOS 128 row follows GEOS 64. It is shown only once the menu has reported a C128, and selecting it on a C64 is refused, because the boot ROM cannot run there. The launch builds the boot ROM's two chips in RAM_Image with the boot image after them. It tells the ROM where that image loads, how many pages it has and where to enter it, and mounts the copy with the image as BOOT's to serve. Then it starts as a C128 cart. A boot file that would reach the shared RAM below $2000 or I/O at $D000 is refused. The GEOS 128 target names its deskTop, mouse driver, disk driver, clock run and reset key.
It runs the documented NMOS opcodes, decimal mode included, against a bus the test supplies, so a test can mock a cartridge's registers and run the real ROM code against them in CI. It passes Klaus Dormann's 6502 functional test (not committed: GPL-3).
…k device The committed ROM is run on the 6502 emulator, with the C128's MMU and shared RAM and a block device that follows docs/TR_Block_Device.md. The tests check that it loads every page into bank 1 and enters GEOS. They also cover a busy device, a stale result, glitched reads, a refused page and a device that never answers.
With no crt loaded, AllocRAMBanks takes RAM_Image as free, so the GeoRAM handler, which starts before the C128 resets, loaded georam.ram over the boot ROM and the boot image. The C128 then found no function ROM and booted to BASIC. GEOS 128 now lists its ROM as a C128 crt's two chips, ending past the boot image, and launches through SetC128Type. GEOS 64 is unaffected: its PRG has been transferred before the handler starts.
A random NFC pick from a TeensyROM directory counted the directory's full size, so on a C64 it could pick the GEOS 128 row the menu hides and fail with "needs a C128". It now counts the rows the menu lists.
Travis's review of SensoriumEmbedded#76: the GEOS 128 row shows on every machine, named +C128 like the other rows that need something, and LaunchGeos's refusal covers a C64; GeosReadFile, GeosBuildBootImage and Geos128SetClock keep FLASHMEM now that they have a second caller.
GEOS 128 launches from the TR on a C128 the way GEOS 64 does on a C64: from the user's own boot disk image, with the USB mouse, and with no disk drive or crt. Stacked on #75 and #74, so until they merge the diff here includes them.
What the user does. Put the GEOS 128
.D81in/GEOS128on the SD card, then pick GEOS 128 +C128 under Utilities on a C128. As with GEOS 64, the TR patches a-TRcopy and GEOS saves to that copy. The row shows on every machine; on a C64, picking it from the menu, the app or an NFC tag is refused with "GEOS 128 needs a C128", because the boot ROM can't run there.How it starts
tools/geos/geos128boot.asm) in RAM and starts as a C128 cartridge.GeosReadFile,GeosBuildBootImageand the clock helpers are FLASHMEM: with a second caller they are no longer inlined, and would otherwise sit in ITCM.Verified on hardware on a TR+ in an NTSC C128, with no IEC drive and with a function ROM board in U36:
Host tests.
geos128boot-run.test.mjsruns the committed ROM on the 6502 emulator with the C128's MMU and shared RAM, against a block device that followsdocs/TR_Block_Device.md. It checks that every page lands in bank 1 and GEOS is entered. It also covers a busy device, a stale result, glitched reads, a refused page and a device that never answers.npm testpasses 299 of 299.Reviewed at medium per change, with each review's fix commit at low, then a final medium pass over the branch. After the maintainer's review, a medium pass over #75 and this PR together added a test that
LaunchGeosrefuses GEOS 128 on a C64 before anything else, now that the row is listed there; that test fails with the check removed.Memory, from CI's build of this head against main: RAM1 code grows 64 B on the TR+ and 128 B on the TR; RAM1 variables, free-for-locals and RAM2 are unchanged.