The Feature Board Project

Feature Board

Why and how

Although at its time ahead of most other desktop systems, the HP 9845 lacked some features which would have made the system even more versatile and useful.

Just as an example, the 9845 series did not have the capability to boot its operating system from mass storage. It simply was not part of the concept. The 9845 should be ready to use almost immediately after powering up, which could only be achieved with all necessary OS code in ROM. However, simply the option to load alternative OS code from mass storage (e.g. via HP-IB) would have required just a handful of additional code lines in ROM, a so-called boot loader. HP changed this with the later 98x6 series. Another example is that the 9845 did not even have an option for providing a hardware random number generator, which again had been somewhat strange for a system which had really strong claims in statistical computing. Finally there is the lack of a more flexible color look-up table for the HP 9845C, which would have made the 9845 a first choice for digital image processing, even with just eight colors at one time.

To be honest, HP's engineers did a quite good job, and every HP 9845 provides lots of extensibility in terms of memory expansions and I/O interface modules. Beyond connecting to the outside world, the I/O interfaces can also be used for extending the mainframe functionality, the 98035A real time clock is an example. In total, HP provided nine different pluggable I/O modules, and a tenth interface, the 98037A, was developed but never released to the market.

Now there is one functional area which in total was never addressed by HP with the HP 9845, and this is multimedia. The HP 9845 did have a beeper, but not sound. The system was highly engineered in many aspects, but lacked simple features like joystick controller ports. So there are in deed many games which have been developed for the HP 9845 series, but all without sound and usable controllers.

I started already in the Games Design Tutorial section with a what-would-be-if reasoning, and came to the conclusion that adding sound and some simple functionality for better game design would have made the 9845 an even more interesting system. Especially for game development and multimedia applications. And don't tell me that it would not have been a selling point for HP's main customer target groups, any scientist or engineer would have tried to convince his manager that exactly this functionality would be indispensible for his work.

So I decided to design my own draft of a hardware extension for the HP 9845. It should be a type of extension which does not require any change of the system itself, i.e. it should, if possible, not be necessary to open the mainframe. It should use only hardware components which had already been available at the time of the HP 9845. And it should fit seamlessly into the hard- and software architecture of the HP 9845 for utilizing the added functionality from BASIC and assembly programs.

Actually, I am still in the design phase of what I call the FeatureBoard. In other words, I did not yet solder anything. Everything you find on this page currently is theory only. But the concept is already in a state, where I would like to open the diskussion for it and give anyone who is interested the opportunity to tell me what kind of nonsense I have designed, or even better give me some suggestion how to improve my design (please use the contact feature to write down your ideas).

The FeatureBoard is designed as a standard interface module for the HP 9845, and as such in principle can be used also with a HP 9825 and HP 9835. A nice side effect of designing the FeatureBoard is to learn how HP 980xx interfaces work in general.

Background: Programmable Sound Generators

The history of digital sound synthesis goes back to the year 1950 or 1951 to Australia's first digital computer, the CSIRAC (=Council for Scientific and Industrial Research Automatic Computer, also known as CSIR Mk1 before it moved to the University of Melbourne in 1955) as the first known computer which was capable of playing music, and to the Ferranti Mark 1, which was the first known computer used for recording digital music (yes, the recording is available in the web, of course).

The design of the CIRAC as a vacuum valve driven serial data processor simplified generating music, since all data which was stored in registers or memory produced a serial bit stream during processing, which then could be translated into pulses by simply connecting an amplifier with speaker to one of the registers. Each change in the bit stream then produced a noticeable click sound, which, with the right delays, could produce square waves with different wave length or frequency. Which again produced tones with adjustable pitch.

It is reported that composing with the CSIRAC had been one of the more sophisticated programming tasks, since pitch and duration depended highly on real time programming skills and knowledge of the systems architecture.

CSIRAC

CSIRAC from 1950

Sound generation on the Ferranti Mark 1 (actually a commercial descendant of the Manchester Mark 1) worked quite similar. A click sound was produced by the "hoot" instruction, which (in contrast to the CSIRAC) already was part of the system design for signalling attention to the operator. Used in the fastest possible program sequence, the hoot command could be used to produce a tone with a frequency of 521 Hz (about middle C).

In fact, the (much later) Apple II used exactly the same mechanism to produce sound and music, but about 27 years after the pioneers.

During the late 70s, computers got increasingly popular for entertainment use in both the arcade and home computing area, so affordable digital sound synthesis got more and more into the focus. Early systems used diskrete circuits for producing sound and music, however with the rise of integrated circuits, the first dedicated sound chips were produced.

Probably the most prominent examples are General Instruments AY-3-8910 (use in the famous Apple II Mocking Board, the Atari ST, and many arcade systems and game consoles) and Texas Instruments SN76489 (used in the TI-99/4, many arcade systems and the SEGA game consoles) which opened the market, together with Atari's POKEY (used for the Atari 400/800/XL) and MOS Technologies 6581/8580 SID (used in the Commodore 64 and 128).

PSGs

Early PSGs Stars (Left to Right: Atari POKEY, GI AY-3-8910, MOS 6581/8580 SID, TI SN76489)

The most important capability of these chips was that once instructed by the CPU, each could synthesize sound and music on its own. This had been a big step ahead. Until then the CPU was totally busy with producing the right sound wave, but with the new sound chips the CPU just told the chip what to play, and then could go back performing other tasks (like moving space ships across the screen or checking for user input) while the sound chips did the remaining job. Due to the programmed nature of the sound, these early sound chips were called "programmable sound generators" or just PSGs.

All PSGs were capable of playing multiple sound channels or voices in parallel for polyphonic music. All PSGs also provided at least one noise channel which could be used for rudimentary sound effects. Noise was produced with cyclic pseudo random number generators, none of the PSGs was capable of generating real (white noise) random patterns. Sound could be controlled by the CPU with respect to pitch and volume. Some of the more sophisticated PSGs also could manage to control the sound envelope with programmable attack, decay, sustain and release (ADSR) phases. However by design, all of the PSGs could only perform sound synthesis based on square or triangle waves, which probably was the most important factor for the unique type of sound produced by those chips.

Chip

TI SN76489
TI SN 76489

GI AY-3-8910
GI AY-3-8910/8912

Atari Pokey
Atari POKEY (C012294)

SID
MOS 6581/8580 SID

