PDS – the Programmers Development System – Part 8
I thought it time to take a proper look at the Amstrad Target board, seeing as I’ve managed to find myself an Amstrad CPC 464. But first I have a short diversion into loading from audio files.
- Part 1 – Introduction, background and some initial reverse engineering.
- Part 2 – A closer look at the PC ISA Interface card.
- Part 3 – Remaking the target interfaces.
- Part 4 – Building the boards.
- Part 5 – Getting everything running (first, unsuccessful attempt).
- Part 6 – Some serious diagnostics and a breakthrough (at last)!
- Part 7 – Diagnostic module PCB.
- Part 8 – Audio loading and the Amstrad target board.
- Find it on GitHub here: https://github.com/diyelectromusic/PDS_Remake
TAP to Real Audio Files
I wanted to produce an audio file of the TAP file for use with the ZX Spectrum and producing a WAV file was relatively straight forward. But finding a way to play it was a lot more tricky than I expected…
Initially I figured I’d just play the file using TZXduino and record it using a phone or something and that did work, but it was a bit noisy. And it wouldn’t load.
But then I discovered https://www.igormaznitsa.com/tap2wav/index.html
This is great and generates a really clean signal. The first utility I found didn’t centre the “zero” point in the wave properly, so I thought that might cause problems, but this one does everything really clearly and when the signal is opened in an Audio editor, we can see how precise everything is.
But this still doesn’t load. So far I’ve tried the following:
- Use a smartphone with a USB-C to 3.5mm jack adaptor.
- Use a dumbphone with a physical headphone jack.
- Use old, otherwise essentially useless, AAA powered MP3 players (several tried).
In terms of the files themselves, I’ve tried the following:
- WAV and MP3.
- Boosting, halving, otherwise adjusting the volume of signals.
- Using a noise-gate filter.
But nothing I’ve tried works. At one point I got the first stage loader to register as far as the filename on the screen, but then R Tape Loading Error.
Asking online, I got some answers. It turns out that modern digital players do not have the kinds of output levels that will drive a ZX Spectrum. A system with a significant volume range may do it, but chances are nothing will compare to a “vintage” small tape recorder.
Stewart Russell on Mastodon sent me to this link which has a really elegant solution: https://retrocomputing.stackexchange.com/questions/773/loading-zx-spectrum-tape-audio-in-a-post-cassette-world
The basic idea is to use a battery powered player, so it has no common GND to the Spectrum, and then create a differential stereo signal. Then using a stereo jack, it will connect to the mono jack in the Spectrum with one channel being GND and the other channel being signal. This has the effect of doubling the signal. That is really lateral thinking!
I’ve not tried it at this stage, and really I’d like to find a bit of a more conventional solution, but really at the end of the day it is hard to compete with the TZXDuino/MaxDuino type solution.
Amstrad CPC Target Board
I really wanted to try to get the Amstrad board running, but to do that, I was missing a rather vital piece of equipment. I don’t have an Amstrad 8-bit computer. Until now. At a recent retro sale at The Retro Collective I managed to pick up an Amstrad CPC 464 with a colour monitor, and it appears to work, which is amazing.
So I set about repeating some of the steps I took in Part 5 with the Spectrum board.
Key points:
- There are Amstrad equivalents of the DL0, DL1 and DL2 monitor code for the Amstrad CPC.
- The Amstrad target board usings ports &FBEC-&FBEF for the PIO data and control channels.
- Otherwise, everything should be essentially the same as the Spectrum version.
The steps to get the monitor code into something usable for me are:
- Make the same adjustments (JPs, labels and removing PDS specific instructions) to the source.
- Assemble it using an online Z80 assembler.
- Take the HEX or Binary output and turn it into something I can use with the Amstrad.
And here I hit the first problem. The Amstrad CPC 464 does not have an external tape port, so I can’t use it with my TZXDuino. The TZXDuino does support the CDT tape format that many Amstrad images use, but there is no where to plug it in. There are a number of projects online that show how to add a typical (for later models) Amstrad 5-pin DIN cassette port socket, but so far I don’t have that.
So another option was to use some of the previous techniques to produce an audio file I could actually et onto a tape. But whilst my tape drive (the “datacorder”) has working FF and REV, it seems that Play does not engage the transport to move the spindles. So that is something I’ll need to sort out at some point.
So for now, if I want to try it, I’m back to typing in a BASIC machine code loader.
The Amstrad BASIC is a bit more sophisticated than the Spectrum, so I can use HEX values directly. This means it is fairly trivial to take the HEX record format and with a bit of repetitive cut-and-pasting get the values as HEX codes in a BASIC program as follows.
:108000003EFF01EEFBED79ED790CED790EEDED79AA
:108010000EEF3E3FED791640F3CD60807BFEB4CA93
:108020004380FEB7CA3980FEB5C21980CD60806337
:10803000CD60806B011980C5E9CD6080067F4BED76
:108040004918D6CD608063CD60806BCD608043CD14
:1080500060804BCD608073230B78B1C2538018B918
:10806000C501EDFBED78AA0FDA64800DED580C7AAE
:07807000ED79EE8157C1C953
:00000001FF
5 SYMBOL AFTER 256: MEMORY &7FFF: SYMBOL AFTER 240
10 LET a=&8000
20 READ n: POKE a,n
30 LET a=a+1
40 GOTO 20
100 DATA &3E,&FF,&01,&EE, &FB,&ED,&79,&ED
105 DATA &79,&0C,&ED,&79, &0E,&ED,&ED,&79
110 DATA &0E,&EF,&3E,&3F, &ED,&79,&16,&40
115 DATA &F3,&CD,&60,&80, &7B,&FE,&B4,&CA
120 DATA &43,&80,&FE,&B7, &CA,&39,&80,&FE
125 DATA &B5,&C2,&19,&80, &CD,&60,&80,&63
130 DATA &CD,&60,&80,&6B, &01,&19,&80,&C5
135 DATA &E9,&CD,&60,&80, &06,&7F,&4B,&ED
140 DATA &49,&18,&D6,&CD, &60,&80,&63,&CD
145 DATA &60,&80,&6B,&CD, &60,&80,&43,&CD
150 DATA &60,&80,&4B,&CD, &60,&80,&73,&23
155 DATA &0B,&78,&B1,&C2, &53,&80,&18,&B9
160 DATA &C5,&01,&ED,&FB, &ED,&78,&AA,&0F
165 DATA &DA,&64,&80,&0D, &ED,&58,&0C,&7A
170 DATA &ED,&79,&EE,&81, &57,&C1,&C9
RUN
CALL &8000
In the above, we can see the HEX record for DL0 (with the PDS specific details removed) with an ORIGIN of 0x8000. Then there is the equivalent BASIC loader with the data statements for the HEX values less the line headers and checksums. This is followed by the two instructions I need to RUN the loader and then CALL the code.
That first line of the BASIC programme is apparently how one limits the memory used by BASIC and reserves space for user machine code programmes.
I typed all this in and checked as I was going, and then double checked at the end. But then – nothing. The PC end is exactly the same as before and I was going to attempt to fill some screen memory again (which apparently starts at 0xC000) but when I tried to link with the target I got the dreaded “computer is not receiving” error. Reluctantly I had to reset the Amstrad and attempt to figure out what was going on.
Following the same process I took in Part 5 (and using my diagnostics board from Part 6) I first tried to write directly to the Z80 PIO from Amstrad BASIC using OUT instructions:
OUT &FBEF, 255 : REM Port B Control
OUT &FBEF, 63 : REM Port B bits 6,7 as OUTPUT
OUT &FBED, 128 : REM Port B Data bit 7
OUT &FBED, 0
This should have turned the Target->PC LED on then off. But I got nothing.
At this point I went back and verified the schematic and address decoding to make sure I knew what was supposed to be happening. The relevant part of the schematic is shown below:

