Repository navigation
USB mouse registers beside GeoRAM, for GEOS - #66
Conversation
Moves the RAM1/RAM2 8K bank allocator, the image preload and the numbered button save out of IOH_REU.c into RAMBanks.c, so the GeoRAM handler can use the same code. The REU keeps its own bank array and count: SerUSBIO's busy check reads NumREU_Banks to mean the REU's DMA is live, which a GeoRAM must not trip. Behavior is unchanged except that the save writes whole banks instead of a byte at a time.
A Berkeley Softworks geoRAM: the $DE00 page window onto RAM banks from RAMBanks.c, with the page ($DFFE) and 16K block ($DFFF) registers decoded across $DF80-$DFFF the way VICE does, leaving $DF00-$DF7F free. No DMA, so it is in every full build, TR and TR+, and serves C64 and C128 mode alike. Up to 512K, as much as fits beside a loaded crt; preloads SD:/georam.ram, and the special button saves the next free georamNNN.ram. Freed with the REU wherever the menu reclaims RAM.
A short write (card full, drive pulled) printed "Saved" and flashed the save LED. Load stops at a read error rather than adding -1 to its count.
…om one shared page
Placed before Debug it moved Debug's number, and that number is what eepAdNextIOHndlr stores, so a board saved with Debug as its default came up on GeoRAM. After Debug, with LastSelectableIOH moved to it, every selectable handler keeps the number it had.
The TR's USB host port takes a mouse; the main loop adds up its movement and the IO handlers hand it to the C64 as signed steps, at $DF00 beside GeoRAM and $DE00 beside the REU, in the halves of the IO area each one leaves free. A 1351 can't be emulated: the SID's POT lines are not on the cartridge port, so this is for software with a TR driver. Each read of X or Y returns the movement since the last read of it, at most 127 steps, and keeps the rest for the next one, so a fast mouse is not lost between polls. Only the main loop writes the USB totals and only the IO ISR writes what it has handed out, so neither needs a lock.
trmouse.py assembles trmouse128.asm and writes it to a GEOS 128 boot D81 as TR USB MOUSE, in the directory entry ahead of the other input drivers, because GEOS loads the first one it finds. The driver finds the TR's registers by their ID at $DF03, else uses $DE00, doubles X in 80 columns as the stock 1351 driver does, and leaves clamping to the kernal, which flags a push past an edge for apps that scroll on it.
…, and drops buttons on unplug
…and drains movement while the pointer is off Without a TR handler serving either page, the driver read open bus at $DE00 as motion and a held button, so the pointer jumped and clicked on its own. Movement made while mouseOn was clear stayed in the TR's counters and swept the pointer across the screen once it came back on.
…d directory chain GEOS reads the permanent name's version from offset 12, where the class string had a space. A directory sector that links back to an earlier one made dir_slots loop forever when no slot was free.
…ort an unplug strands On the Cortex-M7 an NVIC_ICER write is not guaranteed to block the IRQ until a DSB/ISB, and without a compiler barrier the inlined getMouseX/Y loads may be hoisted above the disable, so the window 78cbc05 closes could stay open. A report landing just before an unplug was left pending and delivered (buttons included) on the next plug. IRQ_USBHS is in scope through USBHost_t36.h, so use the library's name.
… that does not hold
…and holds the class name to its 12 bytes
…piler too mouseDataClear() keeps its stores ahead of NVIC_ENABLE_IRQ only because it lives in another translation unit; with LTO (opt=o2lto) it inlines, and its plain stores may sink past the volatile NVIC write, reopening the race on the way out.
A 1581 directory lives only on track 40, sectors 3-39. A chain into a free data sector on any other track let allocate() hand that sector to the driver while the new directory entry was written over it. D81_SIZE is derived from the geometry it stands for.
…r's directory link, and grows a full directory
… undercounts a track, and a header with no directory link
…ry sector the BAM frees, not only the first free one
SensoriumEmbedded
left a comment
There was a problem hiding this comment.
Thanks for the 40/80-column runs, and for flagging the MouseController overwrite yourself.
Memory: 64 B of RAM1 variables and 1,664 B of ITCM code on both the TR and the TR+. About 0.9 KB of that is USBHost_t36's MouseController, which the new global links in. On the plain TR, the stack's new strings and const tables cross a 4 KiB alignment boundary at this PR, so free-for-locals drops 4,160 B there (127,132 to 122,972). That's alignment padding rather than new data, and it's still far above the floor.
- Items 1 and 2 below also take 556 B of ISR code (
IO1Hndlr_REU) andPollUSBMouse's 104 B out of the TR+'s ITCM.
Two things before merging:
1. Please drop the REU-side registers (IOH_REU.c:555, :473)
Plain REU mode used to leave IO1 alone. With IO1Hndlr_REU, every program run with the REU selected sees the mouse registers at $DE00–$DE05 (and, after #69, the block device beside them), and a read of $DE00/$DE01 consumes mouse movement. Software that probes IO1 for other hardware while an REU is selected (a SwiftLink/ACIA at $DE00, an RR-Net, a MIDI interface) now reads changing values there instead of open bus.
GEOS doesn't need them. Your own GEOS 128 run used GeoRAM, with the mouse on its IO2 page, and #70's GEOS 64 launch uses GeoRAM as well. They can't serve the freezer + REU modes either: Retro Replay, SSv5 and FC3 1.01 with the REU keep $DE00 for the freezer's own IO1 handler and only borrow the REU's IO2 side. That's how it should stay, since freezers with the REU are a core use. As the PR notes, this placement hasn't been run on hardware.
Suggested fix: remove IO1Hndlr_REU and the InitUSBMouse() call in InitHndlr_REU, along with the InitTRBlock() call #69 adds next to it. All three freezer + REU modes run InitHndlr_REU for registers they can never expose. That also takes 556 B of ISR code out of the TR+'s ITCM.
2. Poll the mouse from GeoRAM's polling handler instead of loop() (Teensy.ino:373, IOH_GeoRAM.c:21)
PollUSBMouse() runs on every loop() pass in every mode, but once item 1 is done only GeoRAM serves the registers. IOHndlr_GeoRAM's "Polled in main routine" slot is still NULL. A PollingHndlr_GeoRAM that calls PollUSBMouse() (and #69's PollTRBlock()) keeps this work, and anything that holds it up, to GeoRAM sessions, the way the REU and other handlers do their background work. It can also be FLASHMEM, along with PollUSBMouse itself (104 B of ITCM today).
Suggested fix: move the call into that handler, and have InitUSBMouse() (USBMouse.c:56) also call usbHostMouse.mouseDataClear(). Outside GeoRAM nothing drains the controller anymore, and without the clear, the last report from before GeoRAM started would arrive as a jump on the first poll.
Hardware testing still to do: for one of us to possibly get to before release
Your NTSC C128 run covers the mouse in GEOS 128 in 40 and 80 columns, and your c1541 image set covers the disk side of trmouse.py.
- the mouse in GEOS 64 on an NTSC C64 rather than a C128. The X/Y registers do their step and clamp math before driving the bus, which makes them the slowest reads on that page, so it's worth watching for pointer jumps.
- unplugging and replugging the mouse while GEOS is running
- a plain TR
- after fix 1: an REU program run with the REU selected, and each freezer + REU mode
- after fix 2: move the mouse at the TR menu, then start GEOS. The pointer should start where GEOS puts it, with no jump.
- PAL
…REU mode leaves IO1 alone again Serving them at $DE00 beside the REU made every read of $DE00/$DE01 consume mouse movement, and IO1 probes for SwiftLink, RR-Net or MIDI saw changing values. The GEOS 128 driver now probes only $DF03, so it stops reading $DE03-$DE05 every frame.
…y main loop pass Other handlers no longer pay for the poll. While GeoRAM is not running the library's report accumulates unread, so starting GeoRAM clears it rather than delivering it to the C64 as one jump.
…do the arithmetic after A read that reaches DataPortWriteWait late is latched wrong on some C64s, so the step and clamp now run after the byte is on the bus. The main loop's poll updates the ready byte with a compare-exchange that fails if a read landed meanwhile, so a step is never driven twice. The bytes a read sequence returns are unchanged.
GeoRAM_NoRAM was never read: the IO handlers return while there are no banks. Init now points the window at the first page before it publishes the bank count, so that stays true without it; the two are volatile so the stores keep that order.
…oram.bak The button saved to the REU's numbered names (georam000.ram, ...), but preload reads only georam.ram, so a saved GeoRAM never came back. The new image is written to georam.tmp first and renamed into place only after the write succeeds. The REU keeps its numbered saves.
… not where they are
# Conflicts: # Source/Teensy/MinimalBoot/Common/IO_Handlers/IOH_GeoRAM.c
…nd puts it back if the save cannot take its place If the last rename failed, georam.ram was gone: the next session preloaded nothing, and saving that blank RAM removed georam.bak, the last good image.
… running handler's memory A launch is accepted while a handler is busy. One naming a TR menu path that does not exist returned after the CRT chips, REU, GeoRAM and SwiftLink buffers were freed, without resetting to the menu, leaving the running program on freed memory.
A C++ harness includes USBMouse.c with the USB controller, the NVIC and the data port stubbed, and runs it from a script of USB reports, polls, inits and IO reads. The tests hold the register map: a large movement arrives as 127s and then the remainder, X and Y apart, sub-step counts carry, init discards movement from before the handler, and the buttons follow the report and clear on unplug. An IO read can be landed at the poll's atomic write of the ready word, and a weak compare-exchange can be made to fail, to show neither repeats nor drops movement.
The source is C++ (static_cast on the controller), so the harness is built as gnu++17 rather than C99. The Cortex-M barrier in PollUSBMouse does not assemble on the host, so the harness turns asm volatile(...) into asm("").
# Conflicts: # Source/Teensy/MinimalBoot/Common/IO_Handlers/IOH_REU.c # Source/Teensy/RemoteControl.ino
|
Thanks for the push to keep plain REU mode clean; it simplified this a lot. 1. The REU-side registersDone. The mouse registers live only beside GeoRAM, plain REU mode leaves IO1 alone again, and 2. Polling from GeoRAM's handlerDone. A Also: the X and Y reads now drive a byte computed ahead of time and do the step and clamp math after, so the slowest reads on the page no longer do arithmetic before the bus. Host tests now drive the registers. Hardware testingAll done, except as noted:
GEOS 128 hasn't been rerun since the driver's probe moved to |
|
GEOS 128 is rerun with the current driver (the |
Part of the GEOS 64 package; stacked on #61 (GeoRAM), so until #61 merges the diff here includes it. Adds a USB mouse on the TR+ USB host port, read through a small register page beside GeoRAM, for a GEOS input driver. This PR carries the driver source with its GEOS 128 build; #70 adds the GEOS 64 build of the same source, which is what the menu ships.
Firmware (
USBMouse.c): registers at$DF00–$DF05, in the part of the IO2 page GeoRAM leaves free.+0X steps since the last read of+0, signed, right is positive, clamped to ±127 with the remainder kept for the next read.+1Y the same, down is positive.+2buttons, 1 = pressed: bit 0 left, bit 1 right, bit 2 middle. Reads 0 with no mouse plugged in.+3..+5"TRM", so a driver can tell the registers are there.PollUSBMouse()runs in the main loop. It reads and clears USBHost_t36'sMouseControllerwith the USB host IRQ masked, so a report that lands mid-read is kept, and clears the report an unplug leaves behind.Driver (
tools/geos):trmouse128.asm(acme), a GEOS input driver that finds"TRM"at$DF03and does nothing if it isn't there.trmouse.pyassembles it and writes it to a boot disk image ahead of every other input driver, since GEOS loads the first one it finds.Tested on a TR+ in a C64 with GEOS 64 (the full stack, #70): fast circles, edges and corners with no jumps, in NTSC and PAL; movement at the menu doesn't move GEOS's pointer at start; unplug and replug while GEOS runs stops and resumes the pointer with no stuck button. With the REU as Special IO,
$DE00–$DE05doesn't follow the mouse. On an original TR in an NTSC C64: circles, edges and corners the same. GEOS 128 in 40 and 80 columns on a TR+ in an NTSC C128, with the current driver.Known limit:
MouseControlleroverwrites X/Y on each USB report instead of adding them up, so movement is lost when the main loop stalls for longer than a report interval.