Available since
1980
1980
1979
1982
Used in
TI-99/4, BBC Micro, IBM PCJr, SEGA consoles (SG, Master System, Game Gear, Mega Drive, Genesis), many arcade systems
Mockingboard, Intellivision, Vectrex, MSX, Amstrad CPC, Oric 1, Colour Genie, Sinclair ZX Spektrum 128, Atari ST, many arcade systems
Atari 400/800, Atari arcade systems
CBM-II, Commodore 64, Commodore 128, Commodore MAX
Voices in total
4
4
2/42
3
Tone channels
3
3
2/42
33
Pitch resolution
8-bit
12-bit
8-bit/16-bit2
16-bit
Noise channels
1
1
2/42
33
Volume resolution
4-bit
4-bit
4-bit
4-bit
Sound envelope
not supported
10 predefined envelopes with hold, alternate, attack, continue plus timing control1
not suported
attack, decay, sustain, release on every channel
Filters
not supported
not supported
high pass
low-pass, high-pass and band-pass
Special features
small packaging
8-bit wide I/O ports (two for 8910, one for 8912)
integrated keyboard controller, timer, interrupt, serial port and 8 analog potentiometer inputs with 8-bit resolution each
four waveforms for each channel (including noise), three ring modulators, external audio mixer input, two analog potentiometer inputs
Packaging
16-pin DIP
40-pin (8910)/28-pin (8912) DIP
40-pin DIP
28-pin DIP

Download
Datasheet

Datasheet
Datasheet
Datasheet
Datasheet
         

1) One envelope for all channels.

2) The POKEY provides 4 sound channels with 8-bit pitch resolution. Two channels can be combined to one single sound channel with 16-bit pitch resolution. Any channel can be configured either as tone or noise channel (the latter with different distortion profiles).

3) Each channel can be configured either as tone or noise generator. The tone generators provide a choice of three waveforms (sawtooth, triangle, pulse).

Later FM sound synthesis and puls code modulation (PCM) replaced the early sound algorithms of the PSGs, allowing much better reproduction of music instruments and voice. But the programmers were quite creative in getting complex sounds out of the PSGs, sounds for which these chips originally never had been designed. A popular approach to simulate PCM for example was to switch the frequency to 0, and just use the 4-bit volume control to play PCM samples (with limited dynamic resolution, of course, but quite capable to produce conceptional voice output). And under heavy load of the CPU.

Requirements

But back to the HP 9845. Sound capabilities were restricted to a single beeper with fixed frequency, pitch and duration. A small circuit is triggered by the keyboard I/O register which then starts a decade counter IC with a single transistor as amplifier for producing the beep.

When we want to add more multimedia capability to the HP 9845, we need something more sophisticated. In fact HP could have decided to use one of the PSG chips which were already available (at least at design time of the 9845B) instead of the simple beep circuit. But HP didn't. HP's engineers probably were not even aware about the sound chips. But we're playing our what-what-be-if scenario. So I decided to design a sound board for the HP 9845 which can use either GI's AY-3-8910 or TI's SN76489 (both chips are still available for an affordable price). Depending on which chip is easier to acquire, the board should support both. And if possible in stereo, requiring at least two of each.

Now using PSGs alone would just hook up with the personal computers or arcade systems of the time, but the HP 9845 was a fast machine, why not try to use it for PCM sound sampling and playback as well? As far as I know, no system in the late 70s had been capable of this. What we basically need would be an analog-to-digital converter (ADC) for sound sampling, and a digital-to-analog converter (DAC) for playback. Sound sampling and playback need constant sampling / playback clocks, so the board should provide its own clock and use direct memory access (DMA) to transfer samples to / from memory without intervention of the CPU (freeing the CPU for other tasks, such as filling memory buffers with samples from mass storage).

ADC/DAC use should not be restricted to audio processing alone, but should also be usable for simple data acquisition tasks (for which a full-fledged instrument would have been oversized), requiring adjustable input sensitivity and sampling rates.

In fact, ADCs with 16-bit resolution as used e.g. for CD Audio would not have been affordable at the time of the HP 9845, so we reduce the dynamics to 8-bit resolution, however still with full stereo. This allows us to keep a stereo sample within one 16-bit word, which again is perfectly suited for processing with an HP 9845.

When we look at game design, there are some other functions which are quite useful, but not provided by standard HP 9845 hardware. First of all, it should be possible to generate interrupts in regular intervals (e.g. for quering controller inputs, moving objects, feeding the sound chips with sound synthesis data or other time related functionality, or just implement a heart beat for an unbuffered real time clock) without the need for a rare and expensive 98035A real time clock. Next, a hardware random number generator seemed quite practical for both gameplay and statistical computing.

Finally, the board should add all controller input ports required for at least two players, with support for common digital as well as analog joysticks and paddle controllers. Trigger buttons should fire interrupts on the HP 9845, so that they can be processed immediately. With the AY-3-8910, another nice feature is available: Each AY-3-8910 provides two 8-bit general purpose I/O ports, so with two chips of that kind, we can utilize a full 32-bit user port with programmable direction, or a 16-bit user port with full-duplex, enough to drive any parallel interface, including printers.

The Feature Board

The FeatureBoard is designed for use with the HP 98x5 desktop computers. It is intended to add a couple of useful functions, which are not available within the standard system configuration (and for some functions also not with any of the original 98x5 interfaces):

Main objective was to add functionality to the 98x5 systems for multimedia & gaming (for having even more fun with those systems). So with the FeatureBoard six fully functional sound channels are added to the 98x5, plus two noise channels for sound effects. Also, digital (wave) audio output is supported with 8-bit sampling resolution and several selectable sampling frequencies from 8 kHz up to 64 kHz, and all that in stereo. For digital audio processing, up to eight analog audio input channels can be digitized, again with sampling frequencies of 8 kHz up to 64 kHz.

Although primarily intended for audio processing, the analog-to-digital and digital-to-analog converters can in principle be used for any digitizing or signal generating task, and with adjustable voltage ranges. The timer can be used both for precisely measuring time intervals and for implementing time controlled processes, such as checking controller inputs in regular intervals, which runs independently of the other system processing. Also the timing behavior of a program can be aligned to a given speed independent of the underlaying system hardware.

Overall Design

The design is oriented towards the original common interface design for the 98x5 desktop computers (two board sandwich design) and aims for authenticity by using components which already were available around 1980 (the release time of the HP 9845B).

