Expand documentation suite: 30+ articles enriched with diagrams, code examples, and hardware details

Graphics: text_fonts (bitmap layout, styles), sprites (DMA, multiplexing), gfx_base (chipset detection), rastport (draw modes, clipping), ham_ehb (mermaid fixes), display_modes (HAM palettes)

Devices: scsi (per-model interfaces, Gayle limits, CD-ROM, native vs vendor drivers), console (ANSI sequences, CON:/RAW:), parallel (CIA registers, pinout), timer (resource exhaustion), gameport (quadrature, XOR state)

Libraries: workbench (WBStartup, AppWindow/Icon/MenuItem), rexxsyslib (ARexx port hosting, command parsing), diskfont (font directory, colour fonts), keymap (rawkey codes, dead keys), locale (catalogue system, date formatting), layers (ClipRect, refresh types), utility (TagItem chains), icon (DiskObject, ToolTypes), iffparse (IFF structure, ByteRun1), expansion (Zorro AutoConfig)

Networking: tcp_ip_stacks (major rewrite - Amiga vs Unix architecture, SANA-II pipeline, PPP/SLIP dial-up, Ethernet cards, MiSTer), bsdsocket (pure API ref), sana2 (buffer hooks, driver requirements), protocols (all code examples). Deduplicated overlap between the three files.

Toolchain: debugging (Enforcer patterns, SnoopDOS, GDB remote, kprintf checklist), sasc (pragma encoding, __saveds idioms), stormc (NEW - StormC IDE, C++, PowerPC)

References: error_codes (DOS, Exec, trackdisk, Intuition error tables)
Driver development: rtg_driver (Native driver analysis, P96 tuning)

All 22 README indexes updated. Root README synced with stormc.md entry.
This commit is contained in:
Ilia Sharin 2026-04-23 21:37:26 -04:00
parent 0ded078134
commit f61c26b542
38 changed files with 6402 additions and 1065 deletions

View file