For address decoding, A0 and A1 have the same function as before – they select between ports A and B and control and data. The IO address is determined by A4 and A10 via an OR gate into /CE. This has the following decoding:
We can see that the only combination that results in /CE being LOW (so activating the Z80 PIO) is when A4 and A10 are both 0. Once again though this leads to very slopping address decoding as, ignoring A0 and A1, any of the other 10 address lines could be any value and the decoding will still trigger.
The convention appears to be to use “all HIGH” addresses, which gives us the prefix used 0xFBEC as follows:
0xFBEC = b1111 1011 1110 11xx
The other things I pondered where how the enable switch connects the /IORQ line of the PIO HIGH in both cases but once with a direct 10K pull-up and once with a 1M pull-up and then on to the edge connector /IORQ. Also I noted that the CLOCK is connected to CLK4 on the edge connector; and how only /RD is connected (i.e. not /WR) alongside /M1. But otherwise there was nothing particularly odd going on.
At this point I grabbed the oscilloscope and started to probe things as I ran the OUT instructions. At one point I knocked the card and had a pile of gibberish appear on the screen as if I’d typed random characters on the keyboard, so I wondered if it was seated properly.
Power off and reseating the board and trying the OUTs again and this type I actually got some LEDs being controlled. Perhaps it just wasn’t physically connected properly.
At this point I sealed myself to retyping in the BASIC loader once again.
I still didn’t seem to get any response to my attempts to fill the screen from the PC PDS, but critically I also wasn’t getting the “computer not receiving” errors either. When I put a scope on the PC to Target and Target to PC control lines, I can see them both toggling in response to the communications happening.
So at this point I can say pretty confidently that the Amstrad CPC Target board is working, but for some reason (probably due to my lack of knowledge about how the Amstrad works) I’ve not been able to induce an observable effect in the CPC by poking memory.
I’ve looked over the monitor code and I can’t see any reason why it wouldn’t do the same as the Spectrum code. I did notice that it appears to disable interrupts near the start, but then so did the Spectrum version. But would this stop the display updating? I don’t think it would, but more research is needed.
Target Type in PDSZ80
At some point, I realised that there is a configuration option in the PC PDSZ80 software to set the target type, so before I typed the BASIC loader in for a third time, I did a bit of reading about it.
From the PDS Manual:

It doesn’t actually say what is different however between the modes – is the protocol different? So digging around in the PDS Z80 Manual, I find this for the “P” command:

And a bit further on, when discussing configuration options:

So whilst there was a small spur of hope at one point that I’d forgotten something simple, i.e. to tell PDSZ80 it was talking to an Amstrad, reading the above, I don’t think it will make any difference. Not enough to make me want to type in the loader again to check, anyway.
Conclusion
I think I’ve shown that the card itself, and probably the provided code, does work which was my main aim.
Unfortunately at this point I don’t know enough about the Amstrad to figure out quite how to drive the PDS in a useful way so on that front I still have some work to do.
But I’m going to leave this here for now. If I figure anything else out, I’m come back and update things.
Kevin