The A1 board assembly provides all necessary functionality to interface to the IOD bus of a 98x5 mainframe, including full interrupt and DMA support. The A2 board assembly implements the special functions of the interface such as programmable timer, audio, or random number generator.

The functional register based designs of the existing 980xx interfaces have been preserved in order to fit into the I/O concept of the 98x5 mainframes and especially the I/O capabilities of the IOC processor. So, the FeatureBoard is progammed just like any other 980xx interface with input, output, status and control registers plus flags for interface operational status (STS) and interface ready (FLG) signals.

The FeatureBoard supports three independent types of interrupts (timer, DMA and trigger). Each can be enabled or disabled by setting/clearing the appropriate bit in the control register.

For identification which event is responsible for an individual interrupt, the event which caused the interrupt is indicated by the appropriate bit in the status register. All interrupt status bits are cleared after reading the status register in order to allow the next event to be registered, except the general interrupt enable bit which always reflects the value of the interrupt enable bit in the control register.

The interrupt enable bits in the control register stay set as long as they are not actively cleared by a write to the control register. So the interrupt service routine (ISR) does not need to re-enable interrupts if further interrupts on subsequent events shall be received.

DMA can be used to free the processor for other tasks, and/or - since DMA is performed with selectable clock rates - for continuous (clocked) input processes (such as audio sampling). To notify the program on the end of a DMA block transfer, an interrupt can be requested on transfer completion, so that e.g. a new buffer can be allocated by the program for streaming sampled data to or from a mass storage device.

A DMA transfer immediately starts when being enabled with the appropriate bit in the control register. On the end of each DMA block transfer, DMA will be automatically disabled by the interface and has to be re-enabled for further DMA transfers. DMA always transfers data to or from the lower data register (R4).

The STS line is not used by the FeatureBoard interface (always true). The FLG line is only used for flow control to the SN76489AN PSG chip (if installed). For all other applications there is no need to check the FLG line since the interface can handle all other transfers with maximum IOD bus speed.

Block Diagram

Block Diagram

Feature Board Block Diagram (Click to Enlarge)

The overall design includes two assemblies, one for the interface to the host (A1) and another where all of the boards features are implemented (A2). This design is similar to that of other 980xx interface modules, however the A1 part really implements all of the IOD functionality, inclusing full maskable interrupt capability and DMA in both directions. Also all eight interface registers are decoded.

Register Overview

Programming the FeatureBoard interface is mostly done by reading from and writing to the interface via the memory adresses 4 to 7, which are here referred to as registers R4 to R7. Use of the registers is similar to that for the other 980xx interfaces in that R4, R6 and R7 are primarily used for data transfers to/from the functional building blocks, and R5 is dedicated for control/status purposes:

Registers

All registers are using the full 16-bit range. R7 is shared by the current timer value and the random number generator. Bit 15 (R7 Select) of R5 (the interface control register) determines which one is returned on reads from this register.

Reads from R4 return digital joystick data in the lower 8 bits, and audio sampling data on the current analog input channel in the upper 8 bits. Writes to R4 contain the right channel audo data in the lower 8 bits and the left channel audio data in the upper 8 bits:

Register 4

R5 works as interface status and control register. In general, status and control register work independent of each other, i.e. the value of the status register does not reflect the value of previous writes to the control register. The only exception from this rule are bits 6 (DMA) and 7 (INT) where the programmer can check whether DMA and interrupts are enabled or not. If there is need to keep track of the other values of the control register, this has to be done by the programmer himself.

The individual bits of the interface status register are assigned as follows:

Control Register

with:

Bit 0 TRIG INT - interrupted by any of the two triggers
Bit 1 TIMER INT - interrupted by timer has reached its upper or lower limits
Bit 2 DMA INT - interrupted by end of DMA transfer
Bit 3-5 interface ID (used to identify the interface)
Bit 6 DMA - DMA is enabled
Bit 7 INT - interrupts are enabled
Bit 8 STS - mapped by the mainframe to the STS signal (interface is installed & operational)
Bit 9-10 PSG TYP1, PSG TYP2 - identify the audio hardware installed
Bit 11 TRIG0 - trigger 0 had been pressed
Bit 12 TRIG1 - trigger 1 had been pressed
Bit 13 BUT0 - button 0 is down
Bit 14 BUT1 - button 1 is down

The individual bits of the interface control register are assigned as follows:

Status Register

with:

Bit 0 ENABLE TRIG INT - enable interrupt on trigger
Bit 1 ENABLE TIMER INT - enable interrupt on timer reaching its limits
Bit 2 ENABLE DMA INT - enable interrupt on end of DMA transfers
Bit 3 START TIMER - enables (starts) or disables (pauses) the timer counter
Bit 4

TIMER UP/DOWN - selects the timer counting direction (clear for
counting down, set for counting up)

Bit 5 RESET - setting this bit resets the interface to its power-on state
Bit 6 ENABLE DMA - starts a DMA transfer (automatically cleared on the end of a DMA transfer)
Bit 7 ENABLE INT - general interrupt enable (must be set to enable any interrupt)
Bit 8-10 ADC SELECT0-2 - selects the ADC analog input channel
Bit 11 AUDIO REG ADDR - tells the AY-3-9810 chip that the next value written to R6 is a register address (set this bit for selecting the AY-3-9810 register on the next write to R6, or clear this bit for sending data to the PSG chip via R6)
Bit 12-14 CLK0-2 - selects the interface clock used for timer & DMA
Bit 15

R7 SELECT - determines whether the current timer or a random number is returned on a read from R7

Programmable Timer

HP once designed the 98035A real time clock interface for adding timer functionality to any of the 98x5 mainframes. In fact, the 98035A interface already provides almost every time related functionality, including a battery buffered real-time clock and multiple programmmable timers with interrupt support.

However, the 98034A today is hard to acquire, so some basic timer functionality is also provided by the FeatureBoard. In contrast to the 98035A, the timer range is limited to 65535 counts in total, which however can be scaled to different clocking frequencies from 125 Hz up to 64 kHz, covering time ranges between one second with 15 µsec resolution up to almost 9 minutes with 8 msec resolution.

The timer resolution/counting frequency is controlled by bits 12 to 14 in the control register (write to R5):

+------ CLK2 (bit 14)
|+----- CLK1 (bit 13)
||+---- CLK0 (bit 12)
|||
000 125 Hz
001 250 Hz
010 500 Hz
011 1 kHz
100 8 kHz
101 16 kHz
110 32 kHz
111 64 kHz

