Christian Werner cd0285cc0b
Some checks failed
Build kernel module / build (1:6.12.93-1+rpt1) (push) Failing after 1m15s
Build kernel module / release (push) Has been skipped
feat(ci): Add arm64 emulation and multi-arch kernel build support
Introduce arm64 emulation setup and enhance the kernel build workflow to
support multi-architecture builds. Updated the process to use Docker
copy commands for compatibility with docker-in-docker environments, ensuring
accurate context access and successful compilation.
2026-06-19 03:55:26 +02:00
2026-06-18 22:25:42 +02:00
2026-06-18 22:25:42 +02:00
2026-06-18 22:25:42 +02:00
2026-06-18 22:25:42 +02:00
2026-06-18 22:25:42 +02:00
2026-06-18 22:25:42 +02:00
2026-06-18 22:25:42 +02:00

comodore-iec-emu — IEC listener PoC

A proof-of-concept Commodore IEC listener device on a Raspberry Pi Zero 2 W. It behaves like a printer (default device address 4): it never talks back, it only listens, and it debug-prints in real time everything the C64 sends.

The timing-critical IEC handshake (ATN ack, per-bit sampling, EOI) runs in a Linux kernel module; a Python userspace program decodes and pretty-prints. See _plans/poc-listener-printer-PLAN.md for the full design and _research/ for the grounding research.

Layout

kernel/        # the kernel module (real-time half) — builds on the Pi
  iec_listener.c   ISR, IRQ-off bit loop, listener state machine, /dev/iec0
  iec_listener.h   shared struct iec_record + ioctls (mirrors device.py)
  iec_lines.h      logical line layer, direct BCM register access (hot path)
  iec_timing.h     handshake timing constants
  Makefile         out-of-tree build + load/unload/overlay targets
  dts/             device-tree overlay (pin reservation / pulls)
iecpoc/        # Python userspace (everything else) — host-testable
  device.py        /dev/iec0 record stream (wire format, replay)
  decode.py        command-byte + event decoder
  petscii.py       PETSCII -> display glyphs
  log.py           the annotated trace formatter (PLAN §8)
  main.py          CLI (--address, --raw, --logfile, --replay)
tests/         # host-runnable, no Pi/kernel needed
docs/          # wiring.md, kernel-notes.md

Userspace (Phase 0 — works on any host)

python3 -m venv .venv && .venv/bin/pip install -e '.[dev]'
.venv/bin/pytest                                  # run the tests
.venv/bin/python -m tests.fixtures                # (re)generate the capture
.venv/bin/python -m iecpoc.main --replay tests/data/hello_world_session.bin

On the Pi, point it at the live device instead:

.venv/bin/python -m iecpoc.main --address 4       # reads /dev/iec0

Example trace (the OPEN 1,4 / PRINT# / CLOSE session, abbreviated):

[IDLE]   waiting for ATN
[ATN]    asserted -> DATA low (ack)
[CMD]    $24  LISTEN 4          (addressed: ME)
[CMD]    $60  DATA  SA=0
[ATN]    released -> LISTENER
[DATA]   $48 'H'
...
[DATA]   $0D <CR>   <EOI>
[ATN]    released -> not addressed -> IDLE

Kernel module (on the Pi)

sudo apt install raspberrypi-kernel-headers
cd kernel && make
sudo insmod iec_listener.ko address=4    # creates /dev/iec0
sudo rmmod iec_listener                  # releases DATA on unload

See docs/wiring.md for the level-shifter circuit and the pre-C64 bring-up checklist, and docs/kernel-notes.md for the resolved kernel real-time decisions.

Status

  • Phase 0 (userspace + tests): complete, runs on any host.
  • Phase 1 (kernel command phase): skeleton present; needs Pi bring-up.
  • Phase 2 (data-phase reception): the real experiment; tune timing on real hardware.

See PLAN.md §9 for the phased milestones.

Description
No description provided
Readme 356 KiB
Languages
Python 39.1%
C 32.3%
Shell 22.3%
Dockerfile 4.4%
Makefile 1.9%