Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions MEGA65.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# CBM-FileBrowser — native MEGA65 / C65 port

This adds a **native MEGA65 (C65-mode)** target to CBM-FileBrowser, alongside the
existing C64 / C128 / VIC-20 / C16 / DTV builds. It runs in the MEGA65's own
native mode (not GO64/C64 mode): it loads at `$2001` with a BASIC-10 SYS stub and
uses the MEGA65 screen and VIC-III/IV.

Because the file browser is a KERNAL/IEC client, it is exactly what you want for
driving a **Meatloaf** device over the IEC serial bus.

## Files added

| File | Purpose |
|------|---------|
| `sources/mega65.def` | Target configuration (`target = 65`): memory map, colours, keys, default device. |
| `sources/mega65.asm` | Entry point — includes `mega65.def` then the shared `CBM-FileBrowser.asm`. |
| `sources/CBM-FileBrowser.asm` | Shared core — now has `target = 65` branches throughout. |
| `sources/Makefile` | New `fb65.prg` rule. |

## Building

You need [ACME](https://sourceforge.net/projects/acme-crossass/) (`brew install acme`).

```bash
cd sources
make fb65.prg # just the MEGA65 build
# or
make # all targets, including fb65.prg
```

Output: `sources/fb65.prg`, load address `$2001`.

## Running in the Xemu MEGA65 emulator (`xmega65`)

```bash
xmega65 -prgmode 65 -prg fb65.prg
```

`-prgmode 65` forces native C65 mode; `-prg` auto-runs the program. The browser
comes up showing its list frame, the drive number, and the `SORT` / `QUIT`
bottom bar.

## Configuration (`sources/mega65.def`)

Key settings you may want to change:

- **`hwdevicenum = 10`** — the IEC device the browser talks to. This is set to
**10** for a setup where the internal floppy is disabled and **Meatloaf answers
as device 10**. Set to `0` to auto-detect from the last-used device, or to `8`
for a standard internal drive. At runtime, press **`D`** to cycle the active
drive (8..15) regardless of this default.
- Colours (`backcolor` / `bordercolor` / `forecolor` …), key bindings
(`key_*`), and feature toggles (`sortdir`, `fastscrolle`, …) work the same as
the other targets — see the comments in `mega65.def`.
- `tap_support` is **off** for MEGA65 (the ITS tape path uses C64-specific ROM
entry points and tape is not relevant natively).

## How the MEGA65 target differs from the others

The C65 KERNAL is derived from the C128 KERNAL, so the portable `$FFxx` KERNAL
jump table (`SETLFS`/`SETNAM`/`OPEN`/`CLOSE`/`LOAD`/`CHKIN`/`CHRIN`/`CHROUT`/
`PLOT`/`GETIN`/…) is used unchanged. The MEGA65-specific pieces are:

- **Memory map:** screen `$0800`, colour RAM `$D800`, BASIC text `$2001`
(vs `$0400`/`$D800`/`$0801` on the C64).
- **BASIC-10 SYS stub** at `$2001` (`10 SYS 8205`).
- **No VDC and no C128 MMU** — the C128 target writes the VDC (`$D600/$D601`) and
banks memory via `$FF00`/`$FF68`; neither exists on the MEGA65, so the C65
target has its own colour/init code and uses the direct-screen-memory drawing
paths.
- **Self-contained print helpers** — the C64 build calls BASIC-ROM routines at
`$AB1E`/`$BDCD`; those addresses are not valid in C65 mode, so `PRNSTR` /
`PRNINT` / `CLEARSCREEN` are reimplemented locally on top of `CHROUT`.
- **Zero page:** `SHFLAG = $D3`, `NDX = $D0`, device `= $BA` (C128-derived),
status `ST = $90`.

## Two MEGA65-specific fixes (both needed for correct operation)

1. **LOAD destination bank (`$AF`/`$B0`).** The MEGA65 KERNAL `LOAD` uses a
32-bit destination pointer in zero page (`$AD`=lo, `$AE`=hi, `$AF`=bank,
`$B0`=megabyte). The C64-compatible relocating `LOAD` sets only `$AD`/`$AE`
from X/Y and leaves the bank byte uninitialised, so the directory/program
would be written into a stray bank (Xemu reports "unhandled memory write for
linear address `$28xxxx`"). The `target = 65` code zeroes `$AF`/`$B0` right
before every `LOAD`.
2. **80-column row stride (`ScreenCols = 80`).** MEGA65 native mode boots into an
80-column editor, so screen RAM at `$0800` has an 80-byte logical row stride.
The direct-memory list drawing (clearlist / fast-scroll) must use 80, or
scrolled entries land in the wrong half of the screen. Column *positions*
(`listx` etc.) are unchanged, so the UI sits in the left 40 columns.

## Program launch (the "RUN" step)

When you select a program the browser does a KERNAL `LOAD` and then launches it.
The C64/C128 targets jump to machine-specific **BASIC-ROM** routines to RUN; the
closed MEGA65 ROM's BASIC internals are undocumented and going back through
BASIC's direct loop dropped into the built-in monitor. So `target = 65` uses a
**ROM-independent launcher** (`m65_run_hook`): it parses the `SYS <addr>` out of
the program's BASIC stub at `$2001` and `JMP`s straight to the machine code.

This launches machine-language `.prg`s (BASIC `SYS` stub + machine code — games,
demos, tools, and the `fb*` programs themselves — the bulk of the software). See
**Known limitations** below for pure-BASIC programs.

Finding the launcher took three MEGA65-specific discoveries, all now in the
`target = 65` code:
- `loadrunpos = $0400`: the C64 tape-buffer `$0334` holds live C65 KERNAL
keyboard-decode vectors — copying the loadrun code there corrupted the
keyboard. `$0400-$07FF` (old C64 screen, free in native mode) is safe.
- keyboard buffer `KEYD = $02B0`, `NDX = $D0` (found by disassembling the ROM).
- stop-key flag `$91` (`$7F` = pressed).

## Known limitations

- **Program launch is machine-language only.** The launcher parses a program's
`SYS <addr>` BASIC-10 stub and jumps to it, so it runs the ML `.prg`s that are
the bulk of MEGA65 software. A **pure BASIC-10 program** has no `SYS` token, so
it is *not* run: the launcher falls back to a reset, and if the program happens
to contain a stray `$9E` byte early in its first line the parse can jump to a
bad address and drop into the monitor. Launching BASIC programs properly needs
a LOAD-then-RUN hand-off back into BASIC-10, which isn't implemented yet. **The
Commander X16 target shares this limitation.**

## Verified in `xmega65` (native C65 mode)

- Boots and runs from the `$2001` BASIC-10 stub.
- Renders the full UI natively — list frame, cursor arrows, disk-name/status
area, colours, and the drive-number / `SORT` / `QUIT` labels.
- **Reads a disk directory via KERNAL `LOAD"$"` and lists the files.**
- **Scrolls the list cleanly** (up/down, page, top/bottom).
- **Selects and launches a program** (`LOAD` + SYS-stub launcher).
- Keyboard/joystick input (CIA1 `$DC00`, C64-compatible on MEGA65).

Tested against a D81 on the emulated internal drive (device 8). On real
hardware the identical KERNAL path talks to **Meatloaf over IEC (device 10)** —
`hwdevicenum = 10` in `mega65.def`.

## Cosmetic note

The browser draws in the left 40 columns of the 80-column MEGA65 screen.
Optionally the MEGA65 could be switched to 40-column mode at startup so it fills
the screen like a C64.
122 changes: 122 additions & 0 deletions X16.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# CBM-FileBrowser — Commander X16 port

This adds a **Commander X16** target (`target = 216`) to CBM-FileBrowser,
alongside the existing C64 / C128 / VIC-20 / C16 / DTV / MEGA65 builds.

The X16 uses a C64-derived KERNAL (standard `$FFxx` jump table, BASIC at
`$0801`, `65C02` CPU), so most of the browser ports cleanly. The one big
difference is **video: the X16 uses VERA**, whose text screen lives in separate
video RAM, *not* in the CPU address space. So this target does **all** drawing
through the KERNAL screen editor (`CHROUT` / `PLOT`) — there is no direct
screen-memory access, and fast-scrolling (which relies on it) is turned off.

Being a KERNAL/IEC client, it's exactly what you want for driving a **Meatloaf**
over the IEC serial bus.

## Files added

| File | Purpose |
|------|---------|
| `sources/x16.def` | Target configuration (`target = 216`): device, colours, keys. |
| `sources/x16.asm` | Entry point — includes `x16.def` then the shared `CBM-FileBrowser.asm`. |
| `sources/CBM-FileBrowser.asm` | Shared core — now has `target = 216` branches throughout. |
| `sources/Makefile` | New `fbx16.prg` rule (also in `all`). |

## Building

Needs [ACME](https://sourceforge.net/projects/acme-crossass/) (`brew install acme`).

```bash
cd sources
make fbx16.prg # just the X16 build
# or
make # all targets, including fbx16.prg
```

Output: `sources/fbx16.prg`, load address `$0801`.

## Running in the emulator (`x16emu`)

The X16 emulator serves the directory it is launched from as device 8 (HostFS),
so run it from a folder that contains `fbx16.prg` (and any programs to browse):

```bash
cd /folder/with/fbx16.prg/and/programs
x16emu -prg fbx16.prg -run
```

The browser comes up, lists the folder, and you can cursor to a program and
press **Return** to launch it. On real hardware, put `fbx16.prg` on the SD card
(or load it from Meatloaf) and `LOAD"FBX16",8` + `RUN`.

## Configuration (`sources/x16.def`)

- **`hwdevicenum = 8`** — the device the browser reads (the X16 SD-card / HostFS
default). Set to `0` to auto-detect from the last-used device, or to the
device your **Meatloaf** answers on. Press **`D`** at runtime to cycle the
active drive.
- Colours / key bindings work like the other targets (see the comments in
`x16.def`). `bordercolor` is ignored (the X16 has no C64-style border);
`fastscrolle` is forced off (VERA has no direct screen RAM); `tap_support` is
off (no tape).

## How the X16 target differs

- **Video is VERA** — screen not in CPU RAM. All drawing via `CHROUT`/`PLOT`;
`clearlist` reimplemented with `PLOT`+`CHROUT`; `fastscrolle = 0` (a full
`CHROUT` redraw per move, fast enough on the 8 MHz X16). The browser sets
40×30 text mode (`screen_mode` `$FF5F`) at startup.
- **SYS-stub launch** — the same ROM-independent SYS-stub launcher as the
MEGA65: parse `SYS <addr>` out of the program's `$0801` BASIC stub and `JMP`
to the machine code. Launches machine-language `.prg`s — see
**Known limitations** below.
- **Zero page / KERNAL vars** — `ST = $0287`, device `= $0292`, `KEYD = $A800`,
`NDX = $A80A`, `STKEY = $A80B`, `SHFLAG = $A80C`. The browser's own zero page
(`$22-$29`, `$57/$58`, `$FB-$FE`) is free on the X16.
- **`loadrunpos = $0400`** — the X16's "golden RAM" (`$0400-$07FF`), free and
below the `$0801` program area.
- **Keyboard-driven** — the joystick read is stubbed to "nothing pressed" so
input falls through to the keyboard (real joystick support via `joystick_get`
`$FF56` is a possible future add). The raster-wait uses a short delay, not a
VERA vsync poll (the KERNAL owns the vsync IRQ, so polling it hangs).
- **ISO mode for mixed-case filenames** — SD-card/HostFS filenames are ASCII, so
the browser switches the X16 to ISO mode at startup (`CHR$15`) so lower- and
upper-case names both render as real letters. Colour/reverse control codes
still work in ISO mode; the one graphic glyph the browser uses (the separator
bar) is drawn with `-` instead of the PETSCII bar `$c0` (which is `A-grave` in
ISO).

## Known limitations

- **Program launch is machine-language only.** The launcher parses a program's
`SYS <addr>` BASIC stub and jumps to it, so it runs the ML `.prg`s that are the
bulk of X16 software (games, demos, tools, and the `fb*` browsers themselves).
A **pure BASIC program** has no `SYS` token, so it is *not* run: the launcher
falls back to a reset, and if the program happens to contain a stray `$9E` byte
early in its first line the parse can jump to a bad address and drop into the
monitor. Launching BASIC programs properly needs a LOAD-then-RUN hand-off back
into BASIC, which isn't implemented yet (re-entering X16 BASIC cleanly from the
browser's running state is fiddly). **The MEGA65 target shares this
limitation.**

## Bug fixed along the way (helps every target)

`parseext` (the disk-image extension matcher) had a **latent infinite loop**:
its outer loop steps X by the 4-byte slot size and stopped only when
`X == extensions_max`, but the extensions table is not a whole multiple of 4
(`"tcrt"` is 5 bytes), so X could step *past* `extensions_max` and never match.
It never surfaced on the C64/C128/MEGA65 because CBM disk names have no file
extension (so `parseext` is skipped), but the X16's HostFS reports names like
`GAME.PRG`, which exercises it. Fixed by terminating on `X >= extensions_max`
(`bcs` instead of `beq`) — a safe hardening for all targets.

## Verified in `x16emu`

Boot from the `$0801` stub · full UI rendered natively via VERA/CHROUT ·
directory read (`LOAD"$"`) and file listing · list scrolling · keyboard
navigation · **selecting and launching a program**.

## Charset

The browser runs the X16 in **ISO mode**, so both upper- and lower-case
filenames (from the SD card / HostFS, which are ASCII) render as real letters.
Binary file added programs/fb65
Binary file not shown.
Binary file added programs/fbx16
Binary file not shown.
Loading