Note that the timer clock is also used for DMA transfers. In fact, the range from 125 up to 1 kHz is mostly intended for timer operation, and 8 kHz up to 64 kHz for DMA, however any of the above clock frequencies is usable both for timer and DMA.

There is only one single timer. It can be loaded with any value and configured to count either up or down. The timer can be started/restarted and paused/stopped as needed, even the count direction can be changed at any time, and count elapsed is indicated as timer event when either reaching 65535 in the count-up mode or 0 in the count-down mode (which - if timer interrupt has been enabled - also fires an interrupt).

The current timer value can be read by the processor at any time without influencing the counting process. So the timer can be used as "stopwatch". Apart from the shared clock, there is no further dependency between the timer and the DMA functions, so timer and DMA can be used independently.

A timer event is indicated by a special flag (bit 1) in the status register, which is cleared after reading the data from the status register. The flag will be set everytime the timer reaches its limits, even if timer interrupts are disabled, and therefore also can be polled. Cyclic interrupts can be produced by reloading and restarting the timer in the interrupt service routine (ISR). Typical application for cyclic interrupts are controller queries within games.

The timer is set by writing a 16-bit unsigned value to the auxiliary register (R7). The current timer value can be read by reading the auxiliary register with bit 15 (R7 SELECT) set in the control register. The count direction is up if bit 4 (COUNT UP/DOWN) in the control register is set, and down if bit 4 in the control register is clear. The timer is started (activated) with bit 3 (START TIMER) in the control register set, and stopped (paused) with bit 3 in the control register clear.

Analog-to-Digital-Converters (ADC)

ADC is an input functionality by measuring analog voltages as digital values in constant intervals. The FeatureBoard uses a dedicated ADC chip with eight selectable analog inputs. The first four input channels are wired to the joystick connectors and can be used to sample analog controllers (2-axis analog joysticks or paddles). Analog input channel 4 to 7 are wired to a separate AUX IN connector. If a stereo plug is installed in the audio in jack, analog channels 4 and 5 are used for sampling LINE IN audio input.

The input channel is selected by bits 8 to 10 (ADC SELECT0 to SELECT2) in the control register:

+------ ADC SELECT2 (bit 10)
|+----- ADC SELECT1 (bit 9)
||+---- ADC SELECT0 (bit 8)
|||
111 channel 0 - analog joystick 0 x-axis or paddle 0
110 channel 1 - analog joystick 0 y-axis or paddle 1
101 channel 2 - analog joystick 1 x-axis or paddle 2
100 channel 3 - analog joystick 1 y-axis or paddle 3
011 channel 4 - AUX IN 0 or right audio in
010 channel 5 - AUX IN 1 or left audio in
001 channel 6 - AUX IN 2
000 channel 7 - AUX IN 3

The ADC offers 8-bit resolution, so that full voltage equals 255, and zero voltage equals 0. The result of the digitizing process is mapped to the upper 8 bit of the lower data read register (R4).

Sampling can be performed either by programmed I/O or by DMA. Programmed I/O is done by simply reading the upper data register, DMA is performed when enabled with bit 6 (ENABLE DMA) of the control regster. The DMA clock frequency is controlled by bits 12 to 14 (CLK0-2) of the control register. Once the current DMA transfer is complete, an interrupt is issued if bit 2 (ENABLE DMA INT) is set in the control register.

The voltage measuring range for all analog input channels can be adjusted/calibrated with a potentiometer on A2 between 0V and up to +5V (normally 0,3V or 0,775V as reference for 0dB).

Note that the 8-bit ADC resolution has limited accuracy for measuring purposes. Also it might become necessary to add a level shifter for negative input voltages. The design still lacks a lowpass filter which would be necessary to avoid possibly irritating samples of frequencies which are above the Nyquist frequency.

Digital-to-Analog-Converters (DAC)

DAC is an output functionality by producing analog output voltages from digital values. Main application is producing analog stereo audio output from 16-bit digital values. DA conversion is done with two dedicated DAC chips which are connected to the audio output jack, each working as one output channel. DAC channel 0 (right audio channel) is using the lower 8 bits of the upper data register (R6), DAC channel 1 (left audio channel) is using the upper 8 bits of the same register. So with each 16-bit write to R6, a stereo signal is output the the audio out jack.

As with the ADC function, digital-to-analog conversion can be performed either by programmed I/O or by DMA. Programmed I/O is done by simply writing the upper data register, DMA is performed when enabled with bit 6 (ENABLE DMA) of the control regster. The DMA clock frequency is controlled by bits 12 to 14 (CLK0-2) of the control register. Once the current DMA transfer is complete, an interrupt is issued if bit 2 (ENABLE DMA INT) is set in the control register.

The voltage output for all analog input channels can be adjusted/calibrated with another potentiometer on A2.

Note that it may be required to add a level shifter circuit in order to generate negative/positive AC voltages.

Programmable Sound Generators (PSG)

All 98x5 mainframes just implement a simple beeper as single audio feedback device. The beeper produces fixed-duration tones at fixed frequency and fixed volume.

At the time of the 98x5 there were already so-called programmable sound generators (PSGs) available, which could be programmed to produce a large variety of sounds with several independent sound channels, including a noise channel for special sound effects. Most of those PSGs were used in arcade machines, and some were used as part of extension boards for home computers like the Apple II. One of the first and most capable was the AY-3-8910, which was used on the so-called "Mockingboard" which became some kind of standard audio hardware extension for the Apple II.

Another common sound chip with less features but still three independent sound channels plus one noise channel was the SN76489AN. Since both chips are not too easy to acquire, the FeatureBoard provides sockets for both chips. Controlling those chips is then the task the custom audio driver routine in the 98x5 mainframe. The user should set the audio type jumpers on A1 appropriately to give the driver a hint which sound chip is installed, since there is no perfect way to auto-detect the PSG chips:

+------ J2
| +---- J1
| |
0 0 - no sound chip installed
0 1 - AY-3-8910 installed
1 0 - SN76489AN installed
1 1 - reserved

(1 means jumper installed at pos. 1, 0 means jumper installed at pos. 0)

Analog-to-digital and digital-to-analog conversion does not rely on PSGs installed, so digital wave input and output is possible with the FeatureBoard even if there is no PSG chip available.

