Skip to content

Commit 94b4fe7

Browse files
Add 3do/ subdir (baseline -- v0.1.0, no release yet)
Scaffolds the 3DO Opera test app following the established per- console pattern (VERSION / CHANGELOG / LICENSE / README / Makefile- free Docker build / etc.). v0.1.0 is the bring-up baseline: builds a 2.5MB .iso via trapexit/3do-devkit and renders P1's live 32-bit DoControlPad bitfield + per-button held labels. Toolchain notes: - trapexit/3do-devkit ships pre-built Norcroft ARM C compilers + 3DO tools as Linux x86 binaries only. The 3doiso step is a Windows binary that runs under wine. Our buildtools/Dockerfile clones the devkit at a pinned commit, adds libc6-i386 + wine32, and pre-makes the devkit tree everyone-writable so the host-uid'd container run can overlay our src/main.cpp on top. - On Apple Silicon / non-x86 hosts the container runs under --platform=linux/amd64 (CI's ubuntu-latest is native amd64, no emulation overhead). - Wine wants HOME to be owned by the running user; bind-mount-backed /work/.wine-home works because /work belongs to the host user. Wired into both CI workflows: - verify-build.yml gets a new matrix entry + Build (3DO) step. CI picks up every push to main. - release.yml gets the `3do)` parse-case + Build (3DO) + Stage (3DO) steps -- dormant until a `3do-v<semver>` tag is pushed. The release artifact name is joypad_tester_v<ver>_3do.iso. Documentation: - README.md Consoles + Acknowledgements tables gain 3do. - CLAUDE.md existing-subdirs list gains 3do with toolchain caveats. - .dev/docs/3do_roadmap.md tracks the queued v0.2+ work: multi-controller polling (up to 8 pads), per-port device-type detection (mouse / lightgun / sillypad / steering wheel, with parsed values + 3dodev.com refs), GameCube-style logo header, custom Joypad boot/splash replacing the devkit placeholder, and the matching joypad-logo bouncing screensaver (7-color cycle to match gcn/gba/pce). Reference for the v0.2+ work: Charles Doty (RasterSoft)'s 3DO Controller Test Multi (2016, "free of any licences"); its 8-pad polling loop + pure-C Sprite renderer are the patterns we'll lean on. We didn't vendor any of his code into v0.1.0.
1 parent 2d82ee8 commit 94b4fe7

13 files changed

Lines changed: 556 additions & 0 deletions

File tree

.dev/docs/3do_roadmap.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# 3DO roadmap (v0.2 -> v1.0)
2+
3+
`3do/` v0.1.0 is the bring-up baseline: scaffold + Docker build +
4+
single-pad P1 button readout. v1.0 = feature parity with the other
5+
consoles in the suite.
6+
7+
## Reference: Charles Doty's 3DO Controller Test Multi
8+
9+
[Source on 3dodev.com](https://3dodev.com/software/homebrew/console_tools),
10+
mirrored locally at `~/Downloads/3DOControllerTestMulti/`. Charles
11+
Doty (RasterSoft, 2016) released this "free of any licences, credit
12+
would be appreciated but not required" — so we can crib its patterns
13+
or vendor selected modules directly with credit.
14+
15+
Specific reusable bits in his tree:
16+
- `src/System.c` — 8-pad `InitControlPad(8)` + `readControlPad` loop
17+
- `src/Sprite.c/.h` — pure-C CEL sprite renderer (don't need to
18+
port back from trapexit's C++ `BasicDisplay` if we want lean C)
19+
- `src/Display.c` — screen-buffer + double-buffer setup
20+
- `Banner.bmp` + `Graphics/` — example art layout (the actual art
21+
is RasterSoft branding, not for reuse, but the asset shape is)
22+
23+
When we tackle items below, the first move is "look at Charles
24+
Doty's source for the device pattern, then build our own."
25+
26+
## Pending work (queued for v0.2+)
27+
28+
### 1. Multi-controller support (up to 8 pads)
29+
30+
3DO supports up to 8 control pads via the daisy-chain protocol. Call
31+
`InitControlPad(8)` and render P1..P8 readouts. Render layout needs a
32+
rethink — the current single-screen P1-only layout doesn't scale.
33+
34+
### 2. Device-type detection + parsed values
35+
36+
Beyond the standard control pad, the 3DO supports:
37+
38+
- **3DO Mouse** — X/Y movement, three buttons (L/M/R). API: separate
39+
from `DoControlPad`; uses the event broker. Mouse-event packets
40+
carry deltas and button mask. See https://3dodev.com/ docs on
41+
ControlPad events and event-broker mouse-class IDs.
42+
- **Light Gun** — for games like Mad Dog McCree, Crime Patrol. Lives
43+
on the same daisy-chain electrical interface but reports
44+
(x, y, trigger) per event poll.
45+
- **SillyPad / arcade controllers** — variants that map to standard
46+
pad bits but expose additional pins.
47+
- **Steering wheel** (Capcom CPS Changer-style) — niche, if anyone
48+
actually shipped one.
49+
50+
Per-port detection: probe each daisy-chain slot for its device-class
51+
ID and select the renderer accordingly. Display device-class label
52+
next to "P1/P2/.." (e.g., "P1: Mouse x +12 y -8 L M R").
53+
54+
Authoritative device-type docs live at https://3dodev.com/ — link to
55+
specific page(s) in the per-port renderer comment headers.
56+
57+
### 3. Logo header on main screen
58+
59+
Match the GameCube tester's top-of-screen branded layout: small
60+
joypad logo to the left of the "Joypad Tester - 3DO" title, rendered
61+
as a sprite/cel. Asset comes from `joypad/branding/logo_solid.svg`
62+
(or a 3DO-friendly resized derivative), converted to 3DO's CEL
63+
format via the devkit's `pcxtocel` tool (or equivalent).
64+
65+
### 4. Custom boot/splash screen
66+
67+
Replace the devkit's default banner.png with our own Joypad-branded
68+
splash. The 3DO BIOS reads the splash from the disc's TAKEME/banner
69+
area; bake-in is handled by the devkit's `3doiso` step. Source
70+
asset: `joypad/branding/` (same as other consoles), exported as a
71+
3DO-friendly 320x240 image.
72+
73+
### 5. Bouncing-logo idle screensaver
74+
75+
Identical to gcn/gba/pce: after 30s idle, clear screen and bounce
76+
the 64x64 joypad logo around the visible area, color-cycling through
77+
red -> green -> yellow -> blue -> magenta -> cyan -> white on each
78+
wall bounce, same step rate as the other consoles. Implementation
79+
uses the devkit's cel/sprite API + a small palette-mutate loop.
80+
81+
### 6. Public release
82+
83+
Tag `3do-v1.0.0` once items 1-5 land and the result is verified on:
84+
85+
- RetroArch with Opera core (4DO emulation)
86+
- Real 3DO hardware (CD-R burn) or an ODE
87+
88+
The release workflow + tag-prefix wiring is already in place
89+
(.github/workflows/release.yml has the `3do)` parse case + build +
90+
stage steps); just need the VERSION bump + tag push when ready.

.github/workflows/release.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ jobs:
3636
snes) PRETTY="Super Nintendo" ;;
3737
gba) PRETTY="Game Boy Advance" ;;
3838
pce) PRETTY="PC Engine" ;;
39+
3do) PRETTY="3DO" ;;
3940
*) PRETTY="$CONSOLE" ;;
4041
esac
4142
echo "console=$CONSOLE" >> "$GITHUB_OUTPUT"
@@ -112,6 +113,26 @@ jobs:
112113
joypad-tester-huc:release \
113114
make
114115
116+
- name: Build (3DO)
117+
if: needs.parse.outputs.console == '3do'
118+
run: |
119+
cd 3do
120+
mkdir -p build .wine-home
121+
docker build --platform=linux/amd64 -t joypad-tester-3do:release buildtools/
122+
docker run --rm \
123+
--platform=linux/amd64 \
124+
-v "$(pwd):/work" \
125+
-u "$(id -u):$(id -g)" \
126+
-e HOME=/work/.wine-home \
127+
joypad-tester-3do:release \
128+
bash -c "
129+
set -e
130+
cp /work/src/main.cpp /opt/3do-devkit/src/main.cpp
131+
cd /opt/3do-devkit
132+
make NAME=joypad-tester
133+
cp iso/joypad-tester.iso /work/build/joypad-tester.iso
134+
"
135+
115136
- name: Stage release artifacts (GameCube)
116137
if: needs.parse.outputs.console == 'gcn'
117138
working-directory: ${{ needs.parse.outputs.console }}
@@ -185,6 +206,16 @@ jobs:
185206
cp build/joypad-tester.pce "_release/joypad_tester_v${VERSION}.pce"
186207
ls -la _release/
187208
209+
- name: Stage release artifacts (3DO)
210+
if: needs.parse.outputs.console == '3do'
211+
working-directory: 3do
212+
run: |
213+
# Single .iso artifact; emulators + flash-friendly burn target.
214+
VERSION="${{ needs.parse.outputs.version }}"
215+
mkdir -p _release
216+
cp build/joypad-tester.iso "_release/joypad_tester_v${VERSION}_3do.iso"
217+
ls -la _release/
218+
188219
- name: Build release body
189220
id: notes
190221
working-directory: ${{ needs.parse.outputs.console }}

