Skip to content

Releases: Jondalar/TRX64

TRX64 0.12.4 — EasyFlash 3

Choose a tag to compare

@Jondalar Jondalar released this 04 Oct 18:55

Added

  • EasyFlash 3. A full EasyFlash 3 image (CRT type 90, 8 MB, 8 slots) runs as the cartridge's CPLD does it:
    • Slots and banking:
      • $DE01 selects one of 8 slots.
      • Each slot uses EasyFlash banking ($DE00/$DE02), including the no-VIC bit and the boot flag.
      • The IO2 RAM is shared by all slots.
      • $DE08 reports the CPLD version.
    • Mode register $DE0F: EasyFlash with a reset (0), without a reset (1), and kill (7).
      • The KERNAL, freezer (AR/RR/NP, SS5) and C128 modes are not emulated. A program that selects one gets the cartridge switched off, and the status says "not emulated".
    • Buttons: the cartridge's three buttons (Menu, Reset, Special) are new:
      • cart button <menu|reset|special> in the monitor;
      • cart/button over the API;
      • cart_button in the FFI.
    • Flash: an MX29LV640EB with its 8 KB boot blocks, so the cartridge's own EasyAPI driver programs and erases unchanged.
      • Writes survive checkpoints and are saved back as a type-90 CRT.
    • Tested with skoe's EF3 boot image: it boots to its menu, starts a slot, and returns to the menu.

Changed

  • C64MegaCart is CRT type 88. It used to be 61, which mainline VICE assigns to MAX Basic. CRT files with type 61 are no longer read as C64MegaCart.

TRX64 0.12.3 — debug builds survive an interrupt

Choose a tag to compare

@Jondalar Jondalar released this 03 Oct 11:06

Fixed

  • Debug builds no longer panic on the first interrupt. 0.12.2 computed an addition on the IRQ/BRK path before checking whether an NMI was pending. With no NMI pending, the addition overflowed:

    • Release builds wrapped silently, and the result was then ignored, so they behaved correctly.
    • Debug builds stopped with "attempt to add with overflow" on every IRQ or BRK, so any application that embeds TRX64 and builds in debug failed.

    The check now runs only when an NMI is pending. The pre-push gate also runs one booted IRQ in a debug build.

TRX64 0.12.2 — U64 turbo as measured

Choose a tag to compare

@Jondalar Jondalar released this 03 Oct 10:36