The most important advantage of the PSGs is that they can be programmed to produce sounds of certain volume, duration and frequency, and for the AY-3-8910 even with sound envelope control, without further need for processor action, so freeing the processor for other tasks.

The FeatureBoard supports two separate PSGs in parallel, each connected to one if the audio output channels. So full stereo audio is supported. PSG control is done by writing to the lower data register (R4). The SN76489AN chip is write only, but the registers of the AY-3-8910 can be also be read via the lower data register (R4).

The rules for programming the two chips differ. Whereas the SN76489AN is accessed by sequential writes to the lower interface data register (R4), the AY-3-8910 provides random access to all of its registers. For selecting the AY-3-8910 registers, first the PSG register number has to be written to the lower data register (R4) with bit 11 (AUDIO ADDR REG) set in the control register. After that, all writes to the lower data register or reads from the lower data register with bit 11 cleared in the control register function as data write to or data read from the previously selected PSG register (the PSG register address has been latched).

Writing to the SN76489AN should check the FLG line for being true in order to send data to the chip only when it has already processed the previous input.

Playing sound or tone lists can be simply achieved by using the FeatureBoard's timer feature for playing the tones from a score within regular interrupts.

Each AY-3-8910 also provides two 8-bit TTL I/O ports, which can be used as 16-bit general purpose inputs or outputs. By combining both AY-3-8910, there are four 8-bit I/O ports available, which then provide 32-bit I/O in total (which is double the width of the 98032A parallel I/O interface, but without any built-in handshake or DMA capability). Each of the 8-bit I/O ports can be configured either as input or output port. So neither can a port be configured as duplex port, nor can individual bits be configured.

Refer to the SN76489AN and AY-3-8910 data sheets for more information on programming those chips. Also, consult SMS Power for more information on SN76489 programming.

Random Number Generator

All 98x5 mainframes provide a pseudo random number generator by software as part of the BASIC instruction set. However, the software solution always produces the same numbers after power-up, and repeats in a predictable way. So it is totally useless for statistics or other applications with need for 'real' (white noise) random numbers.

The FeatureBoard implements a 16-bit hardware random number generator which produces real white noise numbers between 0 and 65535. The next random number is produced by simply reading the auxiliary register (R7) with bit 15 (R7 SELECT) set in the control register.

Controller Ports

The 98x5 mainframes connect to peripherals via external interfaces only. There is no built-in I/O port for any kind of controller. If available, the 98032A GPIO interface and the 98035A real time clock interface both provide general purpose digital I/O ports which can also be used as controller inputs.

The FeatureBoard has two sub-D controller jacks, each of which includes inputs for an eight-way standard digital joystick with one trigger, plus analog inputs for one two-axis analog joystick or two paddles. The analog inputs are handled by the ADC (see analog-to-digital converters above), whereas the inputs of the digital joystick is directly mapped to the lower 8 bits of the lower data input register (R4), with first joystick in the lower 4 bits and the second joystick in the next higher 4 bits.

Direction and trigger are implemented in the controller hardware as switches to ground. Analog inputs are implemented with linear 1 MOhm potentiometers against +5V.

The joystick direction encoding depends on the controller hardware used. The recommended 8-way ATARI style controller is encoded as follows (most digital joysticks with 9-pin sub-D connector comply to this scheme):

joystick 0 joystick 1

+------ Bit 3 ----- Bit 7
|+----- Bit 2 ----- Bit 6
||+---- Bit 1 ----- Bit 5
|||+--- Bit 0 ----- Bit 4
||||
0000 joystick centered
0001 forward
0010 back
0100 left
1000 right
0101 forward left
0110 back left
1001 forward right
1010 back right

The trigger inputs are mapped to bit 11 (TRIG0) and bit 12 (TRIG1) of the interface status register, and automatically cleared after each read from the status register in order to be ready to register the next trigger event. If bit 0 (ENABLE TRIG INT) of control register is set, any trigger event will issue an interrupt, which then can be identified by bit 0 (TRIG INT) set in the status register. Bits 0, 11 and 12 will be set everytime one of the triggers are fired, even if timer interrupts are disabled, and therefore also can be polled.

In most cases, the controller fire buttons will be used as "one-shot" triggers, however it may be necessary to track the current state for button-up or button-down, e.g. for drag operations. For that purpose, the current button state can be read from bits 13 (BUT0) and 14 (BUT1). The bits are set when the button is pressed, and clear when the button is released. The status always reflects the currrent fire button state and will not be cleared when reading the status register.

As with the ADC function, reading the joystick inputs can be performed either by programmed I/O or by DMA. Programmed I/O for joystick data is done by simply reading the lower data register (R4), DMA is performed when enabled with bit 6 (ENABLE DMA) of the control register. The DMA clock frequency is controlled by bits 12 to 14 (CLK0 to CLK2) of the control register. Once the current DMA transfer is complete, an interrupt is issued if bit 2 (ENABLE DMA INT) is set in the control register.

The controller ports are intended for connecting standard controller devices, however can be used as standard TTL input ports with interrupt, DAC and DMA capability.

Connectors

The FeatureBoard uses the following connectors:

The joystick ports are subject to the follwing pinout:

Joystick Pinout

Pin Function

1 digital joystick forward input
2 digital joystick back input
3 digital joystick left input
4 digital joystick right input
5 analog joystick y-axis or paddle B
6 fire button/trigger input
7 +5V
8 ground
9 analog joystick x-axis or paddle A

Digital joystick and trigger inputs are done by connecting the appropriate pin to ground. Some joysticks (e.g. Atari 7800) use pins 5 and 9 for right and left buttons, and pin 6 for both buttons pressed. Use the ADC inputs to query those buttons if required.

Configuration Jumpers

There are only two jumpers on the A1 board for configuring the type of programmable sound generator chip installed (J1 and J2):

+------ J2
| +---- J1
| |
0 0 - no sound chip installed
0 1 - AY-3-8910 installed
1 0 - SN76489AN installed
1 1 - reserved

(1 means jumper installed at pos. 1, 0 means jumper installed at pos. 0)

Feature Board Design

The FeatureBoard consists of two separate assemblies (A1 and A2) which are stacked in sandwich manner.

A1 Assembly

The A1 assembly interfaces to the IOD bus and provides an edge connector for plugging into the I/O backplane of the 98x5 mainframe. It also implements all general I/O functionality such as interrupts or DMA transfers, and the select code of the interface can be set on this assembly.

A1 Assembly

A1 Assembly Schematics (Click Image for Download)

