Saturday 21 January 2023

Driving the AY-3-8910 / YM2149 from an 8 bit micro

In several previous posts, I have been building and using the RC2014 YM2149 sound card from Z80kits.com.

In the last post, I glossed over a strange anomaly in the way these devices are driven from the Z80 bus. It all goes back to the original use of the General Instruments AY-3-8910 chip, which was with the early General Instruments PIC microcontrollers like the PIC1650, or the General Instruments CP1610 microprocessor (as used in the Intellivision console).

Most other chips used on 8 bit microcprocessor systems in the day were designed for things like the 65xx/68xx series or the 8080/Z80 series, and as such use a separate data bus and address bus. Interfacing to these is fairly straightforward.

65xx/68xx series

These microcprocessors have an 8 bit data bus and usually a 16 bit address bus. IO is memory mapped, and everything is controlled from a single R/W pin, high for reads, low for writes.

There are two states for accessing external devices:

R /W
State
0
Write to external device
1
Read from external device

Z80/8080 series

These microcprocessors also have an 8 bit data bus and usually a 16 bit address bus. IO and memory are accessed separately with either a /IO_Request or /Memory_Request signal, and there are separate /Red and /Write signals.

As well as various other modes for interrupts etc., there are four states for accessing external devices:

/Read
/Write
/IO Request
/Memory Request
State
0
1
0
1
Read from external IO device
0
1
1
0
Read from external memory device
1
0
0
1
Write to external IO device
1
0
1
0
Write to external memory device

/WR and /RD both low is invalid, both high is inactive. /IORQ and /MEMRQ low is invalid, both high is inactive.

CP1610

These microprocessors have a combined 16 bit address and data bus, and these are controlled by a BusDirection signal (BDIR) and two BusControl lines (BC1, BC2).

There are eight states used on those systems, but for simplicity, I will only look at the four used by the AY-3-8910.
BDIR
BC2
BC1
State
0
1
0
Inactive
0
1
1
Read from external device
1
1
0
Write to external device
1
1
1
Latch Address

BC2 is always high in these situations, so can be pulled high or wired direct to 5V as it is in all of the circuits below. There are also two additional address lines, A8 and /A9 (only on the 40 pin chip), these are not used in these applications, and just pulled high and low respectively.

As a side note, look at that pinout. See if you can spot D0 and D1. Why couldn't they just put them in order. It's like the databus on a Z80, that is just annoying.

How do other computers do it?

These signals don't easily map to those used on the Z80 or the 6502, and looking at machines from the 1980s, various methods were employed to get around this.

Amstrad CPC464

To get around the complications of driving these pins directly, the Amstrad CPC464 uses an 8 bit IO port on an 8255 PIO chip to drive the data bus, and two lines from a second port to drive BDIR and BC1.

This also avoids any issues of the speed of the bus interface (which seems to vary from datasheet to datasheet), since the data can be latched on the IO chips output port for as long as necessary and the BC1 and BDIR singals toggled before and after setting it.

This may seem wasteful of an IO port, but the AY-3-8192 chip used has it's own 8 port which is used to drive the keyboard and joystick. Slightly convoluted, but it works.

Oric 1 / Atmos

The Oric solution is very similar. A port on the 6522 VIA is used to drive the databus, which is shared with the printer port. Two of the handshaking pins on the 6522 drive BC1 and BDIR.

The Oric 1 PCB has a direct connection from CB2 to BDIR, but some Atmos boards had the track cut and a 1nF capacitor installed, which would delay the BDIR pulse slightly. As seen on a previous repair blog:

http://blog.tynemouthsoftware.co.uk/2022/11/oric-atmos-repair.html

The IO port on the AY-3-8192 is used to drive the keyboard.

The Oric is the only one to directly tie the three outputs together, the rest use a resistor mixer to combine the three output channels.

ZX Spectrum + / +2

The ZX Spectrum + and +2 drive the data bus direct, but the BC1 and BDIR are driven by a combination of diodes and resistors, redrawn below. The IO port is used to drive the 1488/1489 buffers that form the keypad and serial ports.

If the PSG (Programmable Sound Generator) line is low, BC1 and BDIR will be pulled low via the diodes, leaving the chip in the inactive state. If that is high, the diodes do not conduct, and the two pins are driven via resistors. BDIR is driven from /RD, and BC1 is driven from A15.

Connecting the AY-3-8910 to the RC2014 bus

The RC2014 YM2194 / AY3-8192 sound card also uses a direct bus connection, but the generation of the control signals is more complicated. I've redrawn that to work it out, with the jumpers set in their default positions. The board can be jumpered for various other combinations (including ZX Spectrum mode), but I have drawn it in the "default" mode. I have shown the 28 pin AY-3-8192 as I had that drawn already. The board actually uses the 40 pin AY-3-8190 which just has an extra 8 bit IO port, but as seen in a previous post, you can use an AY-3-8192 in an adapter socket.

The first 74HCT138 is used to decode addresses in the range D0-DF, shown as /Dx, inverted to give Dx.

The second 138 is enabled when the current address is in the Dx range, A1 is low (so D0, D1, D4, D5, D8, D9, DC, DD) and an IO Request is in operation. This is further filtered by the three address inputs. Three outputs are generated, /D8_Read, /D0_Write and /D8_Write. These are combined by the two 74HCT00 NAND gates to give one signal which is high when there is a D8_Read or a D8_Write; this drives BC1. The second signal is high when there is a D8_Write or a D0_Write; this drives BDIR.

That gives the following results:

Signal
BDIR
BC2
BC1
State
-
0
1
0
Inactive
D8 read
0
1
1
Read from external device
D0 write
1
1
0
Write to external device
D8 write
1
1
1
Latch Address

As you can see, that's not quite what you would expect. D0 (also D1, D4 and D5) is the data register. Writing there is a write to the sound chip, that's OK.

D8 is the address latch (also D9, DC and DD). Writing there latches the address.

However, the read operation is set for D8, so to read from the chip, you read from the register port rather than the data port. I am not sure if there is a specific reason for this, maybe compatibility with some existing systems? (and no, you can't change that with the jumpers)

The D0 and D8 addresses in hex are the 208 and 216 addresses in decimal in the previous posts.

The full schematic for this V5 version of the board can be found on the designers github:

https://github.com/electrified/rc2014-ym2149/tree/4b8af5396633bc87178b81087cec0f71b8307908

Note there is also a V6 version of the board which removes the D0/D8 access and uses addressing compatible with the Spectrum and MSX:

https://github.com/electrified/rc2014-ym2149

Could it be fixed?

Swapping the output of the second 138 from pin 12 to pin 13 should make it respond to reads on the data port instead.

I guess the existing board has been around long enough now that reading the register port is the accepted way of doing it, and to change it would break existing code.


Advertisements

Minstrel 4D

The Minstrel 4D kits are shipping now, you can order one from The Future Was 8 bit

https://www.thefuturewas8bit.com/minstrel4d.html

More info in a previous post:

http://blog.tynemouthsoftware.co.uk/2022/08/minstrel-4d-overview.html


Z80 Kits

The YM2149 Sound Card is available from Z80Kits.com

https://z80kits.com/shop/ym2149-sound-card/


Patreon

You can support me via Patreon, and get access to advance previews and behind the scenes updates. These are often in more detail than I can fit in here, this post contains bits from three Patreon posts, and there is a forth and fifth to follow. This also includes access to my Patreon only Discord server for even more regular updates.

https://www.patreon.com/tynemouthsoftware