Skip to content
Phosphoricwiki
Contents

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

Page 3: who answers at which addressThe 256 addresses from $0300 to $03FF are reserved for input and output. The VIA takes $0300-$030F and also answers on the rest of the page when no card claims it. The emulated cards share the rest: Microdisc at $0310-$031F, ACIA 6551 at $031C (or $0380 with the LOCI), ULA-NG at $0340-$035F, LOCI at $03A0-$03BF, SP0256 speech at $03F1, Jasmin at $03F4-$03FF, DTL 2000 at $03F8-$03FD, Mageco MIDI or MEA 8000 speech at $03FE-$03FF. Overlapping cards are exclusive.Page 3 · $0300-$03FF: the cards' windows$0300$0340$0380$03C0$03FFVIA 6522$0300-$030FMicrodisc$0310-$031FACIA 6551$031C-$031FULA-NG$0340-$035FACIA (LOCI)$0380-$0383LOCI$03A0-$03BFSP0256$03F1Jasmin$03F4-$03FFDTL 2000$03F8-$03FDMageco · MEA 8000$03FE-$03FFWithout a card, the VIA answers on the whole of page 3 (its 16 registers repeated).Overlapping cards cannot be plugged in together: the F1 menu says so.
The cards’ windows in page 3. The VIA answers wherever no card does.

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):

FieldRole
claimsis this address mine?
read, writeserve an access; write can decline and let the write fall through to the VIA
claims_writeoptional, when the card listens on a wider area for writes than for reads
peekread without side effects (for the debugger)
save, loadits section in save states
tickmove 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

Adding an expansion card: one file and one lineAn expansion card is written in a single file, src/cards/card_<id>.c, and added with one line X(<id>, <tick>) in include/cards_list.h. The core derives everything else from it: launch options, help, the F1 menu, the phosphoric.cfg file, the I/O bus table, per-cycle ticks, save states and audio mixing.One card = one file + one line (ADR 0006)src/cards/card_<id>.cthe card's descriptorX(<id>, <tick>)in include/cards_list.hnothing else to touchthe corederives the restlaunch options--help textF1 menu pagephosphoric.cfgbus table (page 3)tick on every cycle.ost save sectionaudio source mixed with the PSGProved by make test-card-template: the sample card is added to a copy of the tree.Ticks are direct calls generated from the list: a table of pointers cost 5%.
Adding a card: one file in src/cards/, one line in include/cards_list.h.

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

CardAddressWhat it does
Microdisc$0310-$031FWD1793 floppy controller, four drives, ROM at $E000
Jasmin$03F4-$03FFWD177x controller, boot ROM at $F800, TDOS floppies
LOCI$03A0-$03BFmodern cartridge: storage, USB, swappable ROM; see The LOCI
ACIA 6551$031C-$031F ($0380 with the LOCI)serial port: V23 modem, Telestrat
DTL 2000$03F8-$03FDDigitelec modem: PIA 6821 and ACIA 6850, V23 for the Minitel
Mageco MIDI$03FE-$03FFACIA 6850 to the MIDI sockets, 31,250 baud
ORICON$031C-$031Fmodern remake of the MIDI interface, compatible with the LOCI
SP0256$03F1allophone speech synthesis (Mageco card)
MEA 8000$03FE-$03FFformant speech synthesis (TMPI card)
hostfs—a host folder shared with the Oric
ULA-NG$0340-$035Fthe 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.

TransportKindUse
loopbacktransparentwhat is sent comes back (tests)
tcp:host:porttransparenta BBS, a Minitel server, telnet, a MIDI router
ptytransparenta POSIX pseudo-terminal (minicom, screen)
com:...transparenta real serial port on the host
file:in[:out]transparentdeterministic replay and capture, with no network
midi[:target]transparenta host MIDI port (ALSA, CoreMIDI, WinMM)
smf:song.midtransparenta MIDI file played into the Oric, at the song’s tempo
modem[:host:port]protocola Hayes AT command interpreter
picowifi[:...]protocolthe 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=1 build, 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. LPRINT and LLIST are 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).

Sources in the repository : README.md, docs/architecture/io-bus.md, docs/CARTES.md, docs/adr/0006-cartes-en-modules.md, docs/COMPATIBILITY.md.