The A1 assembly is intended as mostly generic implementation which offers a number of functions needed for diverse applications:

The IOD data paths are decoupled from the A2 board by a 16-bit bidirectional buffer with tri-state capability (IC9, IC10). The current interrupt and DMA status as well as some FeatureBoard specific status information is kept by a number of flip-flops (IC1B, IC2B, IC3B, IC5B, IC6B) which connect to the IOD bus via tri-state buffers (IC15).

The signals which may cause interrupts are TRIG, TIMER_END and DMA_END. Additional inputs are TRIG0 and TRIG1, which may be used to either qualify which trigger caused the TRIG interrupt, or simply monitored instead of using interrupts. All those inputs are edge triggered by a number of additional flip-flops (IC1A, IC2A, IC3A, IC5A, IC6A), so that just the change from low to high is registered, and the status register flip-flops actual show that an event has happened, but not the current state (the timer for instance might have already been restarted, and the status bit of the last timer event is still memoried by the status register until it is read which clears all bits).

Interrupt poll or requesting a DMA transfer reaches the IOD bus via buffers/gates with open collector outputs. Control information sent by the host is directly stored from the IOD bus into appropriate latches and flip flops (IC12, IC13, IC14A, IC18).

The select code on the PA lines is directly compared by four XOR gates (IC23). Any match asserts the MYPA signal, which again is combined with the INT signal to the MYPA_INT signal, indicating the board has been addressed for register I/O but without interrupt poll in progress. The MYPA_INT signal is used to enable register access. Status and control registers are both implemented on the A1 board with separate buffers. The bidirectional tri-state buffer is used only for transferring data to or from the A2 assembly. Consequently, the bidirectional buffer is set active with MYPA_INT asserted but register access is not R5, which is done with IC11A.

A central register decoder (IC21) provides a read and write enable line (strobe) for each of the registers based on the IOD interface control lines IC1 an IC2, the DOUT signal and the IOSB signal. Output signals with potentially high current while connected to more than 10 inputs (R5IN, R5SB, RESET) are buffered with three additional 74LS07 open collector drivers with up to 40mA sink current each (IC8A, IC8B, IC8C).

An interrupt is requested if one of the interrupt flip flops is cleared and the appropriate interrupt enable bits are set in the control register (R5). The interrupts are collected by IC1B, IC2B and IC3B, and combined into one single IRQ signal, which then again is AND'ed with the general interrupt enable setting in R5 before it sets an interrupt request condition in the interrupt request flip flop (IC14B), which again asserts IRL or IRH on the IOD bus depending on whether the select code of the interface is 0-7 or 8-15.

When the host recognizes IRL or IRH asserted, it performs an interrupt poll to find which interface requested the interrupt. Interrupt poll detection by the interface requires both INT low and a match of the PA3 line and the MSB of the select code of the interface, also indicating the priority of the interrupt. The MSB comparison is done with a number of gates (IC20D, IC25A, IC25B, IC25C) building an XOR gate.

If an interrupt request is in progress (indicated by the state of flip flop IC14B) the board responds to the poll by pulling the IOD lines low according to the select code of the interface. INT going low also clears the IRQ condition in the flip flop in order to terminate the interrupt request.

Note: In fact, the IRQ condition should not be cleared by INT, but rather by a defined register access in the interrupt service routine. However, all of the 98x5 interfaces clear the interrupt request on INT getting asserted.

DMA is requested by the low-to-high transition of the DMA_CLOCK signal, provided that the DMA enable bit is set in the control register (R5). The DMA request is stored in a flip flop (IC26A), which again triggers the DMAR line on the IOD bus low (via a 74LS07 driver gate with open collector output), provided that DMA is enabled in R5 and the DMA block transfer has not yet been completed (indicated by the DMA_TRANSFER_COMPLETE signal). The IC2 signal is used by the processor to indicate the last word of a DMA block transfer, therefore it must be hold off from the register decoder as long as a DMA cycle is in progress, otherwise the DMA transfer would switch to R6 instead of the default DMA source/sink R4. That hold-off is done with another flip flop (IC26B), which clears on the low-to-high transiation of the IOSB, which indicates the DMA word cycle is done.

It is assumed that the next I/O cycle after a DMA request is done to satisfy the DMA request, so that the next IOSB going low quickly clears the DMA request condition (indicated by the DMA_CYCLE_COMPLETE signal), resetting the DMA request flip flop (IC26A).

The DMA_TRANSFER_COMPLETE signal is derived from IC2, IOSB and MYPA_INT signals all being asserted which indicates the host DMA controller has finished the DMA block transfer.

If enabled by the DMA INT ENABLE bit in the control register (R5), the end of a DMA transfer also causes an interrupt request via the DMA_END signal.

Both the READY and the STATUS signals are received from the A2 assembly and AND'ed with the MYPA signal with open collector outputs to the FLG and STS lines of the IOD bus.

A2 Assembly

The A2 assembly holds all the components needed to implement the special functions of the FeatureBoard such as programmable timer, analog-to-digital and digital-to-analog conversion, joystick ports and random number generator. The A2 assembly also provides sockets for installing either AY-3-8910 or SN76489AN programmable sound chips plus all necessary joystick and audio connectors. Two PSG chips can be installed in parallel for stereo sound generation.

A2 Assembly

A2 Assembly Schematics (Click Image for Download)

The A2 assembly implements all registers except the R5 status/control register (which is implemented by the A1 assembly with latches and buffers). The R7 register ist logically doubled for reads by bit 15 (R7 SELECT) in the control register. With this bit clear, R7A is selected, if set, R7B is selected. So the A2 assembly in fact provides four read registers (R4, R6, R7A, R7B) and three write registers (R4, R6, R7).

Heart of the A2 assembly is the clock generator, which provides a 3.579545 MHz clock (for pitch compatibility with most historical SN76489AN applications) and a 2.048 MHz clock to the PSGs. The 3.579545 MHz clock also is used by the random number generator, whereas the 2.048 MHz clock is subdivided by a cascade of binary dividers into the clocks used for clocking the programmable timer, ADC clock an the DMA transfers.

