Heath8080A — Product Design : PAM/8 GUI
Page last updated
On this page
Management of the PAM/8 GUI window is split between the event loop, which handles all the mouse-down and key-down events for the front panel, and a drawing routine that keeps the window itself updated. All of the PAM/8 I/O ports are managed by the I/O package.
This page focuses on keypad handling, which is done in the event handler, LED drawing, which is done in panel drawing, and sound, which is done entirely in the I/O package.
When there's a mouse-down event in the body of the GUI window, it may be on a front-panel keypad button.
The buttons are icons drawn on adjacent 36 x 36 pixel squares. Our requirements for mouse-down notification are very simple, so I bypassed the overhead of using controls to represent the buttons and handle the mouse-down events locally.
If the point hit is not within the keypad rectangle, it's ignored. Otherwise, the point is scaled by subtracting the top and left rectangle offset so that we're working from an origin of zero. The event handler maintains an array of buttons, starting at the top left and working across then down to the bottom right. An index to that array is developed from this scaled v & h coordinate pair:
keyHit = (v/36)*4 + (h/36);
The key table contains the key code to put on PAM's input port (360q) and a button-down version of the icon, which is drawn. Key code values are:
The button stays down as long as you keep the mouse button down. When the subsequent mouse-up event comes in, the no-key value (377q) is placed on PAM's input port and the button-up version of the icon is drawn.
The two-key sequences, 0-# and 0-/, are entered by holding down the keyboard option key while clicking the # or / button, respectively. Option-/ resets the H8 hardware. Option-#, Return to Monitor, forces a clock interrupt and places the value 0x2e (the value of the # key in the high bank and the 0 key in the low bank) on the PAM/8 keypad input port.
For convenience and speed in operating the emulator, I mapped certain Mac keyboard keys to emulator functions so that, for example, to enter a "go" command you can click the '4' key on the GUI using the mouse, type '4' on the keyboard, or type 'g' on the keyboard.
Key-down events are processed for the GUI only if the GUI window is front. Keys are mapped as follows:
Usage example: to set PC to 040.100a and go, enter this command string:
r p a 0 4 0 1 0 0 a g
... which is equivalent to this command string:
. 6 / 0 4 0 1 0 0 / 4
There is no state checking in the emulator: we don't verify that 'p' is only used after 'r'. Pressing 'p' is the same as pressing '6' and any user-interface state-related processing is done by PAM/8 as if the front panel keypad were being used.
Both upper and lower case characters are supported.
The two-key sequences, 0-# and 0-/, are entered by holding down the keyboard option key while typing the # or either / key. Option-/ resets the H8 hardware. Option-#, Return to Monitor, forces a clock interrupt and places the value 0x2e on the PAM/8 keypad input port.
The implementation goes generally like this:
The scheduling loop decrements the key-down timer and when it expires, puts the no-key code (377q) onto port 360q (ref. time distribution).
PAM/8 expects keystrokes to stay on the port for at least 20ms. I felt that 30ms was a good length of time to keep the key on the port, and it has proven to be very responsive in practice, keeping up with fairly fast typing.
The H8's 8-segment LEDs are managed by PAM/8. The LEDs themselves, when written, will flash briefly and then blank, and have to be repeatedly refreshed so that, to the user, they appear to be on constantly. If the LED is not refreshed, it will go blank. This happens when interrupts are disabled for too long — say, during a disk I/O operation — or when front panel refresh is disabled.
PAM/8 refreshes one LED every 2ms clock tick; a given LED will be refreshed every 18ms. The refresh is done in reverse order, right to left. PAM starts by outputting the selected digit index in the low-order nibble of the hardware control port (360q). (The high-order nibble holds hardware flags that control sound, the clock, the single-step instruction interrupt and the monitor lamp.) The LED segment pattern is then output to port 361q.
LED segments are active-off — zero bits are on and one bits are off. Bits correspond to segments as shown in the figure. (Bit zero is the low-order bit.)
The LEDs are addressed with indices of '1' through '9'. Front panel LED refresh can be disabled by setting the UO.NFR bit in the .MFLAG byte in PAM/8's workspace. In that case, the first OUT still takes place but the selected LED index is '0'.
Redrawing a LED every two milliseconds is way too much overhead, so the emulator will buffer output digit patterns. The front panel LEDs are updated en mass immediately before checking for Macintosh events (every 25ms if we're in the foreground and every 10ms if background; ref. time distribution). To simulate blanking when refresh stops, the time of the last refresh is kept. If an LED is not refreshed within 50ms, its pattern is set to 377q — all segments off.
In order to reduce overhead even further, we only redraw the segments that change from draw to draw. To do that, we keep a before and after picture of each LED. Before drawing, the before and after segment patterns are XOR'd together to create a mask; the '1' bits in the mask represent changed bits. Only the "after" segments that correspond with '1' bits in the mask are actually drawn.
While the emulator doesn't redraw on the same frequency as a real H8, the visual appearance is identical, at least according to my memory of the beast.
The H8's beeps and clicks are produced in the I/O package.
A real H8 will produce sound by resetting the high-order bit of the byte output to the control port (360q). (The bit is active-on.) While any program can produce sound by setting and resetting this bit, PAM/8 produces only three sounds:
The emulator ignores the short sound, counting on the Mac keyboard and mouse to produce effective feedback. The medium sound is produced by playing a sound resource.
The long alarm is produced by allocating a sound channel and playing a suitable tone using SndDoCommand. This was a simple thing under Mac OS System 8.5, but under System 9.1, I have to clock the sound down myself and clear the channel to clear the sound.