Documentation › Architecture
Technical architecture — OricTel
Overview
OricTel is made of two independent subsystems:
- Oric program (6502 C/ASM) — the Minitel terminal.
- Python bridge — a WebSocket ↔ TCP gateway.
Data flow
Minitel server (ws://3617.fr/ws)
|
| WebSocket (binary frames, raw Videotex bytes)
v
+-------------------+
| orictel_bridge.py | Python asyncio
| TCP port 3615 | Transparent bidirectional relay
+-------------------+
|
| TCP socket (raw bytes, no framing)
v
+-------------------+
| Phosphoric | Oric emulator
| TCP ACIA backend | --serial tcp:127.0.0.1:3615
| V23 mode | --serial-v23 (1200/75 baud)
+-------------------+
|
| ACIA 6551 registers @ $0380-$0383 (LOCI base)
| Cycle-accurate timing
v
+-------------------+
| OricTel program | 6502 code (cc65)
| |
| serial_asm.s | <-- Low-level ACIA driver
| videotex.c | <-- Protocol state machine
| display.c | <-- HIRES rendering
| keyboard.c | <-- Keyboard scan + mapping
| main.c | <-- Main loop
+-------------------+
Oric memory map
$0000-$00FB Zero Page (cc65: $00E2-$00FB)
$0100-$01FF 6502 stack
$0200-$02FF System variables
$0300-$030F VIA 6522 (mirror $0300-$03FF)
$0380-$0383 ACIA 6551 (serial, LOCI base)
$0400-$0500 Oric system area
$0501-$97FF OricTel CODE + DATA (~37 KB)
$9800-$9FFF BSS / cc65 stack (2 KB)
$A000-$BF3F HIRES framebuffer (8000 bytes)
$BB80-$BFDF Text screen (rows 25-27 = status bar)
$C000-$FFFF ROM (16 KB)
ACIA 6551 registers (Oric side)
| Address | Read | Write |
|---|---|---|
$0380 | Received data | Data to send |
$0381 | Status register | Program reset |
$0382 | Command register | Command register |
$0383 | Control register | Control register |
Minitel V23 configuration
- Control:
$28= 1200 baud, 7 bits, 1 stop - Command:
$69= DTR on, RX IRQ off, even parity enabled
Status register bits
- Bit 3 (RDRF=
$08): received data available - Bit 4 (TDRE=
$10): transmitter ready
Videotex protocol — state machine
NORMAL ──ESC($1B)──> ESC_SEQ
──US($1F)───> US_ROW
──SO($0E)───> (switch to G1)
──SI($0F)───> (switch to G0)
──$20-$7F──> (display character)
──$08-$0B──> (cursor move)
──$0C─────> (clear screen)
──$0D─────> (carriage return)
ESC_SEQ ──$40-$47──> (ink colour) -> NORMAL
──$50-$57──> (background colour) -> NORMAL
──$48/$49──> (flash on/off) -> NORMAL
──$4C-$4F──> (size) -> NORMAL
──$5B─────> CSI
──$39─────> PRO
US_ROW ──$40-$57──> US_COL (stores row)
US_COL ──$41-$68──> NORMAL (positions cursor)
CSI ──params+letter──> NORMAL (ANSI-like command)
HIRES display
- Resolution: 240×200 pixels = 40 columns × 25 rows
- Each cell: 6×8 pixels
- 3 character sets:
- G0: alphanumeric (Minitel ASCII, French accents)
- G1: semigraphic mosaics (2×3 blocks = 64 patterns)
- G2: additional characters (diacritics)
Per-cell attributes
- Ink colour (0-7)
- Background colour (0-7)
- Flash
- Video inverse
- Underline / mosaic separation
- Size (normal, double height, double width, double size)
- Conceal
Optimised rendering (dirty rectangles)
Each modified cell is marked “dirty”. Each frame (50 Hz), only the modified cells are re-rendered into the HIRES framebuffer. This considerably reduces the 6502's CPU load.
Reproduced from docs/ARCHITECTURE.md (authoritative, up-to-date version on GitHub).