@ -1,64 +1,130 @@
[← Home](../README.md) · [Devices](README.md)
# gameport.device — Joystick and Mouse
# gameport.device — Joystick and Mouse Ports
## Overview
`gameport.device` reads joystick and mouse ports (active on port 1 for joystick, port 0 for mouse). Uses CIA and custom chip registers.
`gameport.device` provides access to the Amiga's two **controller ports** (mouse/joystick). The hardware reads controller state through custom chip registers `JOY0DAT`/`JOY1DAT` and the CIA-A port for fire buttons. Understanding the hardware protocol is critical for FPGA cores.
---
## Hardware Registers
| Register | Address | Controller | Function |
|---|---|---|---|
| `JOY0DAT` | `$DFF00A` | Port 1 (mouse) | Quadrature-encoded position data |
| `JOY1DAT` | `$DFF00C` | Port 2 (joystick) | Direction bits or quadrature data |
| `JOYTEST` | `$DFF036` | Both | Write to set counter test value |
| `POTGO` | `$DFF034` | Both | Proportional/paddle port control |
| `POTGOR` | `$DFF016` | Both | Read paddle/proportional values |
| CIA-A PRA | `$BFE001` | Both | Fire buttons (active low) |
### JOYxDAT Bit Layout
```
Bits 158: Y counter (or vertical quadrature)
Bits 70: X counter (or horizontal quadrature)
```
### Mouse Quadrature Decoding
For mouse input, the X/Y values are **quadrature counters** — they increment/decrement as the mouse moves:
```c
/* Read mouse delta: */
UWORD joy = custom->joy0dat; /* current counter */
WORD dx = (WORD)(joy & 0xFF) - (WORD)(prev_joy & 0xFF);
WORD dy = (WORD)(joy >> 8) - (WORD)(prev_joy >> 8);
/* dx/dy = movement since last read (signed, wraps at 255→0) */
prev_joy = joy;
```
### Joystick Digital Decoding
For digital joysticks, the direction bits are encoded:
```c
UWORD joy = custom->joy1dat;
BOOL right = joy & 0x0002;
BOOL left = (joy >> 1) ^ (joy & 0x0001); /* XOR of bit 1 and bit 0 */
BOOL down = joy & 0x0200;
BOOL up = (joy >> 9) ^ ((joy >> 8) & 0x0001);
/* Fire button — from CIA-A: */
BOOL fire = !(ciaa->ciapra & 0x80); /* port 2 button, active low */
/* Port 1 fire = bit 6 of CIAA PRA */
```
> [!IMPORTANT]
> The joystick directional decoding uses **XOR** between adjacent bits — not direct reads. This is because the hardware shares the same quadrature interface used for mice. This is a common source of bugs in FPGA implementations.
### Fire Buttons
| Button | Register | Bit | Port |
|---|---|---|---|
| Port 1 fire (left mouse) | CIA-A PRA `$BFE001` | 6 | Mouse port |
| Port 2 fire (joystick) | CIA-A PRA `$BFE001` | 7 | Joystick port |
| Port 1 middle/right | POTGOR `$DFF016` | 8, 10 | Mouse port |
| Port 2 second button | POTGOR `$DFF016` | 12, 14 | Joystick port |
---
## Using gameport.device (OS Level)
```c
struct MsgPort *gpPort = CreateMsgPort();
struct IOStdReq *gpReq = (struct IOStdReq *)
CreateIORequest(gpPort, sizeof(struct IOStdReq));
/* Open port 1 (joystick port): */
OpenDevice("gameport.device", 1, (struct IORequest *)gpReq, 0);
/* Set controller type: */
UBYTE type = GPCT_ABSJOYSTICK;
gpReq->io_Command = GPD_SETCTYPE;
gpReq->io_Data = (APTR)&type;
gpReq->io_Length = 1;
DoIO((struct IORequest *)gpReq);
/* Set trigger conditions: */
struct GamePortTrigger trigger;
trigger.gpt_Keys = GPTF_UPKEYS | GPTF_DOWNKEYS;
trigger.gpt_Timeout = 0; /* no timeout */
trigger.gpt_XDelta = 1; /* report on any movement */
trigger.gpt_YDelta = 1;
gpReq->io_Command = GPD_SETTRIGGER;
gpReq->io_Data = (APTR)&trigger;
gpReq->io_Length = sizeof(trigger);
DoIO((struct IORequest *)gpReq);
/* Read events: */
struct InputEvent ie;
gpReq->io_Command = GPD_READEVENT;
gpReq->io_Data = (APTR)&ie;
gpReq->io_Length = sizeof(ie);
SendIO((struct IORequest *)gpReq);
/* Wait for joystick event: */
Wait(1L << gpPort->mp_SigBit);
WaitIO((struct IORequest *)gpReq);
/* ie now contains joystick movement/button data */
```
---
## Controller Types
```c
/* devices/gameport.h */
#define GPCT_ALLOCATED -1 /* port is allocated */
#define GPCT_NOCONTROLLER 0 /* nothing connected */
#define GPCT_MOUSE 1 /* mouse */
#define GPCT_RELJOYSTICK 2 /* relative joystick (proportional) */
#define GPCT_ABSJOYSTICK 3 /* absolute joystick */
```
---
## Reading a Joystick
```c
struct IOStdReq *gp = CreateStdIO(port);
OpenDevice("gameport.device", 1, (struct IORequest *)gp, 0);
/* Set controller type: */
UBYTE type = GPCT_ABSJOYSTICK;
gp->io_Command = GPD_SETCTYPE;
gp->io_Data = &type;
gp->io_Length = 1;
DoIO((struct IORequest *)gp);
/* Set trigger conditions: */
struct GamePortTrigger trigger = {
GPTF_UPKEYS | GPTF_DOWNKEYS, /* report buttons */
10000, /* X delta timeout */
10000, /* Y delta timeout */
1, 1 /* X/Y delta threshold */
};
gp->io_Command = GPD_SETTRIGGER;
gp->io_Data = &trigger;
gp->io_Length = sizeof(trigger);
DoIO((struct IORequest *)gp);
/* Read events: */
struct InputEvent ie;
gp->io_Command = GPD_READEVENT;
gp->io_Data = &ie;
gp->io_Length = sizeof(ie);
DoIO((struct IORequest *)gp);
/* ie.ie_Code, ie.ie_position.ie_xy give button/direction */
CloseDevice((struct IORequest *)gp);
```
| Constant | Value | Device |
|---|---|---|
| `GPCT_MOUSE` | 1 | Standard Amiga mouse |
| `GPCT_RELJOYSTICK` | 2 | Relative joystick (proportional) |
| `GPCT_ABSJOYSTICK` | 3 | Absolute/digital joystick |
---
## References
- NDK39: `devices/gameport.h`
- NDK39: `devices/gameport.h`, `hardware/custom.h`, `hardware/cia.h`
- HRM: *Amiga Hardware Reference Manual* — Controller Ports chapter
- See also: [input.md](input.md) — input handler chain that receives gameport events
- See also: [keyboard.md](keyboard.md) — keyboard shares CIA-A interrupt infrastructure