The analog-to-digital and digital-to-analog functions are implemented with custom 8-bit ADC (ADC0808) and DAC (AD7524) chips. Although already available in 1980, 16-bit high precision ADCs would have been extremely expensive at the time. 8 bit however works perfectly for the aim of the FeatureBoard. The ADC0808 provides eight selectable analog input channels. For stereo wave output, two separate AD7524 are used. The ADC input channels can be calibrated to an adjustable reference voltage and so tuned in their digitizing range. For audio sampling, however, there is still a DC offset circuit missing (line audio range is typically somewhat within ±300mV, the negative voltage portions currently will not be digitized with the ADC0808 so that the input signal gets clipped at 0V). Also there should be a low-pass filter at the DACs outputs for reducing digitizing noise.

A DC offset can easily be made with a voltage divider connecting +5V to ground with one 100k resistor and a linear 100k potentiometer in series. A 10µF capacitor connects with its negative lead to the audio input, and with its positive lead to the junction of the resistor and the potentiometer. The nominal voltage at the junction then can be tuned with the potentiometer between 0V and +2.5V. This junction also connects to the input of the ADC and, via a 47nF capacitor, to ground. The audio signal, when oscillating between positive and negative voltages, then charges the 10µF capacitor so that the ADC input gets biased around the nominal positive voltage at the junction, so that the full audio range can be sampled. The change needs to be applied separately to both ADC input channels 4 and 5 (the audio inputs).

The low pass filter for the output signal can be implemented with a simple RC connecting each of the two DAC audio outputs via a 3k resistor and a 0.01µF capacitor in series to ground, with a cut-off frequency of ~16 kHz. The filtered output is then sourced from the junction between the resistor and the capacitor.

The PSGs are directly connected to the A2 data bus, with some support from the control register to select register address input for the AY-3-8910 or from the READY line for signalling the ready state of the SN76489AN.

All audio outputs are simply added together for each channel by wiring. The audio line out/speaker/headphone amplifier is built up with an LM358 for current/voltage conversion and a TDA2822 for stereo power amplification, with some additional capacitors and resistors. The outputs of the DAC circuits are pre-amplified by an LM358 as current-to-voltage converter before adding them to the audio amplifier inputs.

The timer is built as a cascade of up/down binary counters with parallel load and output capability which asserts the timer interrupt line in case the upper (65535) or lower (zero) limit is reached.

The random number generator is implemented with an astable transistor couple, which is then transformed into a diskrete bit stream by a schmitt-trigger. The bit stream is then fed into a cascade of two 8-bit shift registers to form a 16-bit register which can be read through a 16-bit buffer with tri-state outputs.

Controller inputs divide into 4-way joystick controls, fire buttons and analog inputs. The joystick inputs are directly connected via tri-state buffers to the A2 data bus, the fire buttons are provided as trigger input signals to the A1 assembly, and the analog controller inputs are connected to ADC input channels for precise 8-bit sampling. The fire buttons are debounced with an RC/Schmitt-Trigger circuit.

If AY-3-8910 are installed, their I/O pins are routed to an external connector with up to 32 TTL I/O channels, e.g. for implementing a Centronics compatible printer interface. Also the +/-12V and +5V supply voltages are made available at the connector. Note that the I/O signals of the AY-3-8910 have internal pull-ups, and are not additionally buffered on the FeatureBoard.

All components are connected to a reset signal, which is activated either by the INIT signal of the IOD bus or by writing a 1 to bit 5 (RESET) of the control register. On RESET going low, the shift registers of the random number generator are cleared and the associated A2 data bus buffers are enabled, so that there is a defined zero level on all A2 data lines during reset. This is of special importance for the DAC, which is then loaded with zero level (=muted). In order to reliably hold the A2 data bus lines at zero especially during the RESET signal going up again, the zero output of the random number generator is delayed for a couple of microseconds with an RC combination.

Programming

Since the board has not yet been realized, it makes limited sense to provide a programming tutorial at this place. So a real tutorial will be added when the hardware is working, and probably placed into this site's tutorials section. On the other side, some information might already be noted which support the understanding of the design and/or certain delicate I/O mechanisms like DMA, and this should be done in this paragraph.

DMA transfers to and from the FeatureBoard

DMA transfers have three essential characteristics:

Burst DMA transfers are intended for efficiently transferring data from peripherals into system memory (in general I/O buffers) or vice versa. In the best case, they run at full IOD bus speed. This is how data is copied between system memory and the graphics buffer. Also mass storage devices may make use of burst DMA transfers provided they transfer full buffer contents (e.g. sector buffers). Burst DMA is the fastest possible way to transfer data between system memory and a periperal, and outperforms the fastest programmed I/O transfer.

Single word DMA transfers data not as compact as it is done with burst DMA transfers, but rather with some pauses in between. However still without the intervention of the BPC, so that the system can perform some other tasks in parallel. Influence on system speed depends on the intervals between each DMA word transfer, since during a DMA cycle both the system memory bus (IDA bus) and the I/O bus (IOD bus) are temporarily blocked by the DMA transfer.

The requests for each DMA word transfer can be either done by the peripheral itself (e.g. when the peripheral is ready to provide or accept new data) or by a clock circuit which tells both the DMA controller and the periperhal now to transfer the next word. Clocked transfers are first choice for time synchronized data streaming to or from a device, such as the streaming of audio data with fixed sampling rates.

Technically, burst and single word DMA differ only by the way the DMA request signal (DMAR) is handled. On burst DMA transfers, the DMAR signal is constantly low during the whole block transfer, whereas on single word DMA transfers the DMAR signal is released (set high) after each DMA cycle.

The FeatureBoard uses DMA only for time synchronized audio data transfer from system memory to the digital-to-analog converters (DACs) or in the other direction from the analog-to-digital converter (ADC) and the controller inputs to system memory (analog and/or digital data acquisition). The necessary DMA clock is provided by a programmable clock generator, so there is a wide choice of sampling frequencies available.

All DMA transfers, whether burst DMA transfers or single word DMA transfers, are performed for a defined number of data words which together build a data transfer block. So once configured for DMA transfer, the DMA controller in the IOC is ready to transfer a specified number of words (data block) to or from a peripheral. For this the DMA controller utilizes its own counter, which is set before the transfer and decremented on each data word transferred via DMA. Once the counter expires, the DMA controller has to be re-configured for the next DMA block transfer.

DMA transfers are initiated always by the programmer. Before doing a DMA transfer, he has to decide about the number of words which should be transferred during one DMA block transfer. Next he has to allocate a part of the system memory as buffer (i.e. memory data source or sink, depending of the direction of the DMA transfer).

He has to prepare the DMA controller by providing