.github/workflows/verify-build.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ jobs:
3737
image: ""
3838
artifacts: |
3939
pce/build/joypad-tester.pce
40+
- console: 3do
41+
# trapexit/3do-devkit cloned at pinned commit inside
42+
# 3do/buildtools/Dockerfile -- see the Build (3DO) step.
43+
image: ""
44+
artifacts: |
45+
3do/build/joypad-tester.iso
4046
steps:
4147
- name: Checkout
4248
uses: actions/checkout@v4
@@ -104,6 +110,30 @@ jobs:
104110
joypad-tester-huc:ci \
105111
make
106112
113+
- name: Build (3DO)
114+
if: matrix.console == '3do'
115+
run: |
116+
# ubuntu-latest is x86_64, so the --platform=linux/amd64 in
117+
# the Dockerfile is a no-op (no emulation needed). The
118+
# devkit + i386/wine setup gets cached in the image so only
119+
# the first run is slow.
120+
cd 3do
121+
mkdir -p build .wine-home
122+
docker build --platform=linux/amd64 -t joypad-tester-3do:ci buildtools/
123+
docker run --rm \
124+
--platform=linux/amd64 \
125+
-v "$(pwd):/work" \
126+
-u "$(id -u):$(id -g)" \
127+
-e HOME=/work/.wine-home \
128+
joypad-tester-3do:ci \
129+
bash -c "
130+
set -e
131+
cp /work/src/main.cpp /opt/3do-devkit/src/main.cpp
132+
cd /opt/3do-devkit
133+
make NAME=joypad-tester
134+
cp iso/joypad-tester.iso /work/build/joypad-tester.iso
135+
"
136+
107137
- name: Upload artifacts
108138
uses: actions/upload-artifact@v4
109139
with:

3do/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
build/
2+
_release/
3+
.wine-home/
4+
.DS_Store

3do/CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Joypad Tester — 3DO — Changelog
2+
3+
## v0.1.0 — 2026-05-12
4+
5+
First release. Bring-up of the 3DO controller test ROM via the
6+
trapexit/3do-devkit toolchain.
7+
8+
### Highlights
9+
10+
- Live P1 button readout: raw 32-bit `DoControlPad` bitfield rendered
11+
on screen, plus per-button labels for the 11 standard 3DO inputs
12+
(D-pad, A/B/C, Start, Stop, L/R shifts).
13+
- Two-pad slot reserved in the polling code (`InitControlPad (2)`) —
14+
P2 hex is shown alongside P1; full P2 button-grid display comes
15+
next.
16+
17+
Full feature breakdown + build / loading instructions in
18+
[`3do/README.md`](https://github.com/joypad-ai/joypad-tester/blob/main/3do/README.md).

3do/LICENSE.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Robert Dale Smith
4+
5+
The Joypad Tester 3DO ROM source (`src/main.cpp`) is original work
6+
licensed under MIT.
7+
8+
The build pipeline depends on Antonio SJ Musumeci's
9+
[3do-devkit](https://github.com/trapexit/3do-devkit) (ISC), which is
10+
cloned at a pinned commit by `buildtools/Dockerfile` and supplies:
11+
12+
- the Norcroft ARM C/C++ compilers,
13+
- 3DO Portfolio SDK headers / libraries,
14+
- the `BasicDisplay` C++ helper class + `abort_err` panic handler
15+
(used unmodified from the devkit's `src/`).
16+
17+
`BasicDisplay` (`display.cpp`/`.hpp`) and `abort.c`/`abort.h` are
18+
trapexit's ISC code, linked into our LaunchMe as part of the
19+
standard devkit build. Their copyright + ISC notice live in the
20+
devkit repository.
21+
22+
The 3DO Portfolio SDK headers (`include/3dosdk/`) are originally
23+
copyrighted by The 3DO Company; they are widely redistributed
24+
within the 3DO homebrew scene and ship inside the trapexit devkit
25+
that we depend on at build time.
26+
27+
---
28+
29+
Permission is hereby granted, free of charge, to any person obtaining a copy
30+
of this software and associated documentation files (the "Software"), to deal
31+
in the Software without restriction, including without limitation the rights
32+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33+
copies of the Software, and to permit persons to whom the Software is
34+
furnished to do so, subject to the following conditions:
35+
36+
The above copyright notice and this permission notice shall be included in all
37+
copies or substantial portions of the Software.
38+
39+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
45+
SOFTWARE.

3do/README.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Joypad Tester — 3DO
2+
3+
3DO Opera (Panasonic FZ-1 / FZ-10, GoldStar GDO, Sanyo TRY, etc.)
4+
build of the [Joypad Tester](../README.md). Reads the 3DO control
5+
pad daisy-chain and renders the live button state on screen.
6+
7+
## What it tests
8+
9+
The active 3DO control pad's full 32-bit `DoControlPad` bitfield,
10+
shown as raw hex plus a per-button held-or-not grid:
11+
12+
```
13+
Joypad Tester - 3DO
14+
===================
15+
16+
P1 raw: 0x00000000
17+
P2 raw: 0x00000000
18+
19+
P1 buttons:
20+
. .
21+
. .
22+
. .
23+
. .
24+
. .
25+
.
26+
```
27+
28+
| Source | Detected as |
29+
|--------|-------------|
30+
| 3DO control pad (D-pad, A/B/C, Start, Stop, L/R shift) | `DoControlPad` slot 1 / slot 2 |
31+
| 3DO mouse / lightgun / arcade panel | not yet wired (uses different SDK calls) |
32+
33+
Buttons rendered: Up, Down, Left, Right, A, B, C, Start, Stop, L (Left
34+
Shift), R (Right Shift). "Stop" is the X button on the original 3DO
35+
pad — its symbol is the eject-style square.
36+
37+
## trapexit/3do-devkit toolchain
38+
39+
3DO homebrew is built with the Norcroft ARM C/C++ compilers (originally
40+
1990s ARM Ltd / Acorn) bundled in
41+
[trapexit/3do-devkit](https://github.com/trapexit/3do-devkit). The
42+
devkit also ships 3DO Portfolio SDK headers + a small modern C++
43+
helper layer (`BasicDisplay`, `abort_err`, etc.) that we link
44+
against unmodified. We pin to a specific devkit commit
45+
(`e0845bc4` at v0.1.0) inside [`buildtools/Dockerfile`](buildtools/Dockerfile);
46+
bumping it = rebuilding the image.
47+
48+
The compilers are 32-bit x86 binaries (Linux only) — and one
49+
post-compile step (`3doiso`) is a Windows binary the devkit runs via
50+
Wine. The Docker image bakes both: `libc6-i386` for the 32-bit
51+
dynamic loader, `wine32` for the iso composer. On Apple Silicon or
52+
any non-x86 host, the container runs under `--platform=linux/amd64`.
53+
54+
## Build
55+
56+
The toolchain is Docker-only:
57+
58+
```
59+
./build_docker.sh # build (first run also builds image)
60+
./build_docker.sh clean # nuke build/
61+
./build_docker.sh rebuild-image # force toolchain image rebuild
62+
```
63+
64+
`build/joypad-tester.iso` is the in-tree output. CI builds on every
65+
push to `main` (see
66+
[`.github/workflows/verify-build.yml`](../.github/workflows/verify-build.yml)).
67+
68+
## Loading on hardware
69+
70+
### 3DO emulator (Opera / Phoenix / RetroArch's Opera core)
71+
72+
Drop `joypad_tester_v<ver>.iso` onto the emulator. Opera-based
73+
cores require a 3DO BIOS dump in their `system/` directory
74+
(`panafz1.bin` / `panafz10.bin` / `goldstar.bin` / `sanyotry.bin`).
75+
76+
### Real 3DO hardware
77+
78+
Burn the `.iso` to CD-R (700 MB blank, ISO mode — 3DO Opera
79+
filesystem is iso9660-compatible enough that standard burning tools
80+
handle it). Boot on a chipped console; unmodified retail consoles
81+
won't boot homebrew CDs.
82+
83+
ODE / SD-loader options like the
84+
[Plextor / Polymega-replacement chips](https://3dodev.com/) are
85+
the contemporary path; check 3dodev.com for current hardware notes.
86+
87+
## Releases
88+
89+
Tagged as `3do-v<semver>` from the repo root — see
90+
[`3do/CHANGELOG.md`](CHANGELOG.md) for per-version notes. The release
91+
workflow attaches `joypad_tester_v<semver>_3do.iso` to each GitHub
92+
Release.
93+
94+
## Origin / credits
95+
96+
Built on Antonio SJ Musumeci's
97+
[3do-devkit](https://github.com/trapexit/3do-devkit) (ISC) — see
98+
[`LICENSE.md`](LICENSE.md). The Joypad Tester source
99+
(`src/main.cpp`) is original; `BasicDisplay` + `abort_err` come
100+
verbatim from the devkit and link in as part of the standard
101+
homebrew build.
102+
103+
3DO Portfolio SDK headers / libraries shipped within the devkit are
104+
originally copyrighted by The 3DO Company and widely redistributed
105+
in the 3DO homebrew scene.
106+
107+
Charles Doty (RasterSoft) wrote the original
108+
**3DO Controller Test Multi** (2016) — released "free of any licences,
109+
credit would be appreciated but not required". Distributed in the
110+
homebrew scene by Aer Fixus. Source is available on
111+
[3dodev.com](https://3dodev.com/software/homebrew/console_tools).
112+
Their 8-pad polling loop + Sprite/CEL rendering modules are the
113+
reference shape for our v0.2 multi-controller + screensaver work
114+
(see `.dev/docs/3do_roadmap.md`). v0.1.0 is a from-scratch bring-up
115+
against the modern trapexit devkit's `BasicDisplay` helper.

3do/VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0.1.0

0 commit comments

Comments
 (0)