The Ember PIA — Initial Design Part 1: Peripheral Interface Adapter
Adding keyboard and gamepad support to the Ember design requires some sort of Peripheral Interface Adapter (PIA). This device will interact with keyboards over PS/2 or USB, and game controllers using USB or their native protocol, then map the various inputs and outputs into registers in shared memory, just like the Flame GPU registers.
Zero Page IO Registers
Like the GPU, the PIA is assigned a specific range of memory addresses in the Ember zero page. In this case, three 256-byte blocks are reserved for user input devices like a keyboard or gamepad. Starting at zero-page address 0x0700, the first 256-byte block contains the PIA control registers and input/output values for connected devices. The next two blocks at 0x0800 and 0x0900 are work RAM reserved for use by the system monitor/console and keyboard buffer. We will cover these in detail when we discuss the Ember firmware design and how system and application code interact with the PIA.
Interrupts
Input on any attached keyboard or control device can generate a CPU interrupt so that when a key or button is pressed or released, or a gamepad stick or trigger is adjusted, an interrupt is sent to the CPU, which is expected to handle reading the change in value and updating any read buffers in memory. Which actions trigger interrupts can be configured in the PIA flags, and either the OS or the application can be configured to handle these or choose to just poll the values directly from the registers.
Basic Configuration Registers
The PIA Global Flags register located at address 0x0700 is used to enable or disable input, interrupts, and other overall settings. The PIA Status Flags register, located at address 0x0710, can be read to determine key up or down state, along with modifier key flags at 0x0704, and the actual scancode, or location in the scan grid of any currently pressed keyboard key, represented by a single 8-bit byte at 0x0708.
Gamepads and Joysticks
The PIA supports up to 4 gamepads or joysticks. The settings and status of each attached device are represented by a 16-byte output block, followed by a 16-byte input block of registers starting at addresses 0x0720, 0740, 0x760, and 0x780.
For player controller 0, the capabilities flags at location 0x0730 can be used to query which buttons, sticks, triggers, or other features are present on an attached device. Depending on the implementation of the emulator, host machine, or FPGA device, not all features may be present or exposed to the Ember software. The other input values indicate the state of up to 16 buttons, two variable triggers, and two proportional sticks.
Keyboard Buffer and System Monitor
While an application can read or write to any of these registers directly, the system will provide a simple default keyboard buffer handler that will queue key up/down and modifier events for the application to read using a system call. Game controller input might also be buffered in a similar way. However, many games will want to poll their own inputs to reduce latency, so that may not be needed.
A simple system monitor program that can be used during debugging might also be interesting. This would allow developers to query and set memory values, load programs, etc. We will cover such an application in a future article.
Next post in this series:
The Ember PIA — Initial Design Part 2: Keyboard Input Handling [Coming Soon!]
Ember Design Series
- The Ember CPU — Initial Design Part 1: Basic Requirements
- The Flame GPU — Initial Design Part 1: Basic Requirements
Back to the beginning of Project Ember:
Going Old-School: Designing A Custom Homebrew Retro Video Game Console From Scratch
Enjoying my content? Support me by buying me a coffee, clapping for this post, and following my page. Thanks so much, and stay safe!