With the FeatureBoard, the programmer must also specify the clock rate for the DMA transfer and whether there should be an interrupt when the requested transfer count has been reached.

There are special registers in the IOC for preparing the DMA controller for a transfer:

DMAPA (address octal 13) is the peripheral address and must be initialized to the select code of the device
DMAMA (address octal 14) is the address in system memory and has to be initialized to the start of the memory buffer
DMAC (address octal 15) is the DMA word counter and has to be initialized with the size of the data block less one
DMAD specifies the direction of the DMA transfer, cannot be accessed directly by address, but has to be initialized with the SDI (set DMA inwards = peripheral-to-memory) and SDO (set DMA outwards = memory-to-peripheral) IOC instructions

The DMA clock rate for the FeatureBoard is specified by bits 12 to 14 in the FeatureBoard's control register (write to R5):

+------ CLK2 (bit 14)
|+----- CLK1 (bit 13)
||+---- CLK0 (bit 12)
|||
000 125 Hz
001 250 Hz
010 500 Hz
011 1 kHz
100 8 kHz
101 16 kHz
110 32 kHz
111 64 kHz

Finally, the DMA transfer is started by setting bit 6 (DMA ENABLE) in the FeatureBoard's control register (write to R5).

An interrupt is generated at each end of DMA block transfer if bits 2 (DMA INT ENABLE) and 7 (INT ENABLE) are both set. On interrupt, the DMA INT ENABLE bit is reset and must be set again if an interrupt is demanded for the end of the next DMA block transfer, whereas the general INT ENABLE flag remains set.

On the end of each block transfer, the DMA word counter (DMAC) in the IOC is negative, and bit 3 (DMA END) in the FeatureBoards status register (read from R5) is set. Also bit 6 (DMA ENABLE) in R5 will be cleared in order to stop the FeatureBoard requesting more DMA cycles.

The programmer can poll DMAC that a DMA block transfer is finished so that he can decide to set up another transfer. Or he can request an interrupt on end-of-DMA and then in the interrupt service routine check DMA END for being set.

So for performing a DMA transfer with the FeatureBoard, the programmer has to perform the following steps:

  1. Decide how many words of data shall be transferred on each DMA block transfer (e.g. 1k words)
  2. Decide whether you need an interrupt on the end of the transfer (e.g. for setting up the next transfer) and if yes, prepare an interrupt service routine
  3. Reserve a part of system memory as data buffer
  4. Write the address of the buffer into the DMAMA register
  5. Write the select code of the peripheral into the DMAPA register
  6. Write the number of words to be transffered during each DMA block transfer into the DMAC register
  7. Use SDI or SDO instructions for setting the desired transfer direction
  8. Configure the FeatureBoard's control register properly by setting the correct bits for DMA clock frequency, DMA ENABLE, and - if desired - INT ENABLE and DMA INT ENABLE

Now the FeatureBoard will trigger the DMA request line (DMAR) with the specified clock frequency until the DMA block transfer word count has been satisfied. Once done, the next DMA block transfer can be prepared and started in the same manner.

Example:

Steps 4-7 are all done with one single BASIC command (either OUTPUT or ENTER). Step 8 has to be performed manually with a WRITE BIN statement to R5 with the correct select code (stored in a variable Sc):

INTEGER Buffer(1024)                     ! allocate buffer
OUTPUT Sc DMA 1024 NOFORMAT; Buffer      ! prepare DMA
WRITE IO Sc,5; 64                        ! start DMA (e.g. with 16 kHz clock)

For larger amounts of DMA transfers (e.g. playing full music titels), the data has to be reloaded continuously from mass storage. Also, for recording larger amounts of data the data has to be stored continuously on mass storage. Since DMA is done mostly independent of other system activity, the memory buffers can be reloaded or stored during DMA transfers to or from the feature board.

No synchronization between DMA word transfer and to or from mass storage transfer has to be done if a two-buffer strategy is applied: During DMA transfer from one buffer, a second buffer is being filled with data from mass storage. Once DMA transfer for the first buffer is complete, DMA memory source is switched to the second buffer, and the first buffer is being filled with data from mass memory. Switching between both buffers can be easily done within an interrrupt service routine (ISR). The ISR should also give a hint to the main program that it can start filling/copying the other buffer from/to mass storage.

Since DMA transfer is performed by the DMA controller, the system can concentrate on filling the buffers with data from mass storage. Both DMA transfer and interrupt work independent from each other and in semi-parallel.

For audio playback, don't forget to write 0 to R4 after playback is completed for setting the DACs outputs to level 0.

DMA Limitations

It has to be noted that no two DMA transfers can be performed in parallel, so the transfer between buffer and mass storage cannot use DMA on its own. Actually, this applies only to mass storage devices which are connected to a 98032A GPIO interface. Simply don't select DMA when using OUTPUT or ENTER statements whith this interface.

Also be careful performing other access to the FeatureBoard during a DMA transfer, since a register access to R4 or R5 might cancel a DMA cycle in progress, so that this data word might be lost. For audio playback however, the effect may be considered deglectable. More severe can be an access to R6 or R7, since asserting IC2 is used by the IOC DMA controller to signal to the board that the current data block transfer is finished, so that the DMA transfer might get cancelled and the rest of the data block will be lost. And there is no way for the board to unambigiously determine that the assertion of IC2 is not related to a DMA transfer in progress.

Working with the Status/Control Register

The fact that except the general DMA and interrupt enable bits none of the control register content can be read because they have no representation in the status register, and the automatic clear function for interrupt indicators in the status register suggest some good programming practices.

Since all interrupt information is automatically cleared on reading the status register (R5) in order to be ready to register the next event, the programmer should keep track of the status information by maintaining his own shadow register (i.e. storing the register content on read anywhere else) so that interrupt information is still available after the read (subsequent reads to the status register will return the cleared status). An example is to read the status register within an interrupt service routine, store the content, check which event has caused the interrupt, and if it was a trigger event, check the appropriate bits to determine which of the two triggers had been responsible.

Also, the programmer should keep the current control information in a separate location, since in general a control word also holds information which should not be altered (e.g. clock select or interrupt enable when starting the timer). By first changing the appropriate control bits in the control shadow register, all current control information will be preserved when writing it to the real control register (R5).

Downloads

Click here for downloading FeatureBoard Eagle data:

Schematics for the Feature Board in Eagle 5.x format FeatureBoard-Eagle-Data-01.zip