Fixed

  • U64 / C64 Ultimate turbo now behaves as measured on the device. The C64 Ultimate (firmware 3.15, core 1.50) was measured, and TRX64 now follows those measurements. Where the old model followed the menu labels or VICE's TurboMaster, it now follows the device:

    • $D031 bit 7 means "no badline stalls". The old model had it inverted. $80 is now 1 MHz without stalls.
    • The top speeds are 47 and 63 CPU cycles per PHI2, not the 48 and 64 on the menu labels. All other speeds are as labelled.
    • Interrupts are taken at the turbo clock, within one PHI2 cycle, as on the device. The old model counted two PHI2 cycles.
    • I/O costs as measured:
      • CIA, IO1/IO2 and VIC/SID accesses wait for the PHI2 bus cycle with the measured lead.
      • UCI at 16× now runs 1.0158×; the device runs 1.0157×.
    • Program and menu share one turbo state. The last write wins, and a menu change applies even when the value is unchanged.
      • In TurboEnable mode, a menu change also sets $D030.
    • Reset readbacks follow the mode. In registers mode, $D031 reads $00 after a reset.
    • The post-reset hold lasts 2^22 PHI2 cycles (4.26 s on PAL). The old value was 2.06 s.
    • $D07A/$D07B, $D0BC–$D0BF and their mirrors decode as on the device.
    • Colour stores ($D020–$D02E) during turbo land at the pixel they were made in.
    • Snapshots and the checkpoint ring carry the turbo state on the U64 profile. Older U64 snapshots load with the reset defaults, and the restore says so.

    At 1 MHz nothing changes.

  • A 1581 finds its DOS in any ROM directory (#4).

    • dos1581-318045-02.bin (or 1581.bin / 1581.rom) used to be looked up only in the directory that held the KERNAL. It is now found in any of the ROM directories.
    • Switching a drive to 1581, or powering one on, without a DOS is now refused. The error names the file and every directory searched. Before, the drive ran with no ROM, and the C64 reported ?DEVICE NOT PRESENT.

TRX64 0.12.1 — the C64's CIAs are VICE's

Choose a tag to compare

@Jondalar Jondalar released this 02 Oct 12:56

Fixed

  • A pending CIA interrupt stays until the ICR is read (#3).

    • Writing the mask to $DC0D / $DD0D (for example $7F) used to release a pending IRQ or NMI and clear the IR bit.
    • A 6526 and VICE keep both until $DC0D / $DD0D is read.
    • An IRQ handler that leaves through $EA81 without reading $DC0D now re-enters for ever, as on the real machine, instead of quietly working only in TRX64.

    The C64's two CIAs now run on the same exact port of VICE's CIA core that the 1581 already used, with the C64 wiring ported from VICE:

    • The keyboard matrix includes ghost keys.
    • Joysticks, the paddle select, the VIC bank, the serial bus and the NMI are wired as in VICE.
    • The CIA model follows the machine: a 6526 in the C64.
    • IRQ timing is VICE's: a 6526 raises its IRQ one cycle late, and an ICR read acknowledges through the delay line.
    • The time-of-day clock no longer loses about one cycle per tick.
  • Snapshots carry the whole CIA state. Older .c64re and .vsf files still load. Their CIA record is converted, and the restore says so.

Programs whose timing hung on the old approximation can run a few cycles differently.

TRX64 0.12.0 — a daemon that ends when nobody uses it

Choose a tag to compare

@Jondalar Jondalar released this 02 Oct 10:40

New

  • The daemon can end itself when nobody uses it. --idle-exit <seconds> (off by default) ends the daemon with exit 0 and [trx64] idle for N s — exiting once, for the whole window, no request arrived, no A/V viewer was connected and no trace was recording.
    • A viewer or a trace holds the clock; the window starts when the last of them ends.
    • Before exiting it persists the cartridge and both drives' disks exactly as eject does.
  • daemon/keep_alive { seconds | null } holds the daemon at least that long; null means never on idle. The reply is the idle status.
  • idleExit in ping and session/state: armedSeconds, deadlineMs (epoch ms, or null when it won't end), keptAliveUntilMs, keptForever, holding ("subscriber" | "trace" | null).
  • RPC-only clients connect with ?av=0. A streaming daemon subscribes every connection to the video and audio push. A client that only speaks JSON-RPC now says so: it gets no binary frames, doesn't start the pacing loop on its own account, and doesn't count as a viewer.

Docs

  • The play-API doc lists daemon/keep_alive and ?av=0. It used to say ping returns {}; it names the build, the project and the idle state.

TRX64 0.11.1 — clean port hand-off, traces that stream

Choose a tag to compare

@Jondalar Jondalar released this 02 Oct 09:45

Fixed

  • A second daemon on a port another runtime owns leaves cleanly.
    • When several clients warm-start a daemon on the same port at once, the losers used to boot a whole C64 and then panic on the bind (exit 101).
    • The port is now taken before anything boots. A port somebody else owns prints one line, port N already owned by another runtime — exiting cleanly, and exits 0.
    • Any other bind error exits non-zero with the OS error.
  • A recording trace streams to its .c64retrace.
    • The run used to sit in memory until trace/run/stop: the file stayed at 0 bytes while recording, the daemon grew with every frame, and a crash lost everything.
    • Now the frames are appended once they pass 4 MiB, and the tail at stop. The finished file is byte-for-byte the same size with the same events.
    • trace/status gains bytesWritten (on disk) next to bytesBuffered (pending).

TRX64 0.11.0 — a loaded program hears the keyboard, writes land where they belong

Choose a tag to compare

@Jondalar Jondalar released this 30 Sep 10:08

New

  • Start a loaded program where you say. run on media/open, session/load_prg and runtime/run_prg starts the program at that address after the load, without going through the keyboard. It takes a number or hex text: 2112, $0840, 0x0840 or 0840. runtime/run_prg used to accept only a number and ignored text.
  • session/create {exerciser: true} declares a CPU/chip exerciser: bytes poked, PC set, run cycle-exact on the CPU-isolated core. It is the only thing that leaves the full machine.

Fixed

  • A loaded PRG hears the keyboard. Opening a PRG, run_prg, or any monitor wr / a / r a=… used to latch the machine onto the CPU-only core as soon as no disk and no cartridge were attached. There the CIAs don't run, so the KERNAL never scans the keyboard: READY. stayed on screen and typed text never arrived. Loading, typing and poking now keep the booted C64 whole.
  • Autostart really starts. media/open on a $0801 BASIC program queued RUN in a buffer nothing read. It now types RUN: + RETURN through the keyboard, as run_prg does. The colon turns text left on the screen line into a following statement instead of a ?SYNTAX ERROR, as VICE does. media/open also sets VARTAB after a $0801 load.
  • media/persist writes the mounted cartridge. It wrote the cartridge's bare file name, so a new .crt appeared in the daemon's working directory and the mounted file stayed unchanged.
    • The cartridge now has one backing path. media/persist, savecrt, swapcrt, eject and auto-persist all use it.
    • After swapcrt, eject and persist write the new cartridge's file, not the old one's.
    • A clean cartridge is no longer rewritten.
    • The reply is {written, role, path: <absolute path written>, bytes}, or {written: false, role, reason}.
  • No write lands in the daemon's working directory any more. A relative path given to snapshot/dump, snapshot/undump, recorder/dump, vsf/save, audio/export, a trace output or ringbuffer/dump resolves against the bound project. With no project bound it is refused, instead of being written wherever the daemon was started. media/ingress resolves its path the way media/mount does.

TRX64 0.10.0 — a block assembler, sandboxes that keep to themselves, Intel Macs

Choose a tag to compare

@Jondalar Jondalar released this 27 Sep 18:41

New

  • Block assembler. The monitor assembles whole blocks with labels (loop:), name = value, *, </>, +/-, .byte, .word and one *=/.org: asm <addr> collects lines until end, asm-file <path> [addr] reads a source file, and RPC asm/block returns bytes, labels and per-line errors without writing anything. A block is written only if all of it assembled.
  • Sandbox runs keep their own media. A sandbox run that writes its disk or flashes its cartridge gets its own copy under <project>/sandbox/<stamp>-<run-id>/, reported under media; the original image is never written. A run that only reads makes no folder.
  • Nearest mark. transport/status carries nearestMark { name, framesAway }, and the transport line ends in it (alpha +160).
  • Intel Macs. Release binaries for macOS x86_64, cross-built from Apple silicon.

Fixed

  • Sandbox runs no longer touch the live machine. sandbox/run and sandbox/runMany restored into the shared session and paused it; each run now works on its own clone, on its own thread.
  • Sandbox --zp $00 / --zp $01 seeds reach the CPU port and override --io. The seed used to land in RAM only, so a routine seeded at $35 ran at $34 and a DEC $01 went to $33 with the character ROM at $D000.
  • iec shows every unit on the bus: both drives by unit and type (1541 or 1581) and every folder or host device, not only drive 8.
  • Monitor help: device names drive8 … drive11 and the 1581, mount/identify list .d81, reu and georam are listed, reset is warm unless cold, and the turbo note only says "stored" on the 128 profile.
  • The cockpit colours .d81 as a disk image.

Docs

  • New docs/FEATURES.md, one line per feature.
  • README, CLI README, MONITOR.md and the Swift API.md brought in line with the code: platforms, cartridge types, .d81 and unit-aware mount/eject, 25 monitor verbs that were missing, measured ring sizes, the NTSC canvas, realtime pacing.

TRX64 0.9.2 — paddles and mice, disk swaps that behave, the Commodore key on Control

Choose a tag to compare

@Jondalar Jondalar released this 24 Sep 10:54

Paddles and mice, disk swaps that behave, and the Commodore key on Control

The POT lines

The SID's paddle registers $D419/$D41A now answer the control port CIA 1 selects
($DC00 bits 6/7), and take a new value every 512 cycles, as the chip does.

  • A host sets what its device delivers per port — paddles, a 1351 mouse, the extra fire
    buttons of a multi-button joystick: set_pot(port, x, y) / clear_pot(port) in the
    library, session/pot_set / session/pot_clear on the daemon, pot in the monitor.
  • With nothing set a POT line reads $FF, as an open line does on a real C64 (it was a
    constant $80). Both ports selected combine like two resistors in parallel.
  • The monitor shows the value the CPU reads at $D419/$D41A, not the write shadow.

Disk swaps

  • The 1541 now notices an eject. The write-protect sensor's reaction to a disk being
    pulled was missing, so a drive never saw the old disk leave — only the new one arrive.
    Every eject and every disk swap now goes through it, with the timing VICE uses.
  • runtime/swap_disk_and_continue does what it says: eject, let the drive notice,
    insert, let the drive notice, press the confirm key, run on — and report the screen
    before and after and whether the prompt changed. It used to mount the new disk at once and
    report steps it never ran. The confirm key is held 400 000 cycles by default
    (confirm_hold_cycles): games that read the keyboard every few frames miss a short press.

Keyboard

Host Control is the Commodore key, as in VICE. The C64's CTRL stays on ^ below ESC,
RUN/STOP on Tab. Cmd is no longer mapped. The cockpit's README lists the whole left edge.

Swift API

The Swift library reaches both drive positions (power, unit, reset, stop, status), the
drive type (1541 or 1581), .d81 disks and the folder device. Existing calls are
unchanged and still address drive 8. The daemon gained session/drives,
session/drive_reset, session/drive_stop and device/folders for it.

Docs

The README now describes embedding trx64-core: the drive positions, the folder device,
IecDevice, FdcController and the POT lines.

TRX64 0.9.1 — a controller of your own in the 1581

Choose a tag to compare

@Jondalar Jondalar released this 24 Sep 07:53

A controller of your own in the 1581

A program that embeds TRX64 can now replace a 1581's WD1772 with its own disk controller
(FdcController). This is for hosts that keep the disk image themselves and serve it
sector by sector — the way the Ultimate's firmware serves a .d81 from an open file.

  • The controller sees every access to the WD registers ($6000-$7FFF) at the drive's
    cycle, the side select and motor from the drive's CIA, and the drive's reset and power.
    It drives the drive's ready, disk-change and write-protect lines.
  • Fitted only while the drive is switched off, like any change to the board. While a
    controller is fitted the drive has no disk of TRX64's own: mounting and ejecting are
    refused.
  • The 1581 DOS waits for BUSY without a timeout: a controller must raise BUSY within
    6 drive cycles of a command, or the drive hangs.
  • A snapshot leaves out the controller's state if it opts out, and names it; restoring a
    snapshot whose controller does not match the machine is refused.
  • Without a controller nothing changes: the built-in WD1772 is untouched and costs
    nothing extra.

For programs that embed trx64-core

  • New: the FdcController trait, Machine::attach_fdc_controller / detach_fdc_controller.