Page 3 and the expansion cards
On the Oric, everything that plugs in goes through 256 addresses: page 3. Phosphoric emulates a dozen cards there, period or new, each in its own module.
On this page
Who answers where
The VIA is wired at $0300-$030F, but it also answers, as a mirror, on the rest of page 3 when no
card claims the address. That is a trap for anyone who wants to detect a card: reading an empty
address returns a VIA register, not zero. The ULA-NG takes this into account in
its handshake.
A peripheral’s contract
Before the current architecture, main.c routed each page 3 access through a cascade of conditions,
with cross priorities. Now each bus peripheral is described by an io_device_t structure
(include/io/io_device.h):
| Field | Role |
|---|---|
claims | is this address mine? |
read, write | serve an access; write can decline and let the write fall through to the VIA |
claims_write | optional, when the card listens on a wider area for writes than for reads |
peek | read without side effects (for the debugger) |
save, load | its section in save states |
tick | move one cycle forward |
This contract receives the whole emulator, not just the card, because the priorities are real: the Microdisc must know whether the ACIA is present, and the LOCI’s ACIA must check the reliability of the cartridge’s bus.
One card, one file, one line
Since the 2.13 to 2.19 series, each card is a module: a file src/cards/card_<id>.c describes its
menu entries, its options, its configuration, its start-up, its bus contract, its save states and its
sound. One line in include/cards_list.h adds it. The core derives everything from it: launch options,
help, the F1 menu, phosphoric.cfg, the bus table, ticks, save states and audio mixing.
There is no dynamic loading: the list is explicit, to stay portable across GCC, MinGW, clang on macOS
and Emscripten. The sample card docs/examples/card_demo.c serves as a model, and
make test-card-template adds it to a copy of the tree to check that it works end to end.
The emulated cards
| Card | Address | What it does |
|---|---|---|
| Microdisc | $0310-$031F | WD1793 floppy controller, four drives, ROM at $E000 |
| Jasmin | $03F4-$03FF | WD177x controller, boot ROM at $F800, TDOS floppies |
| LOCI | $03A0-$03BF | modern cartridge: storage, USB, swappable ROM; see The LOCI |
| ACIA 6551 | $031C-$031F ($0380 with the LOCI) | serial port: V23 modem, Telestrat |
| DTL 2000 | $03F8-$03FD | Digitelec modem: PIA 6821 and ACIA 6850, V23 for the Minitel |
| Mageco MIDI | $03FE-$03FF | ACIA 6850 to the MIDI sockets, 31,250 baud |
| ORICON | $031C-$031F | modern remake of the MIDI interface, compatible with the LOCI |
| SP0256 | $03F1 | allophone speech synthesis (Mageco card) |
| MEA 8000 | $03FE-$03FF | formant speech synthesis (TMPI card) |
| hostfs | — | a host folder shared with the Oric |
| ULA-NG | $0340-$035F | the extended ULA, always present, locked at start-up |
Overlapping cards are exclusive: a single disk card (Microdisc, Jasmin or LOCI), a single MIDI card (Mageco or ORICON). The F1 menu reports address conflicts.
The serial port: chips and transports
Phosphoric separates the chip that the Oric program drives from the transport that carries the bytes on the host. You pick a chip, then give it a transport.
| Transport | Kind | Use |
|---|---|---|
loopback | transparent | what is sent comes back (tests) |
tcp:host:port | transparent | a BBS, a Minitel server, telnet, a MIDI router |
pty | transparent | a POSIX pseudo-terminal (minicom, screen) |
com:... | transparent | a real serial port on the host |
file:in[:out] | transparent | deterministic replay and capture, with no network |
midi[:target] | transparent | a host MIDI port (ALSA, CoreMIDI, WinMM) |
smf:song.mid | transparent | a MIDI file played into the Oric, at the song’s tempo |
modem[:host:port] | protocol | a Hayes AT command interpreter |
picowifi[:...] | protocol | the PicoWiFiModemUSB Wi-Fi modem, AT commands |
Protocol transports only go with --serial (the ACIA 6551), by design: the DTL 2000 dials through
its PIA (a line bit), not through AT commands, and putting them behind the faithful card would make
it unfaithful.
file: is valuable for protocol tests: you replay a recorded server stream and capture the program’s
replies, with no network and no peer.
MIDI
The original Mageco card (--mageco) and its ORICON remake (--oricon) put an ACIA 6850
behind the MIDI sockets, at 31,250 baud. Phosphoric can:
- capture the Oric’s MIDI stream to a file (
file::out.mid); - play a standard MIDI file into the Oric, at the song’s tempo (
smf:song.mid[:loop]); - in a
MIDI=1build, open a real host MIDI port (“Phosphoric MIDI” under ALSA): the Oric drives FluidSynth or a music program, and a MIDI keyboard plays into the Oric.
What plugs into the ports
Some peripherals take no address in page 3: they plug into the ports of the VIA or the PSG.
- The IJK joystick, the most common adapter, on the PSG’s port A (active low): from the keyboard
(arrows, right Ctrl and Alt to fire,
-j keys) or on a real gamepad (-j gamepad, hot-plug). - The Centronics printer: data on the VIA’s port A, strobe pulse on CA2.
LPRINTandLLISTare captured to a text file (-p out.txt). - The MCP-40 plotter (
--printer-type mcp40): four pens, the plotting commands (home, draw, move, colour, text, line type), a 480 × 400 dot sheet exported as BMP. - The tape, on the VIA’s CB1 input (see Tapes, floppies and save states).