#programmersdevelopmentsystem — Public Fediverse posts
Live and recent posts from across the Fediverse tagged #programmersdevelopmentsystem, aggregated by home.social.
-
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 &8000In 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, 0This 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:
A10A4/CE000011101111We 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.
Amstrad BASIC PDS Tracer
Going back to the BASIC code, I wrote a simple BASIC programme to effectively implement the GETBYTE algorithm from the DL0 code. Unfortunately that wouldn’t run at any useful speed for me. But implementing GETBYTE in assembly and calling it from BASIC worked ok:
; GETBYTE Routine.
; Key addresses:
; 7FFE - Received data byte
; 7FFF - Record of the control flags
; 8000 - Execution address
;
ORG 7FFEH
EBYTE:
DB 0
DFLAG:
DB 64
;
PUSH AF
PUSH BC
PUSH DE
LD A,(DFLAG)
LD D,A
LD BC,0FBEDH
LAB1: IN A,(C)
XOR D ;Wait for 'sent the byte'
RRCA
JP C,LAB1
DEC C
IN E,(C) ;Get the byte
INC C
LD A,(DFLAG)
OUT (C),A ;Say 'byte received'
XOR 129
; LD D,A ;Flip flags ready for next byte
LD (DFLAG),A
LD A,E
LD (EBYTE),A
POP DE
POP BC
POP AF
RET
; End of GETBYTE
9 REM Hybrid BASIC/Assembler tester
10 OUT &FBEE,255
20 OUT &FBEE,255
30 OUT &FBEF,255
40 OUT &FBEF,63
70 CALL &8000
80 PRINT PEEK(&7FFE)
90 GOTO 70
299 REM Machine code loader, code start &8000
300 SYMBOL AFTER 256: MEMORY &7FFD: SYMBOL AFTER 240
310 FOR a=0 TO &28
320 READ n: POKE &7FFE+a,n
330 NEXT a
399 REM GETBYTE machine code
400 DATA &00,&40,&F5,&C5, &D5,&3A,&FF,&7F
405 DATA &57,&01,&ED,&FB, &ED,&78,&AA,&0F
410 DATA &DA,&0A,&80,&0D, &ED,&58,&0C,&3A
415 DATA &FF,&7F,&ED,&79, &EE,&81,&32,&FF
420 DATA &7F,&7B,&32,&FE, &7F,&D1,&C1,&F1,&C9I wanted to print the received values in both HEX and decimal, but it couldn’t quite keep up to receive a whole message if I did that. Printing in decimal, I can see the results of the command
F 49152,2,255
179 Padding
180 Download command
192 Address high byte
0 Address low byte
0 Length high byte
2 Length low byte
255 Data 1
255 Data 2So I know messages are getting through. At this point I decided it was probably my poor knowledge of the Amstrad meaning I wasn’t getting a visible result, so I went for one more try and retyped the code.
Now prior to running it I executed a CLS instruction. You can see the results of the “F 49152,256,255” below. Finally, I have the confidence I need that it is working.
Conclusion
This is a great place to get to. It seems that everything is basically working. I now need to do some work on my Amstrad itself to make things a bit more practical, but in essence, I’m there.
I’ve updated the GitHub accordingly.
Kevin
#amstradCpc #pds #programmersDevelopmentSystem -
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 &8000In 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, 0This 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:
A10A4/CE000011101111We 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? More research is needed.
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
#amstradCpc #pds #programmersDevelopmentSystem -
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 &8000In 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, 0This 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:
A10A4/CE000011101111We 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? More research is needed.
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
#amstradCpc #pds #programmersDevelopmentSystem -
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 &8000In 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, 0This 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:
A10A4/CE000011101111We 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.
Amstrad BASIC PDS Tracer
Going back to the BASIC code, I wrote a simple BASIC programme to effectively implement the GETBYTE algorithm from the DL0 code. Unfortunately that wouldn’t run at any useful speed for me. But implementing GETBYTE in assembly and calling it from BASIC worked ok:
; GETBYTE Routine.
; Key addresses:
; 7FFE - Received data byte
; 7FFF - Record of the control flags
; 8000 - Execution address
;
ORG 7FFEH
EBYTE:
DB 0
DFLAG:
DB 64
;
PUSH AF
PUSH BC
PUSH DE
LD A,(DFLAG)
LD D,A
LD BC,0FBEDH
LAB1: IN A,(C)
XOR D ;Wait for 'sent the byte'
RRCA
JP C,LAB1
DEC C
IN E,(C) ;Get the byte
INC C
LD A,(DFLAG)
OUT (C),A ;Say 'byte received'
XOR 129
; LD D,A ;Flip flags ready for next byte
LD (DFLAG),A
LD A,E
LD (EBYTE),A
POP DE
POP BC
POP AF
RET
; End of GETBYTE
9 REM Hybrid BASIC/Assembler tester
10 OUT &FBEE,255
20 OUT &FBEE,255
30 OUT &FBEF,255
40 OUT &FBEF,63
70 CALL &8000
80 PRINT PEEK(&7FFE)
90 GOTO 70
299 REM Machine code loader, code start &8000
300 SYMBOL AFTER 256: MEMORY &7FFD: SYMBOL AFTER 240
310 FOR a=0 TO &28
320 READ n: POKE &7FFE+a,n
330 NEXT a
399 REM GETBYTE machine code
400 DATA &00,&40,&F5,&C5, &D5,&3A,&FF,&7F
405 DATA &57,&01,&ED,&FB, &ED,&78,&AA,&0F
410 DATA &DA,&0A,&80,&0D, &ED,&58,&0C,&3A
415 DATA &FF,&7F,&ED,&79, &EE,&81,&32,&FF
420 DATA &7F,&7B,&32,&FE, &7F,&D1,&C1,&F1,&C9I wanted to print the received values in both HEX and decimal, but it couldn’t quite keep up to receive a whole message if I did that. Printing in decimal, I can see the results of the command
F 49152,2,255
179 Padding
180 Download command
192 Address high byte
0 Address low byte
0 Length high byte
2 Length low byte
255 Data 1
255 Data 2So I know messages are getting through. At this point I decided it was probably my poor knowledge of the Amstrad meaning I wasn’t getting a visible result, so I went for one more try and retyped the code.
Now prior to running it I executed a CLS instruction. You can see the results of the “F 49152,256,255” below. Finally, I have the confidence I need that it is working.
Conclusion
This is a great place to get to. It seems that everything is basically working. I now need to do some work on my Amstrad itself to make things a bit more practical, but in essence, I’m there.
I’ve updated the GitHub accordingly.
Kevin
#amstradCpc #pds #programmersDevelopmentSystem -
PDS – the Programmers Development System – Part 7
After the final successes of the past post, I thought it would be worth formally building a diagnostic module that can be used to help debug the system should the need arise.
- 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
Diagnostic Module Design
This is a reimplementation of the breadboard diagnostic breakout used in Part 6:
But I’m building it all onto a PCB and want to add built-in LEDs. One thing to watch out for is the current draw as there could be up to 16 LEDs on at any one time.
The 74LS245 buffer for the data lines on the target board will often be driving the 8 data LEDs, so from the datasheet we can see a sink current of 24mA and source current of 15mA and I believe a total supply current of between 70 and 95mA depending on the state of the outputs. So that will be limiting me to around 10mA per LED.
From the other side, the LEDs will be driven by the Intel 8255, but through a series of 74LS244 buffers which seem to have a very similar spec to the 245s used at the target end.
The control lines at the target end are driven from the Z80 PIO via a 74LS04. That is a little more problematic as it appears to have an asymmetric current specification, being 0.4mA for a HIGH output and maybe up to 16mA for a LOW output. 0.4mA is really not very much for an LED…
Some resistor “ball parks” for a 5V powered circuit for a variety of forward voltages of LEDs:
Forward VoltageResistorCurrent1.7V1K3.3mA1.7V4K70.7mA2.0V500R6.0mA2.0V1K3.0mA2.0V2K1.5mA2.0V4K70.7mA2.2V1K2.8mA2.2V2K1.4mA2.2V4K70.6mAWe can see that none of these really get very close to the 0.4mA for the 74LS04’s smaller limit. For a diagnostic circuit, running at slightly over spec for a short time probably isn’t a major issue, but using a 4K7 or above resistor will make for a pretty dim LED.
I’m going to leave this to the discretion of the reader but build for 2K+ resistors. If things start to become an issue then using a 74xx04 variant with higher current limits on the target board might be an option. Of course the correct way would be to go through some kind of LED driver or buffer, but that is getting a bit much for something that is meant to be a simple, temporary, monitoring, diagnostic tool.
Other features I’m after:
- Additional pin header breakout to facilitate attaching a scope, etc.
- A way to disconnect the PDS GND pin from the board’s GND in case I ever want to use it as a generic 2×8 way breakout.
- Additional GND pins both to allow an alternative connection but also to act as anchors for a scope of other measurements.
- The board itself is not powered other than what comes in via the IO pins.
I’ve deliberately not labelled the pins as the board is already fairly generic. I have labelled what I’m anticipating to be the PC and target ends.
The board is designed to be used with a straight-through 16-way (2×8) cable between the target and the diagnostic board, and the usual (swapped) PDS cable between the PC and the diagnostic board.
Diagnostic Module Build
Bill of Materials
- Diagnostic Module PCB (GitHub link here)
- 16x 3mm rectangular LEDs (colours to taste, but take note of the above discussion re impact of forward volage on the current calculation).
- 2x 8-way (9 pin) 2K or higher resistor networks (again see previous discussion).
- 2x Shrouded 16-way (2×8) header pins.
- 1x 2×8 header pins.
- Single row header pins.
- 16-way, straight through, IDC or similar ribbon cable (e.g. a Eurorack 16-way power cable).
In the end, I went for green LEDs for the “control” side of things and red LEDS for the data. I used a 4K7 resistor network for the green LEDs and 2K for the red. I didn’t bother populating the breakout headers and GND pins at this time as I’m just relying on the LEDs.
Note: for the PDS link, only two of the green LEDs are significant – the 2nd and 3rd from the right. This is because for a PDS link the first pin is GND and the other pins are largely unused.
Conclusion
Amusingly, when I first used this, more of the green LEDs were illuminated and I wasn’t sure why. Then I realised this was because I’d only had two LEDs wired up when using the solderless breadboard! This is just the standard state of the control LEDs when the PC card is doing its thing.
This is simple, but works really well. This will be really useful in debugging other systems I think.
At this point, I don’t think I have anything more to say about the PDS, other than, over time as we find out more information about it, I’ll keep updating the repository on GitHub. But from this point, I think the GitHub will slowly replace the information in these blog posts.
Kevin
#leds #pds #programmersDevelopmentSystem #zxSpectrum -
PDS – the Programmers Development System – Part 7
After the final successes of the past post, I thought it would be worth formally building a diagnostic module that can be used to help debug the system should the need arise.
- 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
Diagnostic Module Design
This is a reimplementation of the breadboard diagnostic breakout used in Part 6:
But I’m building it all onto a PCB and want to add built-in LEDs. One thing to watch out for is the current draw as there could be up to 16 LEDs on at any one time.
The 74LS245 buffer for the data lines on the target board will often be driving the 8 data LEDs, so from the datasheet we can see a sink current of 24mA and source current of 15mA and I believe a total supply current of between 70 and 95mA depending on the state of the outputs. So that will be limiting me to around 10mA per LED.
From the other side, the LEDs will be driven by the Intel 8255, but through a series of 74LS244 buffers which seem to have a very similar spec to the 245s used at the target end.
The control lines at the target end are driven from the Z80 PIO via a 74LS04. That is a little more problematic as it appears to have an asymmetric current specification, being 0.4mA for a HIGH output and maybe up to 16mA for a LOW output. 0.4mA is really not very much for an LED…
Some resistor “ball parks” for a 5V powered circuit for a variety of forward voltages of LEDs:
Forward VoltageResistorCurrent1.7V1K3.3mA1.7V4K70.7mA2.0V500R6.0mA2.0V1K3.0mA2.0V2K1.5mA2.0V4K70.7mA2.2V1K2.8mA2.2V2K1.4mA2.2V4K70.6mAWe can see that none of these really get very close to the 0.4mA for the 74LS04’s smaller limit. For a diagnostic circuit, running at slightly over spec for a short time probably isn’t a major issue, but using a 4K7 or above resistor will make for a pretty dim LED.
I’m going to leave this to the discretion of the reader but build for 2K+ resistors. If things start to become an issue then using a 74xx04 variant with higher current limits on the target board might be an option. Of course the correct way would be to go through some kind of LED driver or buffer, but that is getting a bit much for something that is meant to be a simple, temporary, monitoring, diagnostic tool.
Other features I’m after:
- Additional pin header breakout to facilitate attaching a scope, etc.
- A way to disconnect the PDS GND pin from the board’s GND in case I ever want to use it as a generic 2×8 way breakout.
- Additional GND pins both to allow an alternative connection but also to act as anchors for a scope of other measurements.
- The board itself is not powered other than what comes in via the IO pins.
I’ve deliberately not labelled the pins as the board is already fairly generic. I have labelled what I’m anticipating to be the PC and target ends.
The board is designed to be used with a straight-through 16-way (2×8) cable between the target and the diagnostic board, and the usual (swapped) PDS cable between the PC and the diagnostic board.
Diagnostic Module Build
Bill of Materials
- Diagnostic Module PCB (GitHub link here)
- 16x 3mm rectangular LEDs (colours to taste, but take note of the above discussion re impact of forward volage on the current calculation).
- 2x 8-way (9 pin) 2K or higher resistor networks (again see previous discussion).
- 2x Shrouded 16-way (2×8) header pins.
- 1x 2×8 header pins.
- Single row header pins.
- 16-way, straight through, IDC or similar ribbon cable (e.g. a Eurorack 16-way power cable).
In the end, I went for green LEDs for the “control” side of things and red LEDS for the data. I used a 4K7 resistor network for the green LEDs and 2K for the red. I didn’t bother populating the breakout headers and GND pins at this time as I’m just relying on the LEDs.
Note: for the PDS link, only two of the green LEDs are significant – the 2nd and 3rd from the right. This is because for a PDS link the first pin is GND and the other pins are largely unused.
Conclusion
Amusingly, when I first used this, more of the green LEDs were illuminated and I wasn’t sure why. Then I realised this was because I’d only had two LEDs wired up when using the solderless breadboard! This is just the standard state of the control LEDs when the PC card is doing its thing.
This is simple, but works really well. This will be really useful in debugging other systems I think.
At this point, I don’t think I have anything more to say about the PDS, other than, over time as we find out more information about it, I’ll keep updating the repository on GitHub. But from this point, I think the GitHub will slowly replace the information in these blog posts.
Kevin
#leds #pds #programmersDevelopmentSystem #zxSpectrum -
Right, the PDS repository is now public and the blog series should now be up to date with where I've got to with it all so far.
Series starts here: https://emalliab.wordpress.com/2026/05/04/pds-the-programmers-development-system/
-
Right, the PDS repository is now public and the blog series should now be up to date with where I've got to with it all so far.
Series starts here: https://emalliab.wordpress.com/2026/05/04/pds-the-programmers-development-system/
-
Right, the PDS repository is now public and the blog series should now be up to date with where I've got to with it all so far.
Series starts here: https://emalliab.wordpress.com/2026/05/04/pds-the-programmers-development-system/
-
Right, the PDS repository is now public and the blog series should now be up to date with where I've got to with it all so far.
Series starts here: https://emalliab.wordpress.com/2026/05/04/pds-the-programmers-development-system/
-
Right, the PDS repository is now public and the blog series should now be up to date with where I've got to with it all so far.
Series starts here: https://emalliab.wordpress.com/2026/05/04/pds-the-programmers-development-system/
-
PDS – the Programmers Development System – Part 6
This series of posts looks at the Programmers Development System (PDS).
- 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
This part gets serious about attempting to debug eveything and find out why it isn’t working…
PDS Diagnostic Breakout
The starting point is trying to figure out what is going on with the signals on the link. To do that, I’ve built a simple breakout which can be used to probe the signal lines or, as in my case, attach some LEDs.
I initially thought I could use some of those “cobbler” breakout boards that expand out Raspberry Pi GPIO to solderless breadboards. But unfortunately, they aren’t a direct 2×13, 2×20 mapping to the breadboard, as the GND pins are all linked together and would short some of the PDS connections.
Instead I went with building something simple myself using protoboard:
It is a straight, simple breakout from the 2×8 way header to two sets of 8-way header pins suitable for plugging into a solderless breadboard.
I’m wiring it up as a “straight through” connection to the target board, mostly to save me having to make more PDS cables – doing it this way means a simple Euro rack 2×8 power ribbon will do (and I have quite a few of those kicking around).
This is the wiring I’m using for the board. Recall the target connector has the following pinouts:
N/CN/CN/CN/CN/CZX->PCPC->ZXGNDD7D6D5D4D3D2D1D0Assuming I have it all right of course.
This now allows me to attach some 8-way LED breakout boards that connect to 8 signals plus ground to allow for easy observations.
Testing the ZX Spectrum Board
At this point I can confirm that the ZX Spectrum target board can still talk to its Z80 PIO using the following BASIC code:
10 OUT 127,255
20 OUT 127,63
30 FOR n=0 TO 100: NEXT n
40 OUT 63,128
50 FOR n=0 TO 100: NEXT n
60 OUT 63,0
70 GOTO 30This is basically a ZX Spectrum/Z80 PIO/PDS “blink” application using the “ZX to PC” pin.
https://makertube.net/w/kQNKyii3R9gYu2iiW6r2f5
So what is going on here? Recall from Part 1 that the IO ports used are as follows:
IO PORTFunctionNotes31Port A DataUsed for the D0-D7 lines (via a buffer)63Port B DataUsed for the ZX<->PC control95Port A ControlUsing Z80 PIO “Mode 3”127Port B ControlUsing Z80 PIO “Mode 3”The mapping of Port B Data to PDS control pins isn’t as one might expect however, again from Part 1, we have noted:
76543210 PORT B DATA BITS
0-- Pin 3: PC to ZX
4321--- Not used
5------- Pin 7: Function unknown
6-------- Data buffer direction control (0=OUT; 1=IN)
7--------- Pin 5: ZX to PCArmed with this knowledge, we can explain the BASIC program as follows:
OUT 127,255 : PORT B Control = b11111111 MODE 3: bidirectional
OUT 127,63 : PORT B Control = b00111111 Bits 6,7=OUTPUT, 0-5=INPUT
OUT 63, 128 : PORT B Data = b10000000
OUT 63, 0 : PORT B Data = b00000000The data lines go via a buffer, so can also be driven if the DIR pin (bit 6 of PORT B) is set appropriately prior to use (LOW = OUTPUT):
10 OUT 127,255 : REM Mode 3
20 OUT 127,63 : REM b6,7=OUT, b0-5=IN
30 OUT 95,255 : REM Mode 3
40 OUT 95,0 : REM b0-7=OUT
50 OUT 63,128 : REM b7=HIGH
60 FOR n=0 TO 100: NEXT n
70 OUT 63,0 : REM b7=LOW
80 FOR n=0 TO 255
90 OUT 31,n : D0-7 = n
95 FOR f=0 TO 10: NEXT f
100 NEXT n
110 OUT 31,0 : D0-7 = 0
120 GOTO 50At this point I can see all data lines counting and the ZX to PC pin being toggled as expected.
Whilst I’m on the topic, I should probably check the input side too.
10 OUT 127,255 : REM Mode 3
20 OUT 127,63 : REM b6,7=OUT, b0-5=IN
30 OUT 95,255 : REM Mode 3
40 OUT 95,255 : REM b0-7=IN
50 OUT 63,192 : REM b7=HIGH, b6=HIGH
60 FOR n=0 TO 10
70 PRINT IN 31
80 NEXT n
90 OUT 63,64 : REM b7=LOW, b6=HIGH
100 FOR n=0 TO 10
110 PRINT IN 31
120 NEXT n
130 GOTO 50With this, I can connect the single OUTPUT pin to any of the data lines and see if the values change as the OUTPUT pin state changes. The pins do indeed change, but the state is often inverted, so when the OUTPUT is connected to D1 (for example) the value toggles between 255 and 253, but this is basically because the other input lines are floating when not connected and in this case are reading HIGH.
All good so far. Next is to see what happens when I fire up the PC end.
Testing the PC Board
Making sure the Spectrum PDS is in INPUT mode, I can try some commands from the PC (I’m still not running the monitor at this stage):
10 OUT 127,255 : REM Mode 3
20 OUT 127,63 : REM OOIIIIII
30 OUT 95,255 : REM Mode 3
40 OUT 95,255 : REM IIIIIIII
50 OUT 63,192 : DIR PC->ZX (plus setting b7 so I can see something)When I run the F(ill) command in the Monitor (F4):
F 32768,16,255
I can see one of the control lines and some of the data lines flash, so that is an encouraging sign that the PC card has a working 8255 IO device and is able to at least try to send data to the target.
Catching it on video, it is just about possible to make out the binary value put on the data lines reading 10110011 which is 179 in decimal. Looking at the PDS protocol description in the PDS Z80 Manual, we can see that 179 is used a lot at the start of commands, as it is the padding byte.
Changing the command to 183 (change bank “Z 1”) which doesn’t have a padding byte, I can indeed see a different pattern on the data bus for b10110111 or for the register command (184, “R”) b10111000.
I can also see the “PC to ZX” control bit changing as the commands are happening, so this gives me confidence that the 8255 on the PC card is at least outputting ok.
Of course at this point nothing is responding so I continue to get “other end is not receiving” errors.
Tape Loading via TZXDuino
At present it is looking like the hardware is probably working, which does seem to point therefore to the target monitor application. Typing the code in was never really a reliable option, so I need to find a way to load it in directly. That is the next task.
I’ve just acquired a TZXDuino. I must admit I was seriously considering just building one, but then decided I wouldn’t be learning much new by doing so and would rather have a neater unit so I bought one from MyRetroStore (link here). There is even an option of 3D printing a case, which I’ll look into a some point.
The more modern way to get games loaded is something like the DivMMC but that is a lot more expensive. Another option could be the Dandanator, but that requires reprogramming memory every time something changes. Possibly something for the future. I particularly wanted to go back to that “tape loading” experience initially (but without going on a side-quest to get my old tape player working again – this project has had enough side questions already!) so the TZXDuino is a great option for me.
It will take TAP and TZX files only though with is a bit of a limitation, but games can be found if you hunt around enough (although many sites seem to have stopped publishing downloadable TAP or TGZ files). It also has the ability to load up AY sound tracks, so that will be something to explore in the future when I get one of my 128Ks running again.
It requires a micro SD card, a mini-USB power lead and a mono 3.5 to 3.5 jack to plug into the Spectrums EAR socket (the Spectrum sockets are labelled for the thing they need to plug into).
One downside of the composite video mod is that there is no audio through the monitor/TV anymore. But the MIC socket provides an audio out that can be fed into an external amp or even the audio companion sockets to the composite video again using a mono 3.5mm jack lead.
This is a sight and experience I haven’t had for a long time. And given (waves hands around), perhaps it was from “a more civilized age” too…
The Spectrum Monitor
The biggest issue I have is how to bootstrap everything, but now I can load in TAP files, I “just” need to figure out how to create a TAP file from my pds binaries from Part 5. I spent a bit of time looking at the format of a TAP file and could probably write something to hard-code one out – it is basically a wrapper format for a string of binary chunks of data normally created from the Spectrum SAVE command – but then I found http://zeroteam.sk/bin2tap.html which does exactly that and has a Windows command line tool pre-built.
I used the following command to create a TAP file for the PDS DL0 binary created in Part 5:
bin2tap(vs3008).exe -a 32768 -r 32760 pdsdl0.bin
This sets the load address to 32768 ($8000) which is the origin used in the assembler. It also sets the start address to 32760 ($7FF8) which apparently is where execution will start (I don’t really understand why at this stage). This creates the file pdsdl0.tap by default.
This can now be transferred to the TZXDuino and loading in using LOAD “” in the usual way. Except that it seems to drop out before fully loading.
After experimenting with some more options (the source code for the tool has a really good readme) I settled on:
bin2tap(vs3008).exe -a 32768 -r 32760 -b pdsdl0.bin
This adds the “-b” option which creates a BASIC bootloader program. I haven’t seen the produced code directly myself, but the readme suggests it will create the following BASIC loader (there is a good explanation of how this works here):
10 REM loader by bin2tap1.3
20 BORDER VAL "0": PAPER VAL "0": INK VAL "7"
30 CLEAR VAL "24575"
40 POKE VAL "23739", CODE "o"
50 LOAD "name_of_file" CODE
60 RANDOMIZE USR VAL "32768"In this example, 24575 is the default “reserve memory” address (I want to use 32760). The POKE in line 40 apparently disables the messages that show bytes loading and so on (more here). You need to use the “-hp” option to include this, so mine probably won’t.
This still seems to drop out, so I wondered if the code was a bit small. I opened the pdsdl0.bin file in Notepad++ and used the HEX viewer plugin to pad the code out to address $200 with 0s. Then re-running the convertion this now does indeed seem to load. The screen goes black after showing the pdsdl0 code string and everything seems to hang – but I think this is just the PDS code running.
When I attempt a fill command now from the PDS, I’m no longer getting “not receiving” errors, so this sounds hopeful. The basic downloader DL0 though doesn’t really let me do very much, so I’m now repeating the above with the DL1 code.
Here is my full procedure to create a DL1 bootloader running on a real ZX Spectrum:
- Use https://beta.asm80.com/.
- Create a new file called pdsdl1.z80 and paste in spec.dl1 from the PDS\Demos area.
- Add “:” to all the code labels.
- Expand all shortcut jump instructions to their full versions – e.g. JZ LABEL becomes JP Z,LABEL
- Comment out the last section which has PDS specific commands to load and run.
- There is one s1 label that needs to be changed to upper case S1.
- Build -> Compile.
- On the resultant HEX file, right click and then select HEX -> BIN.
- Open the resultant, downloaded, pdsdl1.bin file in a hex editor and pad it with zeros out to address $1FF and save.
- Run the following command to create the TAP file:
bin2tap(vs3008).exe -a 32768 -r 32760 -b pdsdl1.bin -o pdsdl1.tap
- Save the pdsdl1.tap file to the TZXDuino and load onto the ZX Spectrum using LOAD “”. The screen will eventually go blank and the border will stop changing, leaving just Bytes: pdsdl1 at the top.
Test using the PDS Monitor (F4). A good command to use is the following which writes directly to the Spectrum display so the effect can be seen straight away:
F 16384,256,45
I now need to do some work on the GitHub repository and start writing some of this up over there. I’ll also upload the TAP file as a “getting started” file. When I’ve done all that, I’ll revisit this post and add some links to everything.
When it comes to actually downloading code to the Spectrum, it is mixed. I appear to be able to load and run a simple machine code program, but I don’t seem to be able to do it without crashing and killing the Spectrum and monitor.
I suspect this is my lack of knowledge about how the PDS is meant to function. The manual does suggest:
But I don’t know what configuration was used for the default bootloader and every time I’ve tried to rebuild it using the PDS and upload it, everything hangs.
I think at this point, there is where I turn things over to someone who actually knows about the PDS. But for me, I can see the hardware is working as I have been able to do all the following:
- Fill memory.
- Upload memory.
- Upload the register list.
- Assemble and download code, but it runs and crashes.
Future Directions
In 2026 there are a number of ways of getting code developed for and running on a ZX Spectrum: emulators, ROM simulators, tape emulators, even online web tools.
Given all that, the idea that it is worth updating something like the PDS is a little redundant, but I have been wondering about a few things that might make the system a little more accessible to modern technology.
The following possible improvements will increasingly take the PDS further and further away from being a PDS though and more towards some of the other more modern techniques, but for completeness, these are the things I’ve been contemplating.
Design improvements to the system “as is”:
- Make the target cards taller or put components on back so they can plug in vertically.
- A full-sized ISA card size with connectors in the same position as the original card.
Upgrades to avoid the problems sourcing components:
- Replace 8255 and Z80 PIO with a microcontroller emulation to keep the same register interface.
- Rewire the PC side IDC sockets to make ribbon cables non-mirrored – i.e. so it can be used with ready-made cables. This is a breaking compatibility change of course.
Design changes that make it a lot less a PDS:
- Create a Pico/USB interface directly to the same target board interface. Ideally there would be some kind of software ISA-over-USB type emulation at the PC end which means the PC software doesn’t need updating (not sure this is even possible tbh).
- Include a small boot ROM on the target board with the monitor program already installed to save having to load it from tape.
I now need to get back to the RetroCollective where there are people who actually know how to use a PDS to see if we can get them up and running and doing something useful with it!
Fingers crossed, we’re nearly there (famous last words?).
Kevin
#pds #programmersDevelopmentSystem #tzxduino #zxSpectrum -
PDS – the Programmers Development System – Part 6
This series of posts looks at the Programmers Development System (PDS).
- 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)!
This part gets serious about attempting to debug eveything and find out why it isn’t working…
PDS Diagnostic Breakout
The starting point is trying to figure out what is going on with the signals on the link. To do that, I’ve built a simple breakout which can be used to probe the signal lines or, as in my case, attach some LEDs.
I initially thought I could use some of those “cobbler” breakout boards that expand out Raspberry Pi GPIO to solderless breadboards. But unfortunately, they aren’t a direct 2×13, 2×20 mapping to the breadboard, as the GND pins are all linked together and would short some of the PDS connections.
Instead I went with building something simple myself using protoboard:
It is a straight, simple breakout from the 2×8 way header to two sets of 8-way header pins suitable for plugging into a solderless breadboard.
I’m wiring it up as a “straight through” connection to the target board, mostly to save me having to make more PDS cables – doing it this way means a simple Euro rack 2×8 power ribbon will do (and I have quite a few of those kicking around).
This is the wiring I’m using for the board. Recall the target connector has the following pinouts:
N/CN/CN/CN/CN/CZX->PCPC->ZXGNDD7D6D5D4D3D2D1D0Assuming I have it all right of course.
This now allows me to attach some 8-way LED breakout boards that connect to 8 signals plus ground to allow for easy observations.
Testing the ZX Spectrum Board
At this point I can confirm that the ZX Spectrum target board can still talk to its Z80 PIO using the following BASIC code:
10 OUT 127,255
20 OUT 127,63
30 FOR n=0 TO 100: NEXT n
40 OUT 63,128
50 FOR n=0 TO 100: NEXT n
60 OUT 63,0
70 GOTO 30This is basically a ZX Spectrum/Z80 PIO/PDS “blink” application using the “ZX to PC” pin.
https://makertube.net/w/kQNKyii3R9gYu2iiW6r2f5
So what is going on here? Recall from Part 1 that the IO ports used are as follows:
IO PORTFunctionNotes31Port A DataUsed for the D0-D7 lines (via a buffer)63Port B DataUsed for the ZX<->PC control95Port A ControlUsing Z80 PIO “Mode 3”127Port B ControlUsing Z80 PIO “Mode 3”The mapping of Port B Data to PDS control pins isn’t as one might expect however, again from Part 1, we have noted:
76543210 PORT B DATA BITS
0-- Pin 3: PC to ZX
4321--- Not used
5------- Pin 7: Function unknown
6-------- Data buffer direction control (0=OUT; 1=IN)
7--------- Pin 5: ZX to PCArmed with this knowledge, we can explain the BASIC program as follows:
OUT 127,255 : PORT B Control = b11111111 MODE 3: bidirectional
OUT 127,63 : PORT B Control = b00111111 Bits 6,7=OUTPUT, 0-5=INPUT
OUT 63, 128 : PORT B Data = b10000000
OUT 63, 0 : PORT B Data = b00000000The data lines go via a buffer, so can also be driven if the DIR pin (bit 6 of PORT B) is set appropriately prior to use (LOW = OUTPUT):
10 OUT 127,255 : REM Mode 3
20 OUT 127,63 : REM b6,7=OUT, b0-5=IN
30 OUT 95,255 : REM Mode 3
40 OUT 95,0 : REM b0-7=OUT
50 OUT 63,128 : REM b7=HIGH
60 FOR n=0 TO 100: NEXT n
70 OUT 63,0 : REM b7=LOW
80 FOR n=0 TO 255
90 OUT 31,n : D0-7 = n
95 FOR f=0 TO 10: NEXT f
100 NEXT n
110 OUT 31,0 : D0-7 = 0
120 GOTO 50At this point I can see all data lines counting and the ZX to PC pin being toggled as expected.
Whilst I’m on the topic, I should probably check the input side too.
10 OUT 127,255 : REM Mode 3
20 OUT 127,63 : REM b6,7=OUT, b0-5=IN
30 OUT 95,255 : REM Mode 3
40 OUT 95,255 : REM b0-7=IN
50 OUT 63,192 : REM b7=HIGH, b6=HIGH
60 FOR n=0 TO 10
70 PRINT IN 31
80 NEXT n
90 OUT 63,64 : REM b7=LOW, b6=HIGH
100 FOR n=0 TO 10
110 PRINT IN 31
120 NEXT n
130 GOTO 50With this, I can connect the single OUTPUT pin to any of the data lines and see if the values change as the OUTPUT pin state changes. The pins do indeed change, but the state is often inverted, so when the OUTPUT is connected to D1 (for example) the value toggles between 255 and 253, but this is basically because the other input lines are floating when not connected and in this case are reading HIGH.
All good so far. Next is to see what happens when I fire up the PC end.
Testing the PC Board
Making sure the Spectrum PDS is in INPUT mode, I can try some commands from the PC (I’m still not running the monitor at this stage):
10 OUT 127,255 : REM Mode 3
20 OUT 127,63 : REM OOIIIIII
30 OUT 95,255 : REM Mode 3
40 OUT 95,255 : REM IIIIIIII
50 OUT 63,192 : DIR PC->ZX (plus setting b7 so I can see something)When I run the F(ill) command in the Monitor (F4):
F 32768,16,255
I can see one of the control lines and some of the data lines flash, so that is an encouraging sign that the PC card has a working 8255 IO device and is able to at least try to send data to the target.
Catching it on video, it is just about possible to make out the binary value put on the data lines reading 10110011 which is 179 in decimal. Looking at the PDS protocol description in the PDS Z80 Manual, we can see that 179 is used a lot at the start of commands, as it is the padding byte.
Changing the command to 183 (change bank “Z 1”) which doesn’t have a padding byte, I can indeed see a different pattern on the data bus for b10110111 or for the register command (184, “R”) b10111000.
I can also see the “PC to ZX” control bit changing as the commands are happening, so this gives me confidence that the 8255 on the PC card is at least outputting ok.
Of course at this point nothing is responding so I continue to get “other end is not receiving” errors.
Tape Loading via TZXDuino
At present it is looking like the hardware is probably working, which does seem to point therefore to the target monitor application. Typing the code in was never really a reliable option, so I need to find a way to load it in directly. That is the next task.
I’ve just acquired a TZXDuino. I must admit I was seriously considering just building one, but then decided I wouldn’t be learning much new by doing so and would rather have a neater unit so I bought one from MyRetroStore (link here). There is even an option of 3D printing a case, which I’ll look into a some point.
The more modern way to get games loaded is something like the DivMMC but that is a lot more expensive. Another option could be the Dandanator, but that requires reprogramming memory every time something changes. Possibly something for the future. I particularly wanted to go back to that “tape loading” experience initially (but without going on a side-quest to get my old tape player working again – this project has had enough side questions already!) so the TZXDuino is a great option for me.
It will take TAP and TZX files only though with is a bit of a limitation, but games can be found if you hunt around enough (although many sites seem to have stopped publishing downloadable TAP or TGZ files). It also has the ability to load up AY sound tracks, so that will be something to explore in the future when I get one of my 128Ks running again.
It requires a micro SD card, a mini-USB power lead and a mono 3.5 to 3.5 jack to plug into the Spectrums EAR socket (the Spectrum sockets are labelled for the thing they need to plug into).
One downside of the composite video mod is that there is no audio through the monitor/TV anymore. But the MIC socket provides an audio out that can be fed into an external amp or even the audio companion sockets to the composite video again using a mono 3.5mm jack lead.
This is a sight and experience I haven’t had for a long time. And given (waves hands around), perhaps it was from “a more civilized age” too…
The Spectrum Monitor
The biggest issue I have is how to bootstrap everything, but now I can load in TAP files, I “just” need to figure out how to create a TAP file from my pds binaries from Part 5. I spent a bit of time looking at the format of a TAP file and could probably write something to hard-code one out – it is basically a wrapper format for a string of binary chunks of data normally created from the Spectrum SAVE command – but then I found http://zeroteam.sk/bin2tap.html which does exactly that and has a Windows command line tool pre-built.
I used the following command to create a TAP file for the PDS DL0 binary created in Part 5:
bin2tap(vs3008).exe -a 32768 -r 32760 pdsdl0.bin
This sets the load address to 32768 ($8000) which is the origin used in the assembler. It also sets the start address to 32760 ($7FF8) which apparently is where execution will start (I don’t really understand why at this stage). This creates the file pdsdl0.tap by default.
This can now be transferred to the TZXDuino and loading in using LOAD “” in the usual way. Except that it seems to drop out before fully loading.
After experimenting with some more options (the source code for the tool has a really good readme) I settled on:
bin2tap(vs3008).exe -a 32768 -r 32760 -b pdsdl0.bin
This adds the “-b” option which creates a BASIC bootloader program. I haven’t seen the produced code directly myself, but the readme suggests it will create the following BASIC loader (there is a good explanation of how this works here):
10 REM loader by bin2tap1.3
20 BORDER VAL "0": PAPER VAL "0": INK VAL "7"
30 CLEAR VAL "24575"
40 POKE VAL "23739", CODE "o"
50 LOAD "name_of_file" CODE
60 RANDOMIZE USR VAL "32768"This still seems to drop out, so I wondered if the code was a bit small. I opened the pdsdl0.bin file in Notepad++ and used the HEX viewer plugin to pad the code out to address $200 with 0s. Then re-running the convertion this now does indeed seem to load. The screen goes black after showing the pdsdl0 code string and everything seems to hang – but I think this is just the PDS code running.
When I attempt a fill command now from the PDS, I’m no longer getting “not receiving” errors, so this sounds hopeful. The basic downloader DL0 though doesn’t really let me do very much, so I’m now repeating the above with the DL1 code.
Here is my full procedure to create a DL1 bootloader running on a real ZX Spectrum:
- Use https://beta.asm80.com/.
- Create a new file called pdsdl1.z80 and paste in spec.dl1 from the PDS\Demos area.
- Add “:” to all the code labels.
- Expand all shortcut jump instructions to their full versions – e.g. JZ LABEL becomes JP Z,LABEL
- Comment out the last section which has PDS specific commands to load and run.
- There is one s1 label that needs to be changed to upper case S1.
- Build -> Compile.
- On the resultant HEX file, right click and then select HEX -> BIN.
- Open the resultant, downloaded, pdsdl1.bin file in a hex editor and pad it with zeros out to address $1FF and save.
- Run the following command to create the TAP file:
bin2tap(vs3008).exe -a 32768 -r 32760 -b pdsdl1.bin -o pdsdl1.tap
- Save the pdsdl1.tap file to the TZXDuino and load onto the ZX Spectrum using LOAD “”. The screen will eventually go blank and the border will stop changing, leaving just Bytes: pdsdl1 at the top.
Test using the PDS Monitor (F4). A good command to use is the following which writes directly to the Spectrum display so the effect can be seen straight away:
F 16384,256,45
I now need to do some work on my GitHub repository and start writing some of this up over there. I’ll also upload the TAP file as a “getting started” file. When I’ve done all that, I’ll revisit this post and add some links to everything.
I really need to prove that I can now use the PDS to upload and run code, but this is an excellent step forward. It shows the basic systems is working!
Future Directions
In 2026 there are a number of ways of getting code developed for and running on a ZX Spectrum: emulators, ROM simulators, tape emulators, even online web tools.
Given all that, the idea that it is worth updating something like the PDS is a little redundant, but I have been wondering about a few things that might make the system a little more accessible to modern technology.
The following possible improvements will increasingly take the PDS further and further away from being a PDS though and more towards some of the other more modern techniques, but for completeness, these are the things I’ve been contemplating.
Design improvements to the system “as is”:
- Make the target cards taller or put components on back so they can plug in vertically.
- A full-sized ISA card size with connectors in the same position as the original card.
Upgrades to avoid the problems sourcing components:
- Replace 8255 and Z80 PIO with a microcontroller emulation to keep the same register interface.
- Rewire the PC side IDC sockets to make ribbon cables non-mirrored – i.e. so it can be used with ready-made cables. This is a breaking compatibility change of course.
Design changes that make it a lot less a PDS:
- Create a Pico/USB interface directly to the same target board interface. Ideally there would be some kind of software ISA-over-USB type emulation at the PC end which means the PC software doesn’t need updating (not sure this is even possible tbh).
- Include a small boot ROM on the target board with the monitor program already installed to save having to load it from tape.
I now need to get back to the RetroCollective where there are people who actually know how to use a PDS to see if we can get them up and running and doing something useful with it!
Fingers crossed, we’re nearly there (famous last words?).
Kevin
#pds #programmersDevelopmentSystem #tzxduino #zxSpectrum -
PDS – the Programmers Development System – Part 6
This series of posts looks at the Programmers Development System (PDS).
- 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
This part gets serious about attempting to debug eveything and find out why it isn’t working…
PDS Diagnostic Breakout
The starting point is trying to figure out what is going on with the signals on the link. To do that, I’ve built a simple breakout which can be used to probe the signal lines or, as in my case, attach some LEDs.
I initially thought I could use some of those “cobbler” breakout boards that expand out Raspberry Pi GPIO to solderless breadboards. But unfortunately, they aren’t a direct 2×13, 2×20 mapping to the breadboard, as the GND pins are all linked together and would short some of the PDS connections.
Instead I went with building something simple myself using protoboard:
It is a straight, simple breakout from the 2×8 way header to two sets of 8-way header pins suitable for plugging into a solderless breadboard.
I’m wiring it up as a “straight through” connection to the target board, mostly to save me having to make more PDS cables – doing it this way means a simple Euro rack 2×8 power ribbon will do (and I have quite a few of those kicking around).
This is the wiring I’m using for the board. Recall the target connector has the following pinouts:
N/CN/CN/CN/CN/CZX->PCPC->ZXGNDD7D6D5D4D3D2D1D0Assuming I have it all right of course.
This now allows me to attach some 8-way LED breakout boards that connect to 8 signals plus ground to allow for easy observations.
Testing the ZX Spectrum Board
At this point I can confirm that the ZX Spectrum target board can still talk to its Z80 PIO using the following BASIC code:
10 OUT 127,255
20 OUT 127,63
30 FOR n=0 TO 100: NEXT n
40 OUT 63,128
50 FOR n=0 TO 100: NEXT n
60 OUT 63,0
70 GOTO 30This is basically a ZX Spectrum/Z80 PIO/PDS “blink” application using the “ZX to PC” pin.
https://makertube.net/w/kQNKyii3R9gYu2iiW6r2f5
So what is going on here? Recall from Part 1 that the IO ports used are as follows:
IO PORTFunctionNotes31Port A DataUsed for the D0-D7 lines (via a buffer)63Port B DataUsed for the ZX<->PC control95Port A ControlUsing Z80 PIO “Mode 3”127Port B ControlUsing Z80 PIO “Mode 3”The mapping of Port B Data to PDS control pins isn’t as one might expect however, again from Part 1, we have noted:
76543210 PORT B DATA BITS
0-- Pin 3: PC to ZX
4321--- Not used
5------- Pin 7: Function unknown
6-------- Data buffer direction control (0=OUT; 1=IN)
7--------- Pin 5: ZX to PCArmed with this knowledge, we can explain the BASIC program as follows:
OUT 127,255 : PORT B Control = b11111111 MODE 3: bidirectional
OUT 127,63 : PORT B Control = b00111111 Bits 6,7=OUTPUT, 0-5=INPUT
OUT 63, 128 : PORT B Data = b10000000
OUT 63, 0 : PORT B Data = b00000000The data lines go via a buffer, so can also be driven if the DIR pin (bit 6 of PORT B) is set appropriately prior to use (LOW = OUTPUT):
10 OUT 127,255 : REM Mode 3
20 OUT 127,63 : REM b6,7=OUT, b0-5=IN
30 OUT 95,255 : REM Mode 3
40 OUT 95,0 : REM b0-7=OUT
50 OUT 63,128 : REM b7=HIGH
60 FOR n=0 TO 100: NEXT n
70 OUT 63,0 : REM b7=LOW
80 FOR n=0 TO 255
90 OUT 31,n : D0-7 = n
95 FOR f=0 TO 10: NEXT f
100 NEXT n
110 OUT 31,0 : D0-7 = 0
120 GOTO 50At this point I can see all data lines counting and the ZX to PC pin being toggled as expected.
Whilst I’m on the topic, I should probably check the input side too.
10 OUT 127,255 : REM Mode 3
20 OUT 127,63 : REM b6,7=OUT, b0-5=IN
30 OUT 95,255 : REM Mode 3
40 OUT 95,255 : REM b0-7=IN
50 OUT 63,192 : REM b7=HIGH, b6=HIGH
60 FOR n=0 TO 10
70 PRINT IN 31
80 NEXT n
90 OUT 63,64 : REM b7=LOW, b6=HIGH
100 FOR n=0 TO 10
110 PRINT IN 31
120 NEXT n
130 GOTO 50With this, I can connect the single OUTPUT pin to any of the data lines and see if the values change as the OUTPUT pin state changes. The pins do indeed change, but the state is often inverted, so when the OUTPUT is connected to D1 (for example) the value toggles between 255 and 253, but this is basically because the other input lines are floating when not connected and in this case are reading HIGH.
All good so far. Next is to see what happens when I fire up the PC end.
Testing the PC Board
Making sure the Spectrum PDS is in INPUT mode, I can try some commands from the PC (I’m still not running the monitor at this stage):
10 OUT 127,255 : REM Mode 3
20 OUT 127,63 : REM OOIIIIII
30 OUT 95,255 : REM Mode 3
40 OUT 95,255 : REM IIIIIIII
50 OUT 63,192 : DIR PC->ZX (plus setting b7 so I can see something)When I run the F(ill) command in the Monitor (F4):
F 32768,16,255
I can see one of the control lines and some of the data lines flash, so that is an encouraging sign that the PC card has a working 8255 IO device and is able to at least try to send data to the target.
Catching it on video, it is just about possible to make out the binary value put on the data lines reading 10110011 which is 179 in decimal. Looking at the PDS protocol description in the PDS Z80 Manual, we can see that 179 is used a lot at the start of commands, as it is the padding byte.
Changing the command to 183 (change bank “Z 1”) which doesn’t have a padding byte, I can indeed see a different pattern on the data bus for b10110111 or for the register command (184, “R”) b10111000.
I can also see the “PC to ZX” control bit changing as the commands are happening, so this gives me confidence that the 8255 on the PC card is at least outputting ok.
Of course at this point nothing is responding so I continue to get “other end is not receiving” errors.
Tape Loading via TZXDuino
At present it is looking like the hardware is probably working, which does seem to point therefore to the target monitor application. Typing the code in was never really a reliable option, so I need to find a way to load it in directly. That is the next task.
I’ve just acquired a TZXDuino. I must admit I was seriously considering just building one, but then decided I wouldn’t be learning much new by doing so and would rather have a neater unit so I bought one from MyRetroStore (link here). There is even an option of 3D printing a case, which I’ll look into a some point.
The more modern way to get games loaded is something like the DivMMC but that is a lot more expensive. Another option could be the Dandanator, but that requires reprogramming memory every time something changes. Possibly something for the future. I particularly wanted to go back to that “tape loading” experience initially (but without going on a side-quest to get my old tape player working again – this project has had enough side questions already!) so the TZXDuino is a great option for me.
It will take TAP and TZX files only though with is a bit of a limitation, but games can be found if you hunt around enough (although many sites seem to have stopped publishing downloadable TAP or TGZ files). It also has the ability to load up AY sound tracks, so that will be something to explore in the future when I get one of my 128Ks running again.
It requires a micro SD card, a mini-USB power lead and a mono 3.5 to 3.5 jack to plug into the Spectrums EAR socket (the Spectrum sockets are labelled for the thing they need to plug into).
One downside of the composite video mod is that there is no audio through the monitor/TV anymore. But the MIC socket provides an audio out that can be fed into an external amp or even the audio companion sockets to the composite video again using a mono 3.5mm jack lead.
This is a sight and experience I haven’t had for a long time. And given (waves hands around), perhaps it was from “a more civilized age” too…
The Spectrum Monitor
The biggest issue I have is how to bootstrap everything, but now I can load in TAP files, I “just” need to figure out how to create a TAP file from my pds binaries from Part 5. I spent a bit of time looking at the format of a TAP file and could probably write something to hard-code one out – it is basically a wrapper format for a string of binary chunks of data normally created from the Spectrum SAVE command – but then I found http://zeroteam.sk/bin2tap.html which does exactly that and has a Windows command line tool pre-built.
I used the following command to create a TAP file for the PDS DL0 binary created in Part 5:
bin2tap(vs3008).exe -a 32768 -r 32760 pdsdl0.bin
This sets the load address to 32768 ($8000) which is the origin used in the assembler. It also sets the start address to 32760 ($7FF8) which apparently is where execution will start (I don’t really understand why at this stage). This creates the file pdsdl0.tap by default.
This can now be transferred to the TZXDuino and loading in using LOAD “” in the usual way. Except that it seems to drop out before fully loading.
After experimenting with some more options (the source code for the tool has a really good readme) I settled on:
bin2tap(vs3008).exe -a 32768 -r 32760 -b pdsdl0.bin
This adds the “-b” option which creates a BASIC bootloader program. I haven’t seen the produced code directly myself, but the readme suggests it will create the following BASIC loader (there is a good explanation of how this works here):
10 REM loader by bin2tap1.3
20 BORDER VAL "0": PAPER VAL "0": INK VAL "7"
30 CLEAR VAL "24575"
40 POKE VAL "23739", CODE "o"
50 LOAD "name_of_file" CODE
60 RANDOMIZE USR VAL "32768"In this example, 24575 is the default “reserve memory” address (I want to use 32760). The POKE in line 40 apparently disables the messages that show bytes loading and so on (more here). You need to use the “-hp” option to include this, so mine probably won’t.
This still seems to drop out, so I wondered if the code was a bit small. I opened the pdsdl0.bin file in Notepad++ and used the HEX viewer plugin to pad the code out to address $200 with 0s. Then re-running the convertion this now does indeed seem to load. The screen goes black after showing the pdsdl0 code string and everything seems to hang – but I think this is just the PDS code running.
When I attempt a fill command now from the PDS, I’m no longer getting “not receiving” errors, so this sounds hopeful. The basic downloader DL0 though doesn’t really let me do very much, so I’m now repeating the above with the DL1 code.
Here is my full procedure to create a DL1 bootloader running on a real ZX Spectrum:
- Use https://beta.asm80.com/.
- Create a new file called pdsdl1.z80 and paste in spec.dl1 from the PDS\Demos area.
- Add “:” to all the code labels.
- Expand all shortcut jump instructions to their full versions – e.g. JZ LABEL becomes JP Z,LABEL
- Comment out the last section which has PDS specific commands to load and run.
- There is one s1 label that needs to be changed to upper case S1.
- Build -> Compile.
- On the resultant HEX file, right click and then select HEX -> BIN.
- Open the resultant, downloaded, pdsdl1.bin file in a hex editor and pad it with zeros out to address $1FF and save.
- Run the following command to create the TAP file:
bin2tap(vs3008).exe -a 32768 -r 32760 -b pdsdl1.bin -o pdsdl1.tap
- Save the pdsdl1.tap file to the TZXDuino and load onto the ZX Spectrum using LOAD “”. The screen will eventually go blank and the border will stop changing, leaving just Bytes: pdsdl1 at the top.
Test using the PDS Monitor (F4). A good command to use is the following which writes directly to the Spectrum display so the effect can be seen straight away:
F 16384,256,45
I now need to do some work on the GitHub repository and start writing some of this up over there. I’ll also upload the TAP file as a “getting started” file. When I’ve done all that, I’ll revisit this post and add some links to everything.
When it comes to actually downloading code to the Spectrum, it is mixed. I appear to be able to load and run a simple machine code program, but I don’t seem to be able to do it without crashing and killing the Spectrum and monitor.
I suspect this is my lack of knowledge about how the PDS is meant to function. The manual does suggest:
But I don’t know what configuration was used for the default bootloader and every time I’ve tried to rebuild it using the PDS and upload it, everything hangs.
I think at this point, there is where I turn things over to someone who actually knows about the PDS. But for me, I can see the hardware is working as I have been able to do all the following:
- Fill memory.
- Upload memory.
- Upload the register list.
- Assemble and download code, but it runs and crashes.
Future Directions
In 2026 there are a number of ways of getting code developed for and running on a ZX Spectrum: emulators, ROM simulators, tape emulators, even online web tools.
Given all that, the idea that it is worth updating something like the PDS is a little redundant, but I have been wondering about a few things that might make the system a little more accessible to modern technology.
The following possible improvements will increasingly take the PDS further and further away from being a PDS though and more towards some of the other more modern techniques, but for completeness, these are the things I’ve been contemplating.
Design improvements to the system “as is”:
- Make the target cards taller or put components on back so they can plug in vertically.
- A full-sized ISA card size with connectors in the same position as the original card.
Upgrades to avoid the problems sourcing components:
- Replace 8255 and Z80 PIO with a microcontroller emulation to keep the same register interface.
- Rewire the PC side IDC sockets to make ribbon cables non-mirrored – i.e. so it can be used with ready-made cables. This is a breaking compatibility change of course.
Design changes that make it a lot less a PDS:
- Create a Pico/USB interface directly to the same target board interface. Ideally there would be some kind of software ISA-over-USB type emulation at the PC end which means the PC software doesn’t need updating (not sure this is even possible tbh).
- Include a small boot ROM on the target board with the monitor program already installed to save having to load it from tape.
I now need to get back to the RetroCollective where there are people who actually know how to use a PDS to see if we can get them up and running and doing something useful with it!
Fingers crossed, we’re nearly there (famous last words?).
Kevin
#pds #programmersDevelopmentSystem #tzxduino #zxSpectrum -
PDS – the Programmers Development System – Part 5
In this part I’m finally getting to properly test the boards, having finally managed to acquire all the parts I need: namely a working ZX Spectrum, an ISA based PC and the means to get software onto them both.
- 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
In terms of documentation for using the PDS, I have found the following:
- PDS IBM Editor Manual: “The_PDS_Editor_Manual.pdf”
- PDS Z80 Manual: “The_PDS_Z80_Manual.pdf”, “P.D.S.Manual.pdf”, “Manual_PDS”
The first describes how to install and use the PC software. The second describes the syntax and functionality of the assembler, and the technical details of the PC to ZX Spectrum target parallel interface.
PC Software
The PC side of the system can be found online in the file “P.D.S._PC-Software” which extracts out to the following:
demos\
arce.com
dopds.bar
pdsz80.exe
read.8
read.meThe PDS manual has this to say about the PC required to run it:
In my case I’ve found a 486 PC with some ISA slots and 256MB of RAM. It has DOS 6.2 installed on a few 100 MB harddisk.
To install the PDS, I copied the above onto a floppy from my laptop using USB floppy drive, then on the DOS PC ran the “dopds.bat” command:
c:\> a:\dopds
This created the c:\pds directory then I can go to that directory and run pdsz80.exe.
On first run I got the error mentioned in the manual saying there must be 640K of memory. After fiddling around moving things out of AUTOEXEC.BAT and CONFIG.SYS (this wasn’t a fresh DOS install), eventually I ran MEMMAKER and that managed to free up ~620K of memory for applications, which seemed to be enough for pdsz80.exe to run.
Later in the PDS manual it recommends the following CONFIG.SYS settings:
BUFFERS=20
FILES=20Note: With no PC card installed, I just get a blank, blue screen, but with the PC card installed I get the following screen, so I’m seeing that as a sign the card is being detected ok.
The FUNCTION keys trigger alternative modes. This one made me smile – I can’t remember when I last saw a phone number in some software…
The PDS Editor Manual details how to use the PDS software. The modes are selected using the following FUNCTION keys:
- F1 [ASSEMBLE] Assembles the program in memory.
- F2 [SAVE/LOAD] Saves or loads all 8 files.
- F3 [GRAPHICS] Enters the graphics editor.
- F4 [MONITOR] Enters the monitor.
- F5 [CONFIGURE] Enters the PDS configuration system.
- F6 [PRINT] Prints files.
- F7 [HELP] Engages the help facility.
- F8 [REPEAT] Repeats search and replace functions.
- F9 [DISK] Enter the PDS disk system.
- F10 [FINISH] Eds current task.
The [CONTROL] and [SCROLL LOCK] keys together enable a dual-window view.
The [HELP] system is interesting. From the manual:
The system came with HELP files for the processor. There is a help.65 and help.z80 file in the “demos” area which I’ve yet to try (I haven’t worked out how to load it yet).
To load in a file of code, for example from the demo areas, CTRL-R inserts it at the current cursor position. I’ve not been able to use the DISK subsystem as apparently I don’t have anything that is XMSDOS formatted. I believe I can load in a file using CTRL-L from the DOS directories though.
There are many time-saving features implemented in the editor including things like header comment generation, automatic labelling, a special ESCape mode for advanced commands and macros, and not to mention an expanded assembly syntax that makes a bit more sense than the original.
There is a real sense of being written by programmers for programmers. It feels massively ahead of its time if I’m honest.
The Target Code
The target code is provided in source form only, as part of the “demo” code for the PC application. This is Z80 assembler (for the ZX Spectrum version) that needs to be assembled and loaded into ZX Spectrum memory.
The problem is that this uses the PDS assembler syntax, which isn’t the same as many standard (if there is such a thing) Z80 assembler syntax.
So this presents a problem. I need to generate a binary, on a tape, that can be loaded into the ZX Spectrum, but I have to find a way to do that from the PDS environment itself. On a 486 PC.
The code itself has, I believe, a possible answer. The comments at the start of the code states the following:
; The long PDS download software for the ZX-SPECTRUM
;
;This is the long download software for the Spectrum, it allows all the
;monitor commands except Analyze to work correctly and will allow you
;to assemble and download programs.
;It may be situated anywhere in memory. Note that it uses up two bytes
;of stack space, it uses the Sinclair stack, setup at the top of memory
;or where ever you do a CLEAR. It disables the interupts, so you may
;download over the system variables at 5C00h upwards.
;
; The code is exactly 344 bytes long
;
;When you first run the download software you should jump to label START,
;if you intend to enter it again then you should jump to MONITOR as it will
;already be setup correctly.
;
;
;
; Setup this ORG to point where you want the download software to be in
; memory. Note that this program as is, requires eight bytes before this
; address for a small 'return to basic program'
;
ORG 8000H ;This could go anywhere (best in fast memory >8000h)
;Ok, so far so good. Then there is the following at the end:
;
; End of the download software, now a small program to set the top of memory
; one byte below the download software, then reset the spectrum and return
; to basic so you may save out the download software using the following
; basic loader :
;
; 1 LOAD "" CODE:RANDOMISE USR start address
;
; Save this using either :
;
; SAVE "DLOADER" LINE 1 : SAVE "CODE" CODE startaddress,344
;
; or for microdrives :
;
; SAVE *"m";1;"DLOADER" LINE 1 : SAVE *"m";1;"CODE" CODE startaddress,344
;
;
ORG START-8 ;Put before download (so gets overwritten)
EXEC $ ;Execute code from here
DI
LD DE,START-1 ;Where 'top of memory' will be
XOR A
JP 11CBH ;Reset Spectrum, leaving download software
;
;
;
SEND COMPUTER1
ENDI believe this allows the PDS to assemble and download the monitor code, then save it out to storage using the recommended BASIC commands once the Spectrum resets after loading.
It uses two PDS “pseudo ops” – “EXEC” and “SEND” which are special PDS commands to set the execution address for the code and to instruct the PDS to download the code, in this case using the COMPUTER1 interface.
But to get to this point requires a working PDS system in the first place. So how does all this start? The PDS Z80 manual has this to say:
This code is provided to allow one to rebuild the monitor with a custom location and so on, and yes, it does indeed assume you already have a monitor program on tape to load into the Spectrum to get everything started… So therein lies the problem.
There are some online assemblers that will compile down to a ZX Spectrum TAP file, which is a sound file ready for loading onto a Spectrum, so if I can fiddle with the syntax I might be able to use one of those.
Here I hit some issues:
- https://beta.asm80.com/ This allows me to build to a HEX file or similar, but there is no way I can find to get this into a format I can get to a ZX Spectrum.
- https://clrhome.org/asm/ This has a “build to TAP” option, but I just couldn’t get the interface to work with the PDS code.
- https://k1.spdns.de/cgi-bin/zasm.cgi This again allows me to upload a source file and produce several outputs, but again no option for a ZX Spectrum load format.
The next option is a tool like https://github.com/retro-speccy/bin2tap which takes a binary file and produces a ZX Spectrum TAP file. But this once again is source code, so that itself is an entire side-quest I don’t really want to follow right now.
Finally, I just decided I might have to type the binary in by hand, so I’m focussing on the minimal downloader – z80.dl0 and using asm80.com. This appears to require the following changes to the source.
- All jump instruction shortcuts need expanding – e.g. JZ -> JP Z; JNZ -> JP NZ; JC -> JP C and so on.
- Jump instructions also need a comma adding – e.g. JZ LABEL -> JP Z, LABEL.
- All labels need a “:” adding – e.g. “START” becomes “START:”.
- The last block of “small program” has to be removed, as this can’t be assembled or built without the PDS itself.
This gives me the following source:
ORG 8000H ;This could go anywhere (best in fast memory >8000h)
;
STARTL: DI
LD A,255
OUT (127),A
OUT (63),A
LD A,63
OUT (127),A
LD A,255
OUT (95),A ;Setup the direction of the IO ports
OUT (95),A
LD D,64 ;Setup flags - Input from main computer
;
; Main loop
;
MAINLOOP: CALL GETBYTE ;Get 'command byte'
LD A,E
CP 180 ;Download code into aabb, len=ccdd
JP Z,DLOAD
CP 183 ;Select bank aa
JP Z,SBANK
CP 181 ;Execute code from aabb?
JP NZ,MAINLOOP ;Not recognised - keep looping.
;
; Function 181, Execute code from aabb
;
CALL GETBYTE
LD H,E ;Get address of routine
CALL GETBYTE
LD L,E
LD BC,MAINLOOP
PUSH BC ;Put return address on stack and jump to routine
JP (HL)
;
; Function 180, Download code into aaaa, length=bbbb
;
DLOAD: CALL GETBYTE
LD H,E
CALL GETBYTE
LD L,E ;Get start address
CALL GETBYTE
LD B,E
CALL GETBYTE
LD C,E ;Get length of code
;
DLOAD1: CALL GETBYTE
LD (HL),E ;Get bytes and store in RAM
INC HL
DEC BC
LD A,B ;Keep getting bytes
OR C
JP NZ,DLOAD1
JR MAINLOOP ;Go back into main download loop
;
; Function 183, select bank xx (This is different for each target computer)
;
SBANK: CALL GETBYTE
LD BC,7FFDH ;HL, BC and A may be corrupted here
OUT (C),E ;This will change banks on the speccy '128
JR MAINLOOP ;E is the bank data byte, D is not to be used!
;
; Get a byte from the main computer into E
;
GETBYTE: IN A,(63)
XOR D
RRCA
JP C,GETBYTE ;Wait for 'I've sent the byte'
IN A,(31)
LD E,A ;Get the byte into the E register
LD A,D
OUT (63),A ;Say 'I've got it!'
XOR 129
LD D,A ;Flip flags for next byte
RET
;This builds to the following HEX file:
:10800000F33EFFD37FD33F3E3FD37F3EFFD35FD3CB
:108010005F1640CD5A807BFEB4CA3380FEB7CA508B
:1080200080FEB5C21380CD5A8063CD5A806B011398
:1080300080C5E9CD5A8063CD5A806BCD5A8043CD3F
:108040005A804BCD5A8073230B78B1C2438018C33A
:10805000CD5A8001FD7FED5918B9DB3FAA0FDA5ADE
:0B80600080DB1F5F7AD33FEE8157C921
:00000001FFDecoding this, requires understanding the HEX record format, which is essentially:
:<LEN><ADDR><TYPE><DATA><CKSUM>
~First Line~
: Start
10 Length=16 bytes in this record
8000 Address=0x8000
00 Record type=00, which is Data
F33E FFD3 7FD3 3F3E 3FD3 7F3E FFD3 5FD3
CB Checksum
~Penultimate Line~
:
0B Length=11 bytes
8060 Address=0x8060
00 Record type=00, Data
80DB 1F5F 7AD3 3FEE 8157 C9
21 Checksum
~Last Line~
: 00 0000
01 Record Type=01, End of File
FF ChecksumThis can be translated into the following BASIC program for the ZX Spectrum which stores the assembly as a series of numbers in a DATA statement and loads it into memory (see chapter 26 of the original ZX Spectrum BASIC Programming book).
Unfortunately I don’t think I can enter them as HEX, so they have to be converted to decimal. I used the following python script on the binary version of the output (right click on the hex file in the online assembler and do HEX -> BIN).
with open("pdsdl0.bin", "rb") as file:
data = file.read()
for b in data:
print(",", b, end='')Pasting the resultant output into a BASIC program as a series of DATA statements gives me the following.
5 CLEAR 32760
10 LET a=32768
20 READ n: POKE a,n
30 LET a=a+1: GOTO 20
40 DATA 243, 62, 255, 211, 127, 211, 63, 62
45 DATA 63, 211, 127, 62, 255, 211, 95, 211
50 DATA 95, 22, 64, 205, 90, 128, 123, 254
55 DATA 180, 202, 51, 128, 254, 183, 202, 80
60 DATA 128, 254, 181, 194, 19, 128, 205, 90
65 DATA 128, 99, 205, 90, 128, 107, 1, 19
70 DATA 128, 197, 233, 205, 90, 128, 99, 205
75 DATA 90, 128, 107, 205, 90, 128, 67, 205
80 DATA 90, 128, 75, 205, 90, 128, 115, 35
85 DATA 11, 120, 177, 194, 67, 128, 24, 195
90 DATA 205, 90, 128, 1, 253, 127, 237, 89
95 DATA 24, 185, 219, 63, 170, 15, 218, 90
100 DATA 128, 219, 31, 95, 122, 211, 63, 238, 129, 87, 201
RUN
PRINT USR 32768At this point I can type it into the ZX Spectrum and hit RUN to load it and then PRINT USR 32768 to run it. The screen goes blank and the Spectrum is now waiting for commands from the PDS. In theory.
Back at the PDS end, I’ve tried the Monitor (F4) F(ill) command and I get “ERROR – The other computer is not receiving.”
If I load in one of the existing downloader programs (using CTRL-R) and attempt to assemble it (F1), I get a message “From 7FF8h to 8156h, exec=7FF8h. Download (Y/N)?” and upon selecting “Y” at this point everything hangs…
Update (July 2026) – This works! I’ve added in an additional CLEAR command at the start so don’t know if that makes a difference, or if I was just really, really careful to make sure I typed everything in correctly, but the above BASIC code does now work and I can use F(ill) as described in Part 6 and see data being written to the display!
Conclusion (for now)
So at this point, the things I know are:
- The PDS software is running on the PC and appears to be able to see the PC Card.
- The target card appears to be able to be seen from a ZX Spectrum direct OUT instructions to the Z80 PIO’s registers.
- It wasn’t working.
So the issues could be any of:
- The PC card is wrong somehow (e.g. pinouts to the cable).
- The Intel 8255 isn’t working properly on the PC card.
- The cable is wrong somehow (remember it appears to have a reversal of pins).
- The target card is wrong somehow (e.g. pinouts to the cable).
- The Z80 PIO isn’t working properly on the ZX Spectrum card.
- The ZX Spectrum target software was typed in wrong (I tried it twice though).
- The ZX Spectrum target software isn’t built correctly.
- The ZX Spectrum target software is not compatible with this version of the PC software/hardware.
I need to get some proper debugging on the link to try to figure out what might be going on.
Spoilers: It is now working (see update above and full details in Part 6).
Kevin
#ISA #pds #programmersDevelopmentSystem #zxSpectrum -
PDS – the Programmers Development System – Part 5
In this part I’m finally getting to properly test the boards, having finally managed to acquire all the parts I need: namely a working ZX Spectrum, an ISA based PC and the means to get software onto them both.
- 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
In terms of documentation for using the PDS, I have found the following:
- PDS IBM Editor Manual: “The_PDS_Editor_Manual.pdf”
- PDS Z80 Manual: “The_PDS_Z80_Manual.pdf”, “P.D.S.Manual.pdf”, “Manual_PDS”
The first describes how to install and use the PC software. The second describes the syntax and functionality of the assembler, and the technical details of the PC to ZX Spectrum target parallel interface.
PC Software
The PC side of the system can be found online in the file “P.D.S._PC-Software” which extracts out to the following:
demos\
arce.com
dopds.bar
pdsz80.exe
read.8
read.meThe PDS manual has this to say about the PC required to run it:
In my case I’ve found a 486 PC with some ISA slots and 256MB of RAM. It has DOS 6.2 installed on a few 100 MB harddisk.
To install the PDS, I copied the above onto a floppy from my laptop using USB floppy drive, then on the DOS PC ran the “dopds.bat” command:
c:\> a:\dopds
This created the c:\pds directory then I can go to that directory and run pdsz80.exe.
On first run I got the error mentioned in the manual saying there must be 640K of memory. After fiddling around moving things out of AUTOEXEC.BAT and CONFIG.SYS (this wasn’t a fresh DOS install), eventually I ran MEMMAKER and that managed to free up ~620K of memory for applications, which seemed to be enough for pdsz80.exe to run.
Later in the PDS manual it recommends the following CONFIG.SYS settings:
BUFFERS=20
FILES=20Note: With no PC card installed, I just get a blank, blue screen, but with the PC card installed I get the following screen, so I’m seeing that as a sign the card is being detected ok.
The FUNCTION keys trigger alternative modes. This one made me smile – I can’t remember when I last saw a phone number in some software…
The PDS Editor Manual details how to use the PDS software. The modes are selected using the following FUNCTION keys:
- F1 [ASSEMBLE] Assembles the program in memory.
- F2 [SAVE/LOAD] Saves or loads all 8 files.
- F3 [GRAPHICS] Enters the graphics editor.
- F4 [MONITOR] Enters the monitor.
- F5 [CONFIGURE] Enters the PDS configuration system.
- F6 [PRINT] Prints files.
- F7 [HELP] Engages the help facility.
- F8 [REPEAT] Repeats search and replace functions.
- F9 [DISK] Enter the PDS disk system.
- F10 [FINISH] Eds current task.
The [CONTROL] and [SCROLL LOCK] keys together enable a dual-window view.
The [HELP] system is interesting. From the manual:
The system came with HELP files for the processor. There is a help.65 and help.z80 file in the “demos” area which I’ve yet to try (I haven’t worked out how to load it yet).
To load in a file of code, for example from the demo areas, CTRL-R inserts it at the current cursor position. I’ve not been able to use the DISK subsystem as apparently I don’t have anything that is XMSDOS formatted. I believe I can load in a file using CTRL-L from the DOS directories though.
There are many time-saving features implemented in the editor including things like header comment generation, automatic labelling, a special ESCape mode for advanced commands and macros, and not to mention an expanded assembly syntax that makes a bit more sense than the original.
There is a real sense of being written by programmers for programmers. It feels massively ahead of its time if I’m honest.
The Target Code
The target code is provided in source form only, as part of the “demo” code for the PC application. This is Z80 assembler (for the ZX Spectrum version) that needs to be assembled and loaded into ZX Spectrum memory.
The problem is that this uses the PDS assembler syntax, which isn’t the same as many standard (if there is such a thing) Z80 assembler syntax.
So this presents a problem. I need to generate a binary, on a tape, that can be loaded into the ZX Spectrum, but I have to find a way to do that from the PDS environment itself. On a 486 PC.
The code itself has, I believe, a possible answer. The comments at the start of the code states the following:
; The long PDS download software for the ZX-SPECTRUM
;
;This is the long download software for the Spectrum, it allows all the
;monitor commands except Analyze to work correctly and will allow you
;to assemble and download programs.
;It may be situated anywhere in memory. Note that it uses up two bytes
;of stack space, it uses the Sinclair stack, setup at the top of memory
;or where ever you do a CLEAR. It disables the interupts, so you may
;download over the system variables at 5C00h upwards.
;
; The code is exactly 344 bytes long
;
;When you first run the download software you should jump to label START,
;if you intend to enter it again then you should jump to MONITOR as it will
;already be setup correctly.
;
;
;
; Setup this ORG to point where you want the download software to be in
; memory. Note that this program as is, requires eight bytes before this
; address for a small 'return to basic program'
;
ORG 8000H ;This could go anywhere (best in fast memory >8000h)
;Ok, so far so good. Then there is the following at the end:
;
; End of the download software, now a small program to set the top of memory
; one byte below the download software, then reset the spectrum and return
; to basic so you may save out the download software using the following
; basic loader :
;
; 1 LOAD "" CODE:RANDOMISE USR start address
;
; Save this using either :
;
; SAVE "DLOADER" LINE 1 : SAVE "CODE" CODE startaddress,344
;
; or for microdrives :
;
; SAVE *"m";1;"DLOADER" LINE 1 : SAVE *"m";1;"CODE" CODE startaddress,344
;
;
ORG START-8 ;Put before download (so gets overwritten)
EXEC $ ;Execute code from here
DI
LD DE,START-1 ;Where 'top of memory' will be
XOR A
JP 11CBH ;Reset Spectrum, leaving download software
;
;
;
SEND COMPUTER1
ENDI believe this allows the PDS to assemble and download the monitor code, then save it out to storage using the recommended BASIC commands once the Spectrum resets after loading.
It uses two PDS “pseudo ops” – “EXEC” and “SEND” which are special PDS commands to set the execution address for the code and to instruct the PDS to download the code, in this case using the COMPUTER1 interface.
But to get to this point requires a working PDS system in the first place. So how does all this start? The PDS Z80 manual has this to say:
This code is provided to allow one to rebuild the monitor with a custom location and so on, and yes, it does indeed assume you already have a monitor program on tape to load into the Spectrum to get everything started… So therein lies the problem.
There are some online assemblers that will compile down to a ZX Spectrum TAP file, which is a sound file ready for loading onto a Spectrum, so if I can fiddle with the syntax I might be able to use one of those.
Here I hit some issues:
- https://beta.asm80.com/ This allows me to build to a HEX file or similar, but there is no way I can find to get this into a format I can get to a ZX Spectrum.
- https://clrhome.org/asm/ This has a “build to TAP” option, but I just couldn’t get the interface to work with the PDS code.
- https://k1.spdns.de/cgi-bin/zasm.cgi This again allows me to upload a source file and produce several outputs, but again no option for a ZX Spectrum load format.
The next option is a tool like https://github.com/retro-speccy/bin2tap which takes a binary file and produces a ZX Spectrum TAP file. But this once again is source code, so that itself is an entire side-quest I don’t really want to follow right now.
Finally, I just decided I might have to type the binary in by hand, so I’m focussing on the minimal downloader – z80.dl0 and using asm80.com. This appears to require the following changes to the source.
- All jump instruction shortcuts need expanding – e.g. JZ -> JP Z; JNZ -> JP NZ; JC -> JP C and so on.
- Jump instructions also need a comma adding – e.g. JZ LABEL -> JP Z, LABEL.
- All labels need a “:” adding – e.g. “START” becomes “START:”.
- The last block of “small program” has to be removed, as this can’t be assembled or built without the PDS itself.
This gives me the following source:
ORG 8000H ;This could go anywhere (best in fast memory >8000h)
;
STARTL: DI
LD A,255
OUT (127),A
OUT (63),A
LD A,63
OUT (127),A
LD A,255
OUT (95),A ;Setup the direction of the IO ports
OUT (95),A
LD D,64 ;Setup flags - Input from main computer
;
; Main loop
;
MAINLOOP: CALL GETBYTE ;Get 'command byte'
LD A,E
CP 180 ;Download code into aabb, len=ccdd
JP Z,DLOAD
CP 183 ;Select bank aa
JP Z,SBANK
CP 181 ;Execute code from aabb?
JP NZ,MAINLOOP ;Not recognised - keep looping.
;
; Function 181, Execute code from aabb
;
CALL GETBYTE
LD H,E ;Get address of routine
CALL GETBYTE
LD L,E
LD BC,MAINLOOP
PUSH BC ;Put return address on stack and jump to routine
JP (HL)
;
; Function 180, Download code into aaaa, length=bbbb
;
DLOAD: CALL GETBYTE
LD H,E
CALL GETBYTE
LD L,E ;Get start address
CALL GETBYTE
LD B,E
CALL GETBYTE
LD C,E ;Get length of code
;
DLOAD1: CALL GETBYTE
LD (HL),E ;Get bytes and store in RAM
INC HL
DEC BC
LD A,B ;Keep getting bytes
OR C
JP NZ,DLOAD1
JR MAINLOOP ;Go back into main download loop
;
; Function 183, select bank xx (This is different for each target computer)
;
SBANK: CALL GETBYTE
LD BC,7FFDH ;HL, BC and A may be corrupted here
OUT (C),E ;This will change banks on the speccy '128
JR MAINLOOP ;E is the bank data byte, D is not to be used!
;
; Get a byte from the main computer into E
;
GETBYTE: IN A,(63)
XOR D
RRCA
JP C,GETBYTE ;Wait for 'I've sent the byte'
IN A,(31)
LD E,A ;Get the byte into the E register
LD A,D
OUT (63),A ;Say 'I've got it!'
XOR 129
LD D,A ;Flip flags for next byte
RET
;This builds to the following HEX file:
:10800000F33EFFD37FD33F3E3FD37F3EFFD35FD3CB
:108010005F1640CD5A807BFEB4CA3380FEB7CA508B
:1080200080FEB5C21380CD5A8063CD5A806B011398
:1080300080C5E9CD5A8063CD5A806BCD5A8043CD3F
:108040005A804BCD5A8073230B78B1C2438018C33A
:10805000CD5A8001FD7FED5918B9DB3FAA0FDA5ADE
:0B80600080DB1F5F7AD33FEE8157C921
:00000001FFDecoding this, requires understanding the HEX record format, which is essentially:
:<LEN><ADDR><TYPE><DATA><CKSUM>
~First Line~
: Start
10 Length=16 bytes in this record
8000 Address=0x8000
00 Record type=00, which is Data
F33E FFD3 7FD3 3F3E 3FD3 7F3E FFD3 5FD3
CB Checksum
~Penultimate Line~
:
0B Length=11 bytes
8060 Address=0x8060
00 Record type=00, Data
80DB 1F5F 7AD3 3FEE 8157 C9
21 Checksum
~Last Line~
: 00 0000
01 Record Type=01, End of File
FF ChecksumThis can be translated into the following BASIC program for the ZX Spectrum which stores the assembly as a series of numbers in a DATA statement and loads it into memory (see chapter 26 of the original ZX Spectrum BASIC Programming book).
Unfortunately I don’t think I can enter them as HEX, so they have to be converted to decimal. I used the following python script on the binary version of the output (right click on the hex file in the online assembler and do HEX -> BIN).
with open("pdsdl0.bin", "rb") as file:
data = file.read()
for b in data:
print(",", b, end='')Pasting the resultant output into a BASIC program as a series of DATA statements gives me the following.
5 CLEAR 32760
10 LET a=32768
20 READ n: POKE a,n
30 LET a=a+1: GOTO 20
40 DATA 243, 62, 255, 211, 127, 211, 63, 62
45 DATA 63, 211, 127, 62, 255, 211, 95, 211
50 DATA 95, 22, 64, 205, 90, 128, 123, 254
55 DATA 180, 202, 51, 128, 254, 183, 202, 80
60 DATA 128, 254, 181, 194, 19, 128, 205, 90
65 DATA 128, 99, 205, 90, 128, 107, 1, 19
70 DATA 128, 197, 233, 205, 90, 128, 99, 205
75 DATA 90, 128, 107, 205, 90, 128, 67, 205
80 DATA 90, 128, 75, 205, 90, 128, 115, 35
85 DATA 11, 120, 177, 194, 67, 128, 24, 195
90 DATA 205, 90, 128, 1, 253, 127, 237, 89
95 DATA 24, 185, 219, 63, 170, 15, 218, 90
100 DATA 128, 219, 31, 95, 122, 211, 63, 238, 129, 87, 201
RUN
PRINT USR 32768At this point I can type it into the ZX Spectrum and hit RUN to load it and then PRINT USR 32768 to run it. The screen goes blank and the Spectrum is now waiting for commands from the PDS. In theory.
Back at the PDS end, I’ve tried the Monitor (F4) F(ill) command and I get “ERROR – The other computer is not receiving.”
If I load in one of the existing downloader programs (using CTRL-R) and attempt to assemble it (F1), I get a message “From 7FF8h to 8156h, exec=7FF8h. Download (Y/N)?” and upon selecting “Y” at this point everything hangs…
Update (July 2026) – This works! I’ve added in an additional CLEAR command at the start so don’t know if that makes a difference, or if I was just really, really careful to make sure I typed everything in correctly, but the above BASIC code does now work and I can use F(ill) as described in Part 6 and see data being written to the display!
Conclusion (for now)
So at this point, the things I know are:
- The PDS software is running on the PC and appears to be able to see the PC Card.
- The target card appears to be able to be seen from a ZX Spectrum direct OUT instructions to the Z80 PIO’s registers.
- It wasn’t working.
So the issues could be any of:
- The PC card is wrong somehow (e.g. pinouts to the cable).
- The Intel 8255 isn’t working properly on the PC card.
- The cable is wrong somehow (remember it appears to have a reversal of pins).
- The target card is wrong somehow (e.g. pinouts to the cable).
- The Z80 PIO isn’t working properly on the ZX Spectrum card.
- The ZX Spectrum target software was typed in wrong (I tried it twice though).
- The ZX Spectrum target software isn’t built correctly.
- The ZX Spectrum target software is not compatible with this version of the PC software/hardware.
I need to get some proper debugging on the link to try to figure out what might be going on.
Spoilers: It is now working (see update above and full details in Part 6).
Kevin
#ISA #pds #programmersDevelopmentSystem #zxSpectrum -
I think I'm making some progress on the PDS once again. I have a PC that seems to recognise the PDS PC ISA card which is great news.
You don't get screens like this in software these days of course...
-
I think I'm making some progress on the PDS once again. I have a PC that seems to recognise the PDS PC ISA card which is great news.
You don't get screens like this in software these days of course...
-
I think I'm making some progress on the PDS once again. I have a PC that seems to recognise the PDS PC ISA card which is great news.
You don't get screens like this in software these days of course...
-
I think I'm making some progress on the PDS once again. I have a PC that seems to recognise the PDS PC ISA card which is great news.
You don't get screens like this in software these days of course...
-
I think I'm making some progress on the PDS once again. I have a PC that seems to recognise the PDS PC ISA card which is great news.
You don't get screens like this in software these days of course...
-
PDS – the Programmers Development System – Part 4
This series of posts looks at the Programmers Development System (PDS).
- 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
This part goes through the build of the three boards I have so far.
PC Interface
The design information and BOM can be found in Part 2. Building the card is relatively straight forward, being mostly DIP sockets, capacitors and connectors. Getting hold of an Intel 8255 might be a little tricky, but they do exist. I’ve ended up with a D8255A, rather than the more typical P8255A, which I think might be an “industrial” version? I’m not sure, information about it doesn’t seem very easy to find.
I’ve got hold of some latching IDE connectors, which are very similar to those used with the original as far as I can see.
Some notes and observations at this stage:
- The connectors are perhaps a little close together for the latches, but I think they’ll be ok.
- The 8255’s capacitor is located under the footprint for the 40-way DIP. It can go on either side of the board.
- As you can see, I’ve used DIP sockets throughout.
Amstrad CPC Interface
The design notes and BOM for the target interfaces can be found in Part 3. There are more components, but building should again be relatively straight forward. Again getting the Z80 PIO is probably the most difficult part of the whole thing.
I figured that given the technology of the time, I’d need a NMOS part that can go to at least 4MHz. I initially went with using a GS Z8420B, which I thought was the 4MHz part, but I was mistaken. With a GS part the speeds go as follows (ref SGS Z80 Family Databook):
- Z8420B – 2.5MHz
- Z8420AB – 4MHz
- Z8420BB – 6MHz
So I need the AB or BB version. The Zilog parts will be Z842004 or Z842006 for the NMOS variants. It will be Z84C2006, and so on, for the CMOS versions.
After a first build using a straight-through, 50-way edge connector socket, I figured there probably wasn’t enough spacing between the edge connector and the Z80 PIO, so I doubt it would fit as a vertical card. Consequently I built a second card using a right-angled edge connector and will have the interface sitting horizontally. Assuming I actually find a CPC to try it with of course (as I don’t have one myself).
I added a switch for the enable function, but then realised that the switch is obscuring the on/off indication. With hindsight, I suspect pin headers and a jumper would be more useful here as I don’t expect this to be used a lot? I could be wrong.
ZX Spectrum Interface
The majority of this is the same as the Amstrad version, and again design details and BOM can be found in Part 3.
The key difference, naturally (apart from one less chip), is the edge connector itself. The ZX Spectrum requires a keyed 56-way connector, with both ends cut off. Really – it has to have connectors flush with the ends of the connector.
The typical way to obtain one of these seems to be to buy a standard 56-way connector, remove the pins from the 5th slot and cut off the edges to make them flush with the connectors.
Then the vacated slot needs filling with something to act as the positioning key. There is a 3D printed design here: https://www.thingiverse.com/thing:6556638 which I tried but didn’t seem to stay in very well. Well, for me, when I plugged it into a Spectrum, on removing the key was left behind. I guess it would need gluing in place.
Alternatively, I had more luck with the parts I cut off the edge connector – just cutting them down and pushing them into place, being careful not to let them force the edge connector to splay out.
Once again I started with straight through connectors but that is unlikely to fit on anything other than an original rubber-keyed Spectrum, and even then I’m not convinced it would be secure, so I also rebuilt this one with a right-angled connector too.
Link Cable
The pinouts for the cable have to reflect the original and from the information and as noted in Part 1, and from the photos on the CPC wiki, we can see that the two IDC sockets at each end of the cable have opposite pinouts – i.e. pins 1-16 at one end are wired to pins 16-1 at the other.
The target connection has to be made to the top connector on the PC card for the information I have about the PDS to make sense. Some of the connections on the second connector are reversed, so I don’t know how that works.
Errata
PC Card:
- I’m still deciding on the best location for the connections and size of the card. But I know it fits in an ISA PC!
ZX Spectrum Interface:
- I’ve realised the enable switch is the opposite sense to the original board.
- If I want a vertical card, then the components need to be further away from the edge connector (or possibly on the back).
Amstrad Interface:
- Same issues as the Spectrum card, plus I can’t actually test it 🙂
Next Steps
I can do some basic electrical connectivity tests, but at present: I don’t have an ISA PC; I don’t have an Amstrad CPC; and right at this point in time I don’t have a working machine among my ZX Spectrums.
The latter I’m working on. I do want to get at least one of them up and running, so that side might be solvable in a basic capacity shortly. I have verified the GND and 5V connections on the PCB with an actual edge connector though.
The other two might be a bit more problematic.
But there is some good news. The Retro Collective reached out to Andy Glaister about recreating the designs and received the response: “You absolutely have my permission to reproduce the boards, the designs and the software. I will see if I can dig up stuff to help. It would be good to see all the code again.”
This means I can now open up the GitHub repository.
Update:
- A ZX Spectrum will boot with Spectrum target card present, so that is good!
- Testing the Spectrum card with my RC2014 (via this add-on card, and with the clock dropped down to 2.5MHz) and then connecting a scope to the OUTPUT control pin (target to PC), I can see the level changing when I do the following:
; Configure Mode 3, B6,7 as OUTPUT
OUT 127,255
OUT 127,63
; Set OUTPUT HIGH
OUT 63,128
; Set OUTPUT LOW
OUT 63,0This gives me some confidence that the Z80 PIO does in fact work on the Spectrum board.
Kevin
#amstradCpc #pcb #pds #programmersDevelopmentSystem #zxSpectrum -
PDS – the Programmers Development System – Part 4
This series of posts looks at the Programmers Development System (PDS).
- 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.
This part goes through the build of the three boards I have so far.
PC Interface
The design information and BOM can be found in Part 2. Building the card is relatively straight forward, being mostly DIP sockets, capacitors and connectors. Getting hold of an Intel 8255 might be a little tricky, but they do exist. I’ve ended up with a D8255A, rather than the more typical P8255A, which I think might be an “industrial” version? I’m not sure, information about it doesn’t seem very easy to find.
I’ve got hold of some latching IDE connectors, which are very similar to those used with the original as far as I can see.
Some notes and observations at this stage:
- The connectors are perhaps a little close together for the latches, but I think they’ll be ok.
- The 8255’s capacitor is located under the footprint for the 40-way DIP. It can go on either side of the board.
- As you can see, I’ve used DIP sockets throughout.
Amstrad CPC Interface
The design notes and BOM for the target interfaces can be found in Part 3. There are more components, but building should again be relatively straight forward. Again getting the Z80 PIO is probably the most difficult part of the whole thing.
I figured that given the technology of the time, I’d need a NMOS part that can go to at least 4MHz. I initially went with using a GS Z8420B, which I thought was the 4MHz part, but I was mistaken. With a GS part the speeds go as follows (ref SGS Z80 Family Databook):
- Z8420B – 2.5MHz
- Z8420AB – 4MHz
- Z8420BB – 6MHz
So I need the AB or BB version. The Zilog parts will be Z842004 or Z842006 for the NMOS variants. It will be Z84C2006, and so on, for the CMOS versions.
After a first build using a straight-through, 50-way edge connector socket, I figured there probably wasn’t enough spacing between the edge connector and the Z80 PIO, so I doubt it would fit as a vertical card. Consequently I built a second card using a right-angled edge connector and will have the interface sitting horizontally. Assuming I actually find a CPC to try it with of course (as I don’t have one myself).
I added a switch for the enable function, but then realised that the switch is obscuring the on/off indication. With hindsight, I suspect pin headers and a jumper would be more useful here as I don’t expect this to be used a lot? I could be wrong.
ZX Spectrum Interface
The majority of this is the same as the Amstrad version, and again design details and BOM can be found in Part 3.
The key difference, naturally (apart from one less chip), is the edge connector itself. The ZX Spectrum requires a keyed 56-way connector, with both ends cut off. Really – it has to have connectors flush with the ends of the connector.
The typical way to obtain one of these seems to be to buy a standard 56-way connector, remove the pins from the 5th slot and cut off the edges to make them flush with the connectors.
Then the vacated slot needs filling with something to act as the positioning key. There is a 3D printed design here: https://www.thingiverse.com/thing:6556638 which I tried but didn’t seem to stay in very well. Well, for me, when I plugged it into a Spectrum, on removing the key was left behind. I guess it would need gluing in place.
Alternatively, I had more luck with the parts I cut off the edge connector – just cutting them down and pushing them into place, being careful not to let them force the edge connector to splay out.
Once again I started with straight through connectors but that is unlikely to fit on anything other than an original rubber-keyed Spectrum, and even then I’m not convinced it would be secure, so I also rebuilt this one with a right-angled connector too.
Link Cable
The pinouts for the cable have to reflect the original and from the information and as noted in Part 1, and from the photos on the CPC wiki, we can see that the two IDC sockets at each end of the cable have opposite pinouts – i.e. pins 1-16 at one end are wired to pins 16-1 at the other.
The target connection has to be made to the top connector on the PC card for the information I have about the PDS to make sense. Some of the connections on the second connector are reversed, so I don’t know how that works.
Next Steps
I can do some basic electrical connectivity tests, but at present: I don’t have an ISA PC; I don’t have an Amstrad CPC; and right at this point in time I don’t have a working machine among my ZX Spectrums.
The latter I’m working on. I do want to get at least one of them up and running, so that side might be solvable in a basic capacity shortly. I have verified the GND and 5V connections on the PCB with an actual edge connector though.
The other two might be a bit more problematic.
But there is some good news. The Retro Collective reached out to Andy Glaister about recreating the designs and received the response: “You absolutely have my permission to reproduce the boards, the designs and the software. I will see if I can dig up stuff to help. It would be good to see all the code again.”
This means I can open up the GitHub repository once I gain a little confidence the boards have a fighting chance of functioning.
Kevin
#amstradCpc #pcb #pds #programmersDevelopmentSystem #zxSpectrum -
PDS – the Programmers Development System – Part 4
This series of posts looks at the Programmers Development System (PDS).
- 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.
This part goes through the build of the three boards I have so far.
PC Interface
The design information and BOM can be found in Part 2. Building the card is relatively straight forward, being mostly DIP sockets, capacitors and connectors. Getting hold of an Intel 8255 might be a little tricky, but they do exist. I’ve ended up with a D8255A, rather than the more typical P8255A, which I think might be an “industrial” version? I’m not sure, information about it doesn’t seem very easy to find.
I’ve got hold of some latching IDE connectors, which are very similar to those used with the original as far as I can see.
Some notes and observations at this stage:
- The connectors are perhaps a little close together for the latches, but I think they’ll be ok.
- The 8255’s capacitor is located under the footprint for the 40-way DIP. It can go on either side of the board.
- As you can see, I’ve used DIP sockets throughout.
Amstrad CPC Interface
The design notes and BOM for the target interfaces can be found in Part 3. There are more components, but building should again be relatively straight forward. Again getting the Z80 PIO is probably the most difficult part of the whole thing.
I figured that given the technology of the time, I’d need a NMOS part that can go to at least 4MHz. I initially went with using a GS Z8420B, which I thought was the 4MHz part, but I was mistaken. With a GS part the speeds go as follows (ref SGS Z80 Family Databook):
- Z8420B – 2.5MHz
- Z8420AB – 4MHz
- Z8420BB – 6MHz
So I need the AB or BB version. The Zilog parts will be Z842004 or Z842006 for the NMOS variants. It will be Z84C2006, and so on, for the CMOS versions.
After a first build using a straight-through, 50-way edge connector socket, I figured there probably wasn’t enough spacing between the edge connector and the Z80 PIO, so I doubt it would fit as a vertical card. Consequently I built a second card using a right-angled edge connector and will have the interface sitting horizontally. Assuming I actually find a CPC to try it with of course (as I don’t have one myself).
I added a switch for the enable function, but then realised that the switch is obscuring the on/off indication. With hindsight, I suspect pin headers and a jumper would be more useful here as I don’t expect this to be used a lot? I could be wrong.
ZX Spectrum Interface
The majority of this is the same as the Amstrad version, and again design details and BOM can be found in Part 3.
The key difference, naturally (apart from one less chip), is the edge connector itself. The ZX Spectrum requires a keyed 56-way connector, with both ends cut off. Really – it has to have connectors flush with the ends of the connector.
The typical way to obtain one of these seems to be to buy a standard 56-way connector, remove the pins from the 5th slot and cut off the edges to make them flush with the connectors.
Then the vacated slot needs filling with something to act as the positioning key. There is a 3D printed design here: https://www.thingiverse.com/thing:6556638 which I tried but didn’t seem to stay in very well. Well, for me, when I plugged it into a Spectrum, on removing the key was left behind. I guess it would need gluing in place.
Alternatively, I had more luck with the parts I cut off the edge connector – just cutting them down and pushing them into place, being careful not to let them force the edge connector to splay out.
Once again I started with straight through connectors but that is unlikely to fit on anything other than an original rubber-keyed Spectrum, and even then I’m not convinced it would be secure, so I also rebuilt this one with a right-angled connector too.
Link Cable
The pinouts for the cable have to reflect the original and from the information and as noted in Part 1, and from the photos on the CPC wiki, we can see that the two IDC sockets at each end of the cable have opposite pinouts – i.e. pins 1-16 at one end are wired to pins 16-1 at the other.
The target connection has to be made to the top connector on the PC card for the information I have about the PDS to make sense. Some of the connections on the second connector are reversed, so I don’t know how that works.
Next Steps
I can do some basic electrical connectivity tests, but at present: I don’t have an ISA PC; I don’t have an Amstrad CPC; and right at this point in time I don’t have a working machine among my ZX Spectrums.
The latter I’m working on. I do want to get at least one of them up and running, so that side might be solvable in a basic capacity shortly. I have verified the GND and 5V connections on the PCB with an actual edge connector though.
The other two might be a bit more problematic.
But there is some good news. The Retro Collective reached out to Andy Glaister about recreating the designs and received the response: “You absolutely have my permission to reproduce the boards, the designs and the software. I will see if I can dig up stuff to help. It would be good to see all the code again.”
This means I can open up the GitHub repository once I gain a little confidence the boards have a fighting chance of functioning.
Kevin
#amstradCpc #pcb #pds #programmersDevelopmentSystem #zxSpectrum -
PDS – the Programmers Development System – Part 4
This series of posts looks at the Programmers Development System (PDS).
- 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.
This part goes through the build of the three boards I have so far.
PC Interface
The design information and BOM can be found in Part 2. Building the card is relatively straight forward, being mostly DIP sockets, capacitors and connectors. Getting hold of an Intel 8255 might be a little tricky, but they do exist. I’ve ended up with a D8255A, rather than the more typical P8255A, which I think might be an “industrial” version? I’m not sure, information about it doesn’t seem very easy to find.
I’ve got hold of some latching IDE connectors, which are very similar to those used with the original as far as I can see.
Some notes and observations at this stage:
- The connectors are perhaps a little close together for the latches, but I think they’ll be ok.
- The 8255’s capacitor is located under the footprint for the 40-way DIP. It can go on either side of the board.
- As you can see, I’ve used DIP sockets throughout.
Amstrad CPC Interface
The design notes and BOM for the target interfaces can be found in Part 3. There are more components, but building should again be relatively straight forward. Again getting the Z80 PIO is probably the most difficult part of the whole thing.
I figured that given the technology of the time, I’d need a NMOS part that can go to at least 4MHz. I initially went with using a GS Z8420B, which I thought was the 4MHz part, but I was mistaken. With a GS part the speeds go as follows (ref SGS Z80 Family Databook):
- Z8420B – 2.5MHz
- Z8420AB – 4MHz
- Z8420BB – 6MHz
So I need the AB or BB version. The Zilog parts will be Z842004 or Z842006 for the NMOS variants. It will be Z84C2006, and so on, for the CMOS versions.
After a first build using a straight-through, 50-way edge connector socket, I figured there probably wasn’t enough spacing between the edge connector and the Z80 PIO, so I doubt it would fit as a vertical card. Consequently I built a second card using a right-angled edge connector and will have the interface sitting horizontally. Assuming I actually find a CPC to try it with of course (as I don’t have one myself).
I added a switch for the enable function, but then realised that the switch is obscuring the on/off indication. With hindsight, I suspect pin headers and a jumper would be more useful here as I don’t expect this to be used a lot? I could be wrong.
ZX Spectrum Interface
The majority of this is the same as the Amstrad version, and again design details and BOM can be found in Part 3.
The key difference, naturally (apart from one less chip), is the edge connector itself. The ZX Spectrum requires a keyed 56-way connector, with both ends cut off. Really – it has to have connectors flush with the ends of the connector.
The typical way to obtain one of these seems to be to buy a standard 56-way connector, remove the pins from the 5th slot and cut off the edges to make them flush with the connectors.
Then the vacated slot needs filling with something to act as the positioning key. There is a 3D printed design here: https://www.thingiverse.com/thing:6556638 which I tried but didn’t seem to stay in very well. Well, for me, when I plugged it into a Spectrum, on removing the key was left behind. I guess it would need gluing in place.
Alternatively, I had more luck with the parts I cut off the edge connector – just cutting them down and pushing them into place, being careful not to let them force the edge connector to splay out.
Once again I started with straight through connectors but that is unlikely to fit on anything other than an original rubber-keyed Spectrum, and even then I’m not convinced it would be secure, so I also rebuilt this one with a right-angled connector too.
Link Cable
The pinouts for the cable have to reflect the original and from the information and as noted in Part 1, and from the photos on the CPC wiki, we can see that the two IDC sockets at each end of the cable have opposite pinouts – i.e. pins 1-16 at one end are wired to pins 16-1 at the other.
The target connection has to be made to the top connector on the PC card for the information I have about the PDS to make sense. Some of the connections on the second connector are reversed, so I don’t know how that works.
Next Steps
I can do some basic electrical connectivity tests, but at present: I don’t have an ISA PC; I don’t have an Amstrad CPC; and right at this point in time I don’t have a working machine among my ZX Spectrums.
The latter I’m working on. I do want to get at least one of them up and running, so that side might be solvable in a basic capacity shortly. I have verified the GND and 5V connections on the PCB with an actual edge connector though.
The other two might be a bit more problematic.
But there is some good news. The Retro Collective reached out to Andy Glaister about recreating the designs and received the response: “You absolutely have my permission to reproduce the boards, the designs and the software. I will see if I can dig up stuff to help. It would be good to see all the code again.”
This means I can open up the GitHub repository once I gain a little confidence the boards have a fighting chance of functioning.
Kevin
#amstradCpc #pcb #pds #programmersDevelopmentSystem #zxSpectrum -
PDS – the Programmers Development System – Part 4
This series of posts looks at the Programmers Development System (PDS).
- 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
This part goes through the build of the three boards I have so far.
PC Interface
The design information and BOM can be found in Part 2. Building the card is relatively straight forward, being mostly DIP sockets, capacitors and connectors. Getting hold of an Intel 8255 might be a little tricky, but they do exist. I’ve ended up with a D8255A, rather than the more typical P8255A, which I think might be an “industrial” version? I’m not sure, information about it doesn’t seem very easy to find.
I’ve got hold of some latching IDE connectors, which are very similar to those used with the original as far as I can see.
Some notes and observations at this stage:
- The connectors are perhaps a little close together for the latches, but I think they’ll be ok.
- The 8255’s capacitor is located under the footprint for the 40-way DIP. It can go on either side of the board.
- As you can see, I’ve used DIP sockets throughout.
Amstrad CPC Interface
The design notes and BOM for the target interfaces can be found in Part 3. There are more components, but building should again be relatively straight forward. Again getting the Z80 PIO is probably the most difficult part of the whole thing.
I figured that given the technology of the time, I’d need a NMOS part that can go to at least 4MHz. I initially went with using a GS Z8420B, which I thought was the 4MHz part, but I was mistaken. With a GS part the speeds go as follows (ref SGS Z80 Family Databook):
- Z8420B – 2.5MHz
- Z8420AB – 4MHz
- Z8420BB – 6MHz
So I need the AB or BB version. The Zilog parts will be Z842004 or Z842006 for the NMOS variants. It will be Z84C2006, and so on, for the CMOS versions.
After a first build using a straight-through, 50-way edge connector socket, I figured there probably wasn’t enough spacing between the edge connector and the Z80 PIO, so I doubt it would fit as a vertical card. Consequently I built a second card using a right-angled edge connector and will have the interface sitting horizontally. Assuming I actually find a CPC to try it with of course (as I don’t have one myself).
I added a switch for the enable function, but then realised that the switch is obscuring the on/off indication. With hindsight, I suspect pin headers and a jumper would be more useful here as I don’t expect this to be used a lot? I could be wrong.
ZX Spectrum Interface
The majority of this is the same as the Amstrad version, and again design details and BOM can be found in Part 3.
The key difference, naturally (apart from one less chip), is the edge connector itself. The ZX Spectrum requires a keyed 56-way connector, with both ends cut off. Really – it has to have connectors flush with the ends of the connector.
The typical way to obtain one of these seems to be to buy a standard 56-way connector, remove the pins from the 5th slot and cut off the edges to make them flush with the connectors.
Then the vacated slot needs filling with something to act as the positioning key. There is a 3D printed design here: https://www.thingiverse.com/thing:6556638 which I tried but didn’t seem to stay in very well. Well, for me, when I plugged it into a Spectrum, on removing the key was left behind. I guess it would need gluing in place.
Alternatively, I had more luck with the parts I cut off the edge connector – just cutting them down and pushing them into place, being careful not to let them force the edge connector to splay out.
Once again I started with straight through connectors but that is unlikely to fit on anything other than an original rubber-keyed Spectrum, and even then I’m not convinced it would be secure, so I also rebuilt this one with a right-angled connector too.
Link Cable
The pinouts for the cable have to reflect the original and from the information and as noted in Part 1, and from the photos on the CPC wiki, we can see that the two IDC sockets at each end of the cable have opposite pinouts – i.e. pins 1-16 at one end are wired to pins 16-1 at the other.
The target connection has to be made to the top connector on the PC card for the information I have about the PDS to make sense. Some of the connections on the second connector are reversed, so I don’t know how that works.
Errata
PC Card:
- I’m still deciding on the best location for the connections and size of the card. But I know it fits in an ISA PC!
ZX Spectrum Interface:
- I’ve realised the enable switch is the opposite sense to the original board.
- If I want a vertical card, then the components need to be further away from the edge connector (or possibly on the back).
Amstrad Interface:
- Same issues as the Spectrum card, plus I can’t actually test it 🙂
Next Steps
I can do some basic electrical connectivity tests, but at present: I don’t have an ISA PC; I don’t have an Amstrad CPC; and right at this point in time I don’t have a working machine among my ZX Spectrums.
The latter I’m working on. I do want to get at least one of them up and running, so that side might be solvable in a basic capacity shortly. I have verified the GND and 5V connections on the PCB with an actual edge connector though.
The other two might be a bit more problematic.
But there is some good news. The Retro Collective reached out to Andy Glaister about recreating the designs and received the response: “You absolutely have my permission to reproduce the boards, the designs and the software. I will see if I can dig up stuff to help. It would be good to see all the code again.”
This means I can now open up the GitHub repository.
Update:
- A ZX Spectrum will boot with Spectrum target card present, so that is good!
- Testing the Spectrum card with my RC2014 (via this add-on card, and with the clock dropped down to 2.5MHz) and then connecting a scope to the OUTPUT control pin (target to PC), I can see the level changing when I do the following:
; Configure Mode 3, B6,7 as OUTPUT
OUT 127,255
OUT 127,63
; Set OUTPUT HIGH
OUT 63,128
; Set OUTPUT LOW
OUT 63,0This gives me some confidence that the Z80 PIO does in fact work on the Spectrum board.
Kevin
#amstradCpc #pcb #pds #programmersDevelopmentSystem #zxSpectrum -
PDS – the Programmers Development System – Part 3
This series of posts looks at the Programmers Development System (PDS).
- 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
ZX Spectrum Interface
Here are the remade schematic and PCB for the ZX Spectrum target interface.
This is simply reproducing the schematic found on the CPC wiki, but now in KiCAD. There are a few extras, such as capacitors for the ICs and a pull-up resistor for the unused inverter. The equivalent PCB is shown below.
The PCB uses the ZX Spectrum Edge connector symbol and footprint from https://github.com/alvaroalea/8bits_kicad_libraries.
The jumpers in the top centre of the board use a custom footprint that mirrors the original PCB, but they can easily be replaced with standard pin-headers or even just a simple wire link.
Bill of Materials
- PDS Remake ZX Spectrum PCB
- Z8420 Z80 PIO (NMOS is currently assumed given it has to work with a Z80A at 3.5MHz)
- 74LS245 octal bus transciever
- 74LS04 hex inverter
- Resistors: 1K, 4K7, 10K
- Capacitors: 3x 100nF
- 6x6x6mm tactile button switch
- SPDT slider switch 2.54mm pitch OR 2.54mm header pins and jumper
- 16-way 2×8 shrouded pin header socket
- ZX Spectrum edge connector (straight)
I’m using a standard/common 56-pin edge connector socket which will have to be “doctored” to turn it into a ZX Spectrum compatible socket. There are notes on how to do this online, but I’ve not experimented yet.
Amstrad CPC Interface
This is very similar to the ZX Spectrum, but the address decoding gives it a different address (see part 1 for details).
The PCB is using a custom 2×25-way edge connector taken from the ZX Spectrum one used previously. It also uses the same custom jumpers as the ZX Spectrum version.
Bill of Materials
- Z8420 Z80 PIO (NMOS is currently assumed given it has to work with a Z80A at 3.5MHz)
- 74LS245 octal bus transciever
- 74LS04 hex inverter
- 74LS032 quad 2-input OR gate
- Resistors: 1K, 4x 4K7, 10K, 1M
- Capacitors: 4x 100nF
- 6x6x6mm tactile button switch
- SPDT slider switch 2.54mm pitch OR 2.54mm header pins and jumper
- 16-way 2×8 shrouded pin header socket
- 50-pin (2×25) edge connector (straight)
I think the edge connector will be a standard 2×25 way, 2.54mm pitch, edge connector socket that will look something like this:
But someone who knows about the Amstrad CPC will have to confirm this is the right one!
Conclusion
These boards come with a HUGE CAVEAT: they are completely untested and in the case of the Amstrad CPC version, a whole pile of ignorance, as I know effectively nothing about the machines.
I think I’ve got the edge connector in the correct orientation for both, but that is still to be verified.
I’ll probably build the spectrum version, but there is little reason for me to build the Amstrad one unless I can find a machine to try it on!
For now, these are just documenting the current state of play with remaking these boards.
Kevin
#amstradCpc #pds #programmersDevelopmentSystem #z80Pio #zxSpectrum -
PDS – the Programmers Development System – Part 3
This series of posts looks at the Programmers Development System (PDS).
- 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
ZX Spectrum Interface
Here are the remade schematic and PCB for the ZX Spectrum target interface.
This is simply reproducing the schematic found on the CPC wiki, but now in KiCAD. There are a few extras, such as capacitors for the ICs and a pull-up resistor for the unused inverter. The equivalent PCB is shown below.
The PCB uses the ZX Spectrum Edge connector symbol and footprint from https://github.com/alvaroalea/8bits_kicad_libraries.
The jumpers in the top centre of the board use a custom footprint that mirrors the original PCB, but they can easily be replaced with standard pin-headers or even just a simple wire link.
Bill of Materials
- PDS Remake ZX Spectrum PCB
- Z8420 Z80 PIO (NMOS is currently assumed given it has to work with a Z80A at 3.5MHz)
- 74LS245 octal bus transciever
- 74LS04 hex inverter
- Resistors: 1K, 4K7, 10K
- Capacitors: 3x 100nF
- 6x6x6mm tactile button switch
- SPDT slider switch 2.54mm pitch OR 2.54mm header pins and jumper
- 16-way 2×8 shrouded pin header socket
- ZX Spectrum edge connector (straight)
I’m using a standard/common 56-pin edge connector socket which will have to be “doctored” to turn it into a ZX Spectrum compatible socket. There are notes on how to do this online, but I’ve not experimented yet.
Amstrad CPC Interface
This is very similar to the ZX Spectrum, but the address decoding gives it a different address (see part 1 for details).
The PCB is using a custom 2×25-way edge connector taken from the ZX Spectrum one used previously. It also uses the same custom jumpers as the ZX Spectrum version.
Bill of Materials
- Z8420 Z80 PIO (NMOS is currently assumed given it has to work with a Z80A at 3.5MHz)
- 74LS245 octal bus transciever
- 74LS04 hex inverter
- 74LS032 quad 2-input OR gate
- Resistors: 1K, 4x 4K7, 10K, 1M
- Capacitors: 4x 100nF
- 6x6x6mm tactile button switch
- SPDT slider switch 2.54mm pitch OR 2.54mm header pins and jumper
- 16-way 2×8 shrouded pin header socket
- 50-pin (2×25) edge connector (straight)
I think the edge connector will be a standard 2×25 way, 2.54mm pitch, edge connector socket that will look something like this:
But someone who knows about the Amstrad CPC will have to confirm this is the right one!
Conclusion
These boards come with a HUGE CAVEAT: they are completely untested and in the case of the Amstrad CPC version, a whole pile of ignorance, as I know effectively nothing about the machines.
I think I’ve got the edge connector in the correct orientation for both, but that is still to be verified.
I’ll probably build the spectrum version, but there is little reason for me to build the Amstrad one unless I can find a machine to try it on!
For now, these are just documenting the current state of play with remaking these boards.
All files are currently in a private GitHub directory as I’m not sure what the licensing issues are going to be. But if you’d like to collaborate with me on getting them built and tested, drop me an email and we can chat.
Kevin
#amstradCpc #pds #programmersDevelopmentSystem #z80Pio #zxSpectrum -
PDS – the Programmers Development System – Part 3
This series of posts looks at the Programmers Development System (PDS).
- 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
ZX Spectrum Interface
Here are the remade schematic and PCB for the ZX Spectrum target interface.
This is simply reproducing the schematic found on the CPC wiki, but now in KiCAD. There are a few extras, such as capacitors for the ICs and a pull-up resistor for the unused inverter. The equivalent PCB is shown below.
The PCB uses the ZX Spectrum Edge connector symbol and footprint from https://github.com/alvaroalea/8bits_kicad_libraries.
The jumpers in the top centre of the board use a custom footprint that mirrors the original PCB, but they can easily be replaced with standard pin-headers or even just a simple wire link.
Bill of Materials
- PDS Remake ZX Spectrum PCB
- Z8420 Z80 PIO (NMOS is currently assumed given it has to work with a Z80A at 3.5MHz)
- 74LS245 octal bus transciever
- 74LS04 hex inverter
- Resistors: 1K, 4K7, 10K
- Capacitors: 3x 100nF
- 6x6x6mm tactile button switch
- SPDT slider switch 2.54mm pitch OR 2.54mm header pins and jumper
- 16-way 2×8 shrouded pin header socket
- ZX Spectrum edge connector (straight)
I’m using a standard/common 56-pin edge connector socket which will have to be “doctored” to turn it into a ZX Spectrum compatible socket. There are notes on how to do this online, but I’ve not experimented yet.
Amstrad CPC Interface
This is very similar to the ZX Spectrum, but the address decoding gives it a different address (see part 1 for details).
The PCB is using a custom 2×25-way edge connector taken from the ZX Spectrum one used previously. It also uses the same custom jumpers as the ZX Spectrum version.
Bill of Materials
- Z8420 Z80 PIO (NMOS is currently assumed given it has to work with a Z80A at 3.5MHz)
- 74LS245 octal bus transciever
- 74LS04 hex inverter
- 74LS032 quad 2-input OR gate
- Resistors: 1K, 4x 4K7, 10K, 1M
- Capacitors: 4x 100nF
- 6x6x6mm tactile button switch
- SPDT slider switch 2.54mm pitch OR 2.54mm header pins and jumper
- 16-way 2×8 shrouded pin header socket
- 50-pin (2×25) edge connector (straight)
I think the edge connector will be a standard 2×25 way, 2.54mm pitch, edge connector socket that will look something like this:
But someone who knows about the Amstrad CPC will have to confirm this is the right one!
Conclusion
These boards come with a HUGE CAVEAT: they are completely untested and in the case of the Amstrad CPC version, a whole pile of ignorance, as I know effectively nothing about the machines.
I think I’ve got the edge connector in the correct orientation for both, but that is still to be verified.
I’ll probably build the spectrum version, but there is little reason for me to build the Amstrad one unless I can find a machine to try it on!
For now, these are just documenting the current state of play with remaking these boards.
All files are currently in a private GitHub directory as I’m not sure what the licensing issues are going to be. But if you’d like to collaborate with me on getting them built and tested, drop me an email and we can chat.
Kevin
#amstradCpc #pds #programmersDevelopmentSystem #z80Pio #zxSpectrum -
PDS – the Programmers Development System – Part 3
This series of posts looks at the Programmers Development System (PDS).
- 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
ZX Spectrum Interface
Here are the remade schematic and PCB for the ZX Spectrum target interface.
This is simply reproducing the schematic found on the CPC wiki, but now in KiCAD. There are a few extras, such as capacitors for the ICs and a pull-up resistor for the unused inverter. The equivalent PCB is shown below.
The PCB uses the ZX Spectrum Edge connector symbol and footprint from https://github.com/alvaroalea/8bits_kicad_libraries.
The jumpers in the top centre of the board use a custom footprint that mirrors the original PCB, but they can easily be replaced with standard pin-headers or even just a simple wire link.
Bill of Materials
- PDS Remake ZX Spectrum PCB
- Z8420 Z80 PIO (NMOS is currently assumed given it has to work with a Z80A at 3.5MHz)
- 74LS245 octal bus transciever
- 74LS04 hex inverter
- Resistors: 1K, 4K7, 10K
- Capacitors: 3x 100nF
- 6x6x6mm tactile button switch
- SPDT slider switch 2.54mm pitch OR 2.54mm header pins and jumper
- 16-way 2×8 shrouded pin header socket
- ZX Spectrum edge connector (straight)
I’m using a standard/common 56-pin edge connector socket which will have to be “doctored” to turn it into a ZX Spectrum compatible socket. There are notes on how to do this online, but I’ve not experimented yet.
Amstrad CPC Interface
This is very similar to the ZX Spectrum, but the address decoding gives it a different address (see part 1 for details).
The PCB is using a custom 2×25-way edge connector taken from the ZX Spectrum one used previously. It also uses the same custom jumpers as the ZX Spectrum version.
Bill of Materials
- Z8420 Z80 PIO (NMOS is currently assumed given it has to work with a Z80A at 3.5MHz)
- 74LS245 octal bus transciever
- 74LS04 hex inverter
- 74LS032 quad 2-input OR gate
- Resistors: 1K, 4x 4K7, 10K, 1M
- Capacitors: 4x 100nF
- 6x6x6mm tactile button switch
- SPDT slider switch 2.54mm pitch OR 2.54mm header pins and jumper
- 16-way 2×8 shrouded pin header socket
- 50-pin (2×25) edge connector (straight)
I think the edge connector will be a standard 2×25 way, 2.54mm pitch, edge connector socket that will look something like this:
But someone who knows about the Amstrad CPC will have to confirm this is the right one!
Conclusion
These boards come with a HUGE CAVEAT: they are completely untested and in the case of the Amstrad CPC version, a whole pile of ignorance, as I know effectively nothing about the machines.
I think I’ve got the edge connector in the correct orientation for both, but that is still to be verified.
I’ll probably build the spectrum version, but there is little reason for me to build the Amstrad one unless I can find a machine to try it on!
For now, these are just documenting the current state of play with remaking these boards.
Kevin
#amstradCpc #pds #programmersDevelopmentSystem #z80Pio #zxSpectrum -
PDS – the Programmers Development System – Part 2
This series of posts looks at the Programmers Development System (PDS).
- 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
Having now got a bit of an idea of how the PDS appears to work in my previous post (PDS – the Programmers Development System) I’m now taking another look at the PC interface and starting to think about the possibility of recreating the system.
The PC Interface
Having decided I couldn’t rely on the schematic on the CPC wiki, I’ve taken the printout-versions of the PCB traces and started tracing them through to see what is really going on. It was greatly helped by the PCB view that can be found here: https://lemmings.info/pds-programmers-development-system/
Of course, I am assuming here that the remade PC card does actually work.
It turns out the ISA to Intel 8255 part was fine, including the address decoding, but the three 8255 IO ports, through the octal line buffers, to the two PDS links are fundamentally missing some key links.
Essentially the three 74LS244s are configured for half in A->Y form and half in Y->A. The three IO ports (PORT A, B, C) are also split in half. This means that most of this circuit is working in 4-bit chunks.
The high level linkages are shown below.
So here we can see how the A halves of each of the 244s handles OUTPUT and the B halves handle INPUT. We can also see that U5 (sticking with the original schematic numbering for now) handles the control signals, U4 is D4-7 and U3 is D0-3. PORTC drives U5 and thus also handles all control signals.
We can also see that the data lines are now fully bidirectionally connected so that each can be connected to an OUTPUT or an INPUT depending on the state of the PC2 line. PORTB handles the OUTPUT and PORTA is the input.
The control signals are still mirrored as determined in the first part, but now we can see that some are OUTPUTs and some are INPUTs. The mappings from PC0-7 through to the link pins is shown below (note I’ve reverted to using the same PDS connector pin numbers as the ZX Spectrum schematic in the diagram above and table below).
PIODirectionLink 1 PinLink 2 PinPC0OUT313PC1OUT133PC2OUT1111PC3OUT99PC4IN515PC5IN155PC6IN7N/CPC7INN/C7There are two swapped pairs of connections, two common, and one unique to each.
As mentioned previously, the ZX Spectrum interface does not connect to pins 9,11,13,15 so that implies to me that it would not work out of link 2 without remapping in the software for the alternative pinout.
From working through the ZX Spectrum monitor code in part 1, we can infer the following functions:
- Pin 3 (OUT): PC to Target CLOCK
- Pin 5 (IN): Target to PC CLOCK/ACK
We can also note the following:
- Pin 11 (OUT): Direction based on PC2. HIGH = PC to Target; LOW = Target to PC
From this point I can now fully recreate the schematic and start to think about recreating the PCB.
The PC Hardware
One slight sticking point in remaking the PCB was getting useful dimensions for an XT era ISA card. Two useful references I found were:
- The ISA Spec can be found as part of the PC XT Technical Reference: https://bitsavers.org/pdf/ibm/pc/xt/6361459_PC_XT_Technical_Reference_Apr84.pdf
- Researched 8-bit ISA card dimensions: https://www.andavno.com/?p=87
The actual spec wasn’t massively useful to me. I don’t know if the ends of cards was slightly different in PC XT systems, but it doesn’t seem to match the photos of the PDS PC card. The second link was very well researched and complete however, so I went with that.
One compromise though was trying to keep the card within a 100x100mm footprint, so I’ve not extended completely to what I believe will be long enough to have an end plate.
The Schematic
The updated schematic is shown above. I’ve added a few things I’d expect to see on a modern design – additional 100nF capacitors (one for each IC), and a resistor network to pull up all unused inputs to the 74LS04.
I originally went with the ZX Spectrum version of the 16-way connector, but then when it came to assigning footprints, to get a right-angled IDC connector meant pin one was now in the wrong place, so I had to revert to the alternative pin numbering as per the original schematic.
The PCB
I’ve followed the original layout used on the PC card remake as far as possible, reasoning that the person who did this almost certainly knows a lot more about electronics than I do.
I’ve also tried to keep the connectors as close to the positions on the original as far as possible, whilst still keeping within the 100x100mm PCB total size.
One thing I wasn’t sure about was a GND fill. I initially created a fill zone, but then decided I’d follow the original lead and use explicit GND connections. If someone advises that a fill will be better then it is pretty trivial to add in.
Other points to note:
- A already mentioned I’ve kept this within the 100x100mm footprint. This leaves two unknowns: will it be tall enough to be useful; and will it extend to the edge of a PC case?
- The two connectors are roughly in the same horizontal position as the original card. They seem comparable to where the pins align with the edge connector anyway. An earlier iteration had them extending beyond the PCB, but I’ve redesigned it to mirror the original card.
- The dimensions are such that more of the PCB is off to the right compared to the photos of the original or the remade board I’ve seen.
- I’ve not been able to include mounting holes in any useful position whilst retaining the 100x100mm footprint.
The current dimensions of the above PCB are shown below.
This will do for now, but I think it is highly likely there will need to be some more physical adjustments at some point for this to be usable.
Conclusion
I believe I’ve got an accurate schematic for the board based on the photos available and I now have design for a candidate PCB. The problem is that I don’t know anything about what the software is expecting when it drives the Intel 8255 to work the PDS interface.
There is also the small matter of needing an ISA bus in a PC…
I’m hoping to get these boards published somewhere but right now, I’m not clear what the licensing issues would be. These boards are not available anymore, but at some point this was a company’s IPR.
For now, I’ll keep blogging observations and see what the interest is.
Next up will be some remake of the target PCBs.
Kevin
#intel8255 #ISA #pcXt #pds #programmersDevelopmentSystem -
PDS – the Programmers Development System – Part 2
This series of posts looks at the Programmers Development System (PDS).
- Part 1 – Introduction, background and some initial reverse engineering.
- Part 2 – A closer look at the PC ISA Interface card.
Having now got a bit of an idea of how the PDS appears to work in my previous post (PDS – the Programmers Development System) I’m now taking another look at the PC interface and starting to think about the possibility of recreating the system.
The PC Interface
Having decided I couldn’t rely on the schematic on the CPC wiki, I’ve taken the printout-versions of the PCB traces and started tracing them through to see what is really going on. It was greatly helped by the PCB view that can be found here: https://lemmings.info/pds-programmers-development-system/
Of course, I am assuming here that the remade PC card does actually work.
It turns out the ISA to Intel 8255 part was fine, including the address decoding, but the three 8255 IO ports, through the octal line buffers, to the two PDS links are fundamentally missing some key links.
Essentially the three 74LS244s are configured for half in A->Y form and half in Y->A. The three IO ports (PORT A, B, C) are also split in half. This means that most of this circuit is working in 4-bit chunks.
The high level linkages are shown below.
So here we can see how the A halves of each of the 244s handles OUTPUT and the B halves handle INPUT. We can also see that U5 (sticking with the original schematic numbering for now) handles the control signals, U4 is D4-7 and U3 is D0-3. PORTC drives U5 and thus also handles all control signals.
We can also see that the data lines are now fully bidirectionally connected so that each can be connected to an OUTPUT or an INPUT depending on the state of the PC2 line. PORTB handles the OUTPUT and PORTA is the input.
The control signals are still mirrored as determined in the first part, but now we can see that some are OUTPUTs and some are INPUTs. The mappings from PC0-7 through to the link pins is shown below (note I’ve reverted to using the same PDS connector pin numbers as the ZX Spectrum schematic in the diagram above and table below).
PIODirectionLink 1 PinLink 2 PinPC0OUT313PC1OUT133PC2OUT1111PC3OUT99PC4IN515PC5IN155PC6IN7N/CPC7INN/C7There are two swapped pairs of connections, two common, and one unique to each.
As mentioned previously, the ZX Spectrum interface does not connect to pins 9,11,13,15 so that implies to me that it would not work out of link 2 without remapping in the software for the alternative pinout.
From working through the ZX Spectrum monitor code in part 1, we can infer the following functions:
- Pin 3 (OUT): PC to Target CLOCK
- Pin 5 (IN): Target to PC CLOCK/ACK
We can also note the following:
- Pin 11 (OUT): Direction based on PC2. HIGH = PC to Target; LOW = Target to PC
From this point I can now fully recreate the schematic and start to think about recreating the PCB.
The PC Hardware
One slight sticking point in remaking the PCB was getting useful dimensions for an XT era ISA card. Two useful references I found were:
- The ISA Spec can be found as part of the PC XT Technical Reference: https://bitsavers.org/pdf/ibm/pc/xt/6361459_PC_XT_Technical_Reference_Apr84.pdf
- Researched 8-bit ISA card dimensions: https://www.andavno.com/?p=87
The actual spec wasn’t massively useful to me. I don’t know if the ends of cards was slightly different in PC XT systems, but it doesn’t seem to match the photos of the PDS PC card. The second link was very well researched and complete however, so I went with that.
One compromise though was trying to keep the card within a 100x100mm footprint, so I’ve not extended completely to what I believe will be long enough to have an end plate.
The Schematic
The updated schematic is shown above. I’ve added a few things I’d expect to see on a modern design – additional 100nF capacitors (one for each IC), and a resistor network to pull up all unused inputs to the 74LS04.
I originally went with the ZX Spectrum version of the 16-way connector, but then when it came to assigning footprints, to get a right-angled IDC connector meant pin one was now in the wrong place, so I had to revert to the alternative pin numbering as per the original schematic.
The PCB
I’ve followed the original layout used on the PC card remake as far as possible, reasoning that the person who did this almost certainly knows a lot more about electronics than I do.
One thing I wasn’t sure about was a GND fill. I initially created a fill zone, but then decided I’d follow the original lead and use explicit GND connections. If someone advises that a fill will be better then it is pretty trivial to add in.
Other points to note:
- A already mentioned I’ve kept this within the 100x100mm footprint. This leaves two unknowns: will it be tall enough to be useful; and will it extend to the edge of a PC case?
- The two connectors extend beyond the edge of the PCB, so they hopefully will be available at the edge of a PC.
- The dimensions are such that more of the PCB is off to the right compared to the photos of the remade board I’ve seen.
This will do for now, but I think it is highly likely there will need to be some physical adjustments for this to be usable.
Conclusion
I believe I’ve got an accurate schematic for the board based on the photos available and I now have design for a candidate PCB. The problem is that I don’t know anything about what the software is expecting when it drives the Intel 8255 to work the PDS interface.
There is also the small matter of needing an ISA bus in a PC…
I’m hoping to get these boards published somewhere but right now, I’m not clear what the licensing issues would be. These boards are not available anymore, but at some point this was a company’s IPR.
For now, I’ll keep blogging observations and see what the interest is.
Next up will be some remake of the target PCBs.
Kevin
#intel8255 #ISA #pcXt #pds #programmersDevelopmentSystem -
PDS – the Programmers Development System – Part 2
This series of posts looks at the Programmers Development System (PDS).
- Part 1 – Introduction, background and some initial reverse engineering.
- Part 2 – A closer look at the PC ISA Interface card.
Having now got a bit of an idea of how the PDS appears to work in my previous post (PDS – the Programmers Development System) I’m now taking another look at the PC interface and starting to think about the possibility of recreating the system.
The PC Interface
Having decided I couldn’t rely on the schematic on the CPC wiki, I’ve taken the printout-versions of the PCB traces and started tracing them through to see what is really going on. It was greatly helped by the PCB view that can be found here: https://lemmings.info/pds-programmers-development-system/
Of course, I am assuming here that the remade PC card does actually work.
It turns out the ISA to Intel 8255 part was fine, including the address decoding, but the three 8255 IO ports, through the octal line buffers, to the two PDS links are fundamentally missing some key links.
Essentially the three 74LS244s are configured for half in A->Y form and half in Y->A. The three IO ports (PORT A, B, C) are also split in half. This means that most of this circuit is working in 4-bit chunks.
The high level linkages are shown below.
So here we can see how the A halves of each of the 244s handles OUTPUT and the B halves handle INPUT. We can also see that U5 (sticking with the original schematic numbering for now) handles the control signals, U4 is D4-7 and U3 is D0-3. PORTC drives U5 and thus also handles all control signals.
We can also see that the data lines are now fully bidirectionally connected so that each can be connected to an OUTPUT or an INPUT depending on the state of the PC2 line. PORTB handles the OUTPUT and PORTA is the input.
The control signals are still mirrored as determined in the first part, but now we can see that some are OUTPUTs and some are INPUTs. The mappings from PC0-7 through to the link pins is shown below (note I’ve reverted to using the same PDS connector pin numbers as the ZX Spectrum schematic in the diagram above and table below).
PIODirectionLink 1 PinLink 2 PinPC0OUT313PC1OUT133PC2OUT1111PC3OUT99PC4IN515PC5IN155PC6IN7N/CPC7INN/C7There are two swapped pairs of connections, two common, and one unique to each.
As mentioned previously, the ZX Spectrum interface does not connect to pins 9,11,13,15 so that implies to me that it would not work out of link 2 without remapping in the software for the alternative pinout.
From working through the ZX Spectrum monitor code in part 1, we can infer the following functions:
- Pin 3 (OUT): PC to Target CLOCK
- Pin 5 (IN): Target to PC CLOCK/ACK
We can also note the following:
- Pin 11 (OUT): Direction based on PC2. HIGH = PC to Target; LOW = Target to PC
From this point I can now fully recreate the schematic and start to think about recreating the PCB.
The PC Hardware
One slight sticking point in remaking the PCB was getting useful dimensions for an XT era ISA card. Two useful references I found were:
- The ISA Spec can be found as part of the PC XT Technical Reference: https://bitsavers.org/pdf/ibm/pc/xt/6361459_PC_XT_Technical_Reference_Apr84.pdf
- Researched 8-bit ISA card dimensions: https://www.andavno.com/?p=87
The actual spec wasn’t massively useful to me. I don’t know if the ends of cards was slightly different in PC XT systems, but it doesn’t seem to match the photos of the PDS PC card. The second link was very well researched and complete however, so I went with that.
One compromise though was trying to keep the card within a 100x100mm footprint, so I’ve not extended completely to what I believe will be long enough to have an end plate.
The Schematic
The updated schematic is shown above. I’ve added a few things I’d expect to see on a modern design – additional 100nF capacitors (one for each IC), and a resistor network to pull up all unused inputs to the 74LS04.
I originally went with the ZX Spectrum version of the 16-way connector, but then when it came to assigning footprints, to get a right-angled IDC connector meant pin one was now in the wrong place, so I had to revert to the alternative pin numbering as per the original schematic.
The PCB
I’ve followed the original layout used on the PC card remake as far as possible, reasoning that the person who did this almost certainly knows a lot more about electronics than I do.
One thing I wasn’t sure about was a GND fill. I initially created a fill zone, but then decided I’d follow the original lead and use explicit GND connections. If someone advises that a fill will be better then it is pretty trivial to add in.
Other points to note:
- A already mentioned I’ve kept this within the 100x100mm footprint. This leaves two unknowns: will it be tall enough to be useful; and will it extend to the edge of a PC case?
- The two connectors extend beyond the edge of the PCB, so they hopefully will be available at the edge of a PC.
- The dimensions are such that more of the PCB is off to the right compared to the photos of the remade board I’ve seen.
- I’ve not been able to include mounting holes in any useful position whilst retaining the 100x100mm footprint.
This will do for now, but I think it is highly likely there will need to be some physical adjustments for this to be usable.
Conclusion
I believe I’ve got an accurate schematic for the board based on the photos available and I now have design for a candidate PCB. The problem is that I don’t know anything about what the software is expecting when it drives the Intel 8255 to work the PDS interface.
There is also the small matter of needing an ISA bus in a PC…
I’m hoping to get these boards published somewhere but right now, I’m not clear what the licensing issues would be. These boards are not available anymore, but at some point this was a company’s IPR.
For now, I’ll keep blogging observations and see what the interest is.
Next up will be some remake of the target PCBs.
Kevin
#intel8255 #ISA #pcXt #pds #programmersDevelopmentSystem -
PDS – the Programmers Development System – Part 2
This series of posts looks at the Programmers Development System (PDS).
- Part 1 – Introduction, background and some initial reverse engineering.
- Part 2 – A closer look at the PC ISA Interface card.
Having now got a bit of an idea of how the PDS appears to work in my previous post (PDS – the Programmers Development System) I’m now taking another look at the PC interface and starting to think about the possibility of recreating the system.
The PC Interface
Having decided I couldn’t rely on the schematic on the CPC wiki, I’ve taken the printout-versions of the PCB traces and started tracing them through to see what is really going on. It was greatly helped by the PCB view that can be found here: https://lemmings.info/pds-programmers-development-system/
Of course, I am assuming here that the remade PC card does actually work.
It turns out the ISA to Intel 8255 part was fine, including the address decoding, but the three 8255 IO ports, through the octal line buffers, to the two PDS links are fundamentally missing some key links.
Essentially the three 74LS244s are configured for half in A->Y form and half in Y->A. The three IO ports (PORT A, B, C) are also split in half. This means that most of this circuit is working in 4-bit chunks.
The high level linkages are shown below.
So here we can see how the A halves of each of the 244s handles OUTPUT and the B halves handle INPUT. We can also see that U5 (sticking with the original schematic numbering for now) handles the control signals, U4 is D4-7 and U3 is D0-3. PORTC drives U5 and thus also handles all control signals.
We can also see that the data lines are now fully bidirectionally connected so that each can be connected to an OUTPUT or an INPUT depending on the state of the PC2 line. PORTB handles the OUTPUT and PORTA is the input.
The control signals are still mirrored as determined in the first part, but now we can see that some are OUTPUTs and some are INPUTs. The mappings from PC0-7 through to the link pins is shown below (note I’ve reverted to using the same PDS connector pin numbers as the ZX Spectrum schematic in the diagram above and table below).
PIODirectionLink 1 PinLink 2 PinPC0OUT313PC1OUT133PC2OUT1111PC3OUT99PC4IN515PC5IN155PC6IN7N/CPC7INN/C7There are two swapped pairs of connections, two common, and one unique to each.
As mentioned previously, the ZX Spectrum interface does not connect to pins 9,11,13,15 so that implies to me that it would not work out of link 2 without remapping in the software for the alternative pinout.
From working through the ZX Spectrum monitor code in part 1, we can infer the following functions:
- Pin 3 (OUT): PC to Target CLOCK
- Pin 5 (IN): Target to PC CLOCK/ACK
We can also note the following:
- Pin 11 (OUT): Direction based on PC2. HIGH = PC to Target; LOW = Target to PC
From this point I can now fully recreate the schematic and start to think about recreating the PCB.
The PC Hardware
One slight sticking point in remaking the PCB was getting useful dimensions for an XT era ISA card. Two useful references I found were:
- The ISA Spec can be found as part of the PC XT Technical Reference: https://bitsavers.org/pdf/ibm/pc/xt/6361459_PC_XT_Technical_Reference_Apr84.pdf
- Researched 8-bit ISA card dimensions: https://www.andavno.com/?p=87
The actual spec wasn’t massively useful to me. I don’t know if the ends of cards was slightly different in PC XT systems, but it doesn’t seem to match the photos of the PDS PC card. The second link was very well researched and complete however, so I went with that.
One compromise though was trying to keep the card within a 100x100mm footprint, so I’ve not extended completely to what I believe will be long enough to have an end plate.
The Schematic
The updated schematic is shown above. I’ve added a few things I’d expect to see on a modern design – additional 100nF capacitors (one for each IC), and a resistor network to pull up all unused inputs to the 74LS04.
I originally went with the ZX Spectrum version of the 16-way connector, but then when it came to assigning footprints, to get a right-angled IDC connector meant pin one was now in the wrong place, so I had to revert to the alternative pin numbering as per the original schematic.
The PCB
I’ve followed the original layout used on the PC card remake as far as possible, reasoning that the person who did this almost certainly knows a lot more about electronics than I do.
One thing I wasn’t sure about was a GND fill. I initially created a fill zone, but then decided I’d follow the original lead and use explicit GND connections. If someone advises that a fill will be better then it is pretty trivial to add in.
Other points to note:
- A already mentioned I’ve kept this within the 100x100mm footprint. This leaves two unknowns: will it be tall enough to be useful; and will it extend to the edge of a PC case?
- The two connectors extend beyond the edge of the PCB, so they hopefully will be available at the edge of a PC.
- The dimensions are such that more of the PCB is off to the right compared to the photos of the remade board I’ve seen.
This will do for now, but I think it is highly likely there will need to be some physical adjustments for this to be usable.
Conclusion
I believe I’ve got an accurate schematic for the board based on the photos available and I now have design for a candidate PCB. The problem is that I don’t know anything about what the software is expecting when it drives the Intel 8255 to work the PDS interface.
There is also the small matter of needing an ISA bus in a PC…
I’m hoping to get these boards published somewhere but right now, I’m not clear what the licensing issues would be. These boards are not available anymore, but at some point this was a company’s IPR.
For now, I’ll keep blogging observations and see what the interest is.
Next up will be some remake of the target PCBs.
Kevin
#intel8255 #ISA #pcXt #pds #programmersDevelopmentSystem -
PDS – the Programmers Development System – Part 2
This series of posts looks at the Programmers Development System (PDS).
- 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
Having now got a bit of an idea of how the PDS appears to work in my previous post (PDS – the Programmers Development System) I’m now taking another look at the PC interface and starting to think about the possibility of recreating the system.
The PC Interface
Having decided I couldn’t rely on the schematic on the CPC wiki, I’ve taken the printout-versions of the PCB traces and started tracing them through to see what is really going on. It was greatly helped by the PCB view that can be found here: https://lemmings.info/pds-programmers-development-system/
Of course, I am assuming here that the remade PC card does actually work.
It turns out the ISA to Intel 8255 part was fine, including the address decoding, but the three 8255 IO ports, through the octal line buffers, to the two PDS links are fundamentally missing some key links.
Essentially the three 74LS244s are configured for half in A->Y form and half in Y->A. The three IO ports (PORT A, B, C) are also split in half. This means that most of this circuit is working in 4-bit chunks.
The high level linkages are shown below.
So here we can see how the A halves of each of the 244s handles OUTPUT and the B halves handle INPUT. We can also see that U5 (sticking with the original schematic numbering for now) handles the control signals, U4 is D4-7 and U3 is D0-3. PORTC drives U5 and thus also handles all control signals.
We can also see that the data lines are now fully bidirectionally connected so that each can be connected to an OUTPUT or an INPUT depending on the state of the PC2 line. PORTB handles the OUTPUT and PORTA is the input.
The control signals are still mirrored as determined in the first part, but now we can see that some are OUTPUTs and some are INPUTs. The mappings from PC0-7 through to the link pins is shown below (note I’ve reverted to using the same PDS connector pin numbers as the ZX Spectrum schematic in the diagram above and table below).
PIODirectionLink 1 PinLink 2 PinPC0OUT313PC1OUT133PC2OUT1111PC3OUT99PC4IN515PC5IN155PC6IN7N/CPC7INN/C7There are two swapped pairs of connections, two common, and one unique to each.
As mentioned previously, the ZX Spectrum interface does not connect to pins 9,11,13,15 so that implies to me that it would not work out of link 2 without remapping in the software for the alternative pinout.
From working through the ZX Spectrum monitor code in part 1, we can infer the following functions:
- Pin 3 (OUT): PC to Target CLOCK
- Pin 5 (IN): Target to PC CLOCK/ACK
We can also note the following:
- Pin 11 (OUT): Direction based on PC2. HIGH = PC to Target; LOW = Target to PC
From this point I can now fully recreate the schematic and start to think about recreating the PCB.
The PC Hardware
One slight sticking point in remaking the PCB was getting useful dimensions for an XT era ISA card. Two useful references I found were:
- The ISA Spec can be found as part of the PC XT Technical Reference: https://bitsavers.org/pdf/ibm/pc/xt/6361459_PC_XT_Technical_Reference_Apr84.pdf
- Researched 8-bit ISA card dimensions: https://www.andavno.com/?p=87
The actual spec wasn’t massively useful to me. I don’t know if the ends of cards was slightly different in PC XT systems, but it doesn’t seem to match the photos of the PDS PC card. The second link was very well researched and complete however, so I went with that.
One compromise though was trying to keep the card within a 100x100mm footprint, so I’ve not extended completely to what I believe will be long enough to have an end plate.
The Schematic
The updated schematic is shown above. I’ve added a few things I’d expect to see on a modern design – additional 100nF capacitors (one for each IC), and a resistor network to pull up all unused inputs to the 74LS04.
I originally went with the ZX Spectrum version of the 16-way connector, but then when it came to assigning footprints, to get a right-angled IDC connector meant pin one was now in the wrong place, so I had to revert to the alternative pin numbering as per the original schematic.
The PCB
I’ve followed the original layout used on the PC card remake as far as possible, reasoning that the person who did this almost certainly knows a lot more about electronics than I do.
I’ve also tried to keep the connectors as close to the positions on the original as far as possible, whilst still keeping within the 100x100mm PCB total size.
One thing I wasn’t sure about was a GND fill. I initially created a fill zone, but then decided I’d follow the original lead and use explicit GND connections. If someone advises that a fill will be better then it is pretty trivial to add in.
Other points to note:
- A already mentioned I’ve kept this within the 100x100mm footprint. This leaves two unknowns: will it be tall enough to be useful; and will it extend to the edge of a PC case?
- The two connectors are roughly in the same horizontal position as the original card. They seem comparable to where the pins align with the edge connector anyway. An earlier iteration had them extending beyond the PCB, but I’ve redesigned it to mirror the original card.
- The dimensions are such that more of the PCB is off to the right compared to the photos of the original or the remade board I’ve seen.
- I’ve not been able to include mounting holes in any useful position whilst retaining the 100x100mm footprint.
The current dimensions of the above PCB are shown below.
This will do for now, but I think it is highly likely there will need to be some more physical adjustments at some point for this to be usable.
Conclusion
I believe I’ve got an accurate schematic for the board based on the photos available and I now have design for a candidate PCB. The problem is that I don’t know anything about what the software is expecting when it drives the Intel 8255 to work the PDS interface.
There is also the small matter of needing an ISA bus in a PC…
I’m hoping to get these boards published somewhere but right now, I’m not clear what the licensing issues would be. These boards are not available anymore, but at some point this was a company’s IPR.
For now, I’ll keep blogging observations and see what the interest is.
Next up will be some remake of the target PCBs.
Kevin
#intel8255 #ISA #pcXt #pds #programmersDevelopmentSystem -
PDS – the Programmers Development System
This series of posts looks at the Programmers Development System (PDS).
- 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
I was directed towards this recently – it is a means of developing for 8-bit computers using early PCs or an Atari ST developed by Andy Glaister. Information about it seems quite sparse online, the main references seem to be:
- https://www.cpcwiki.eu/index.php/PDS_development_system
- https://www.worldofsam.org/products/pds-development-system (largely a repeat of the above)
- https://trastero.speccy.org/cosas/JL/PDS/Introduccion.html (link via Internet Archive)
- https://lemmings.info/pds-programmers-development-system/ and https://lemmings.info/pds-recreating-the-system/
- It is also talked about and demonstrated here: https://youtu.be/S6DlSfEj0as?si=gEOmOA53eiqXRWc_&t=589
As far as I can tell the original system was developed in the 1980s and there have been two attempts at recreating it since, as listed above.
The original reimplementation is from the Spanish site and provides a schematic and Eagle files. The next link was an attempt at using these design files by importing into KiCAD and getting Gerber files built which seemed to be pretty successful.
I must admit that when I first heard about it, I wondered if it was the same one that Dean Belfield was using with his Tatung Einstein at the 2025 RetroFest, but having read a bit more about it, there are definitely similarities, but I’m not sure its the same. Details of Dean’s setup here:
- http://www.breakintoprogram.co.uk/computers/recreating-my-80s-dev-system-part-1
- https://github.com/breakintoprogram/einstein-ide
It uses a similar principle to the PDS, in that development is performed on the Tatung and then code is transferred across to the target system using a combination of hardware and code running on both sides.
Basic Operation
As I understand things, with the PDS there was an interface card for the PC which linked via a 16-wire IDC cable to another interface card for the target computer. There were versions for the ZX Spectrum, Amstrad CPC, C64 and MSX (and possibly others). I’m only really interested in the ZX Spectrum version.
The PC card is based around the Intel 8255 parallel IO chip sitting on an 8-bit ISA bus. The target interface is usually based around the Z80 PIO (Z84C20) interfacing to the bus of the host system. The PC card supports two target interfaces and both cards include some logic chips to handle addressing and the IO interface.
Details of the 16-way IO link seem very sparse and will probably have to be worked through and inferred from the source code that has been uncovered.
From what I can tell, most of the protocol handling is done in the code and the interfaces are essentially IO “passthroughs”. The target has to run some monitor code to react to PDS commands and interface with the memory as required, setting, reading, updating, and so on.
The CPC wiki seems to be the most complete source of information so far, and includes photos of the remade boards and schematics for the PC card and ZX Spectrum interface.
The PDS Link
The PDS link itself is via a 16-way IDC ribbon cable and 2×8 IDC connectors. Unfortunately I’ve not found a pin-out anywhere so far, but from various sources, this is what I know so far.
GND12DATA 0PC to Target Clock34DATA 1Target to PC Clock/Ack56DATA 2Unknown78DATA 3Not used910DATA 4Not used1112DATA 5Not used1314DATA 6Not used1516DATA 7This is using the pin numbering from the ZX Spectrum schematic.
Unfortunately the schematic labelling of the two PDS sockets for the PC card is backwards compared to the ZX Spectrum card. Pin 16 for the PC version is GND, but that is pin 1 for the ZX Spectrum version. It would also appear that the socket shroud is also reversed. This means that D0 is pin 15 for the PC and pin 2 for the Spectrum.
The CPC wiki has a photo of the cable used, showing how pins 1-16 are wired to pins 16-1:
The PC Card
The schematic for the PC card can be found on the CPC wiki here: https://www.cpcwiki.eu/index.php/PDS_development_system
Main Components required:
- Intel 8255 Programmable Peripheral Interface (PPI).
- 74LS138 – 3 to 8 line decoder (for the addressing).
- 3x 74LS244 – 8 channel non-inverting buffers.
- 74LS04 – Hex Inverter (only one inverter is used).
It probably goes without saying for this era technology, but everything is 5V TTL levels.
The Intel 8255 PPI
The Intel 8255 Programmable Peripheral Interface (PPI) device provides access to 3 bidirectional 8-bit IO ports. There is a good summary here.
From https://en.wikipedia.org/wiki/Intel_8255:
The 8255 gives a CPU or digital system access to programmable parallel I/O. The 8255 has 24 input/output pins. These are divided into three 8-bit ports (A, B, C). Port A and port B can be used as 8-bit input/output ports. Port C can be used as an 8-bit input/output port or as two 4-bit input/output ports or to produce handshake signals for ports A and B.
The three ports are further grouped as follows:
- Group A consisting of port A and upper part of port C.
- Group B consisting of port B and lower part of port C.
There are two address lines that are used to select one of four registers as follows:
A1A0Register00Port A01Port B10Port C11Control RegisterThe device is selected on the bus when CS is active. It also uses RD and WR to know if it is reading from or writing to the registers.
Things get a bit complicated pretty quickly, but there is a good summary of the various modes of operation on the Wikipedia page, and of course, a comprehensive datasheet.
PC PDS Interface
According to the schematic, this is how the three 8255 IO ports map onto the two PDS connections:
8255 IO PortPDS Connection74LS244 UsedEnabled byPORT A 0-3Link 2: Data 0-3IC 3B/PC2PORT A 4-7Link 1: Data 0-3IC 4B/PC2PORT B 0-3Link 1: Data 4-7IC 3APC2PORT B 4-7Link 2: Data 4-7IC 4APC2PORT C 0-3Link 1 and 2: ControlIC 5AAlways OnPORT C 4-7Link 1 and 2: ControlIC 5BAlways OnIt is also worth noting that the three 74LS244 buffers are enabled in different ways according to the state of PC2. Also, as the enable is active LOW, the inverter on PC2 generates a “NOT PC2” signal, which itself must be LOW to activate IC3A/IC4A – i.e. it is a “active on NOT NOT PC2” signal. PC2 appears to be used to decide which nibble of the data port should be active. It is also passed through to the link control pins (see below).
The 8 control lines map onto the two links in an interesting way. Note this is using “PC interface” pin numbering which as previously mentioned is different to the ZX Spectrum side.
Link 1 PinsLink 2 PinsPC0144PC1414PC266PC388PC4122PC5212PC610N/CPC7N/C10So we can see that PC2 and PC3 are common; that PC0/PC1, PC4/PC5 are swapped; and that PC6 is link 1 only; and PC7 is link 2 only. Recall PC2 appears to select which nibble is active.
When mapped onto the ZX Spectrum card, anything on pins 2,4,6,8 are mapped onto unused pins.
I must say I’m struggling to make sense of this. This seems to be implying that when data is written to one of the PPI IO PORTs, it is striped across both link 1 and 2. Surely it would make more sense to select one or the other and write all 8 data values in one go?
I did wonder if this was related to the different IO modes of the 8255, but on re-reading how the modes work, this still doesn’t make much sense to me.
Unfortunately there doesn’t appear to be any source code for the PC end of things to see what it is doing.
Ok, so finding a print of the traces for the PCB and overlaying them on a light box gives me the following:
I’ve highlighted the connection for D0. We can clearly see that on the PCB D0 for both links is connected, and not only that, it is connected to both input side 2A1 and output side 1Y4 on the /same/ IC. This would make sense for a bi-directional bus, but it is quite a long way from the schematic.
At this point I have to conclude that the schematic is just plain wrong so I’m leaving the PC card for now.
The ZX Spectrum Card
The spectrum side is based on the Z80 PIO (Z8420/Z84C20). There is also a schematic and PCB for that on the CPC wki, but after the experiences with the PC card, I’m now treating it with a little skepticism…
Z80 PIO
There is a lot of information about using the Z80 PIO around. Key references:
- Z80 PIO Users Guide: http://www.z80.info/zip/z80piomn.pdf
- Spectrum Hardware Guide Chapter 15: https://worldofspectrum.net/item/2000357/
Key features:
- Two fully bidirectional 8-bit IO ports.
- Handshaking (not used for the PDS).
- Close compatibility with Z80 control signals (most not used for the PDS).
- Four modes of operation:
- Byte output
- Byte input
- Byte bidirectional (port A only)
- Bit control
- Six registers addressable via 4 IO ports in the Z80 IO map.
The signals involved in address decoding are:
ZX BusPIOFunctionA5PORTSELSelects PORT A or PORT BA6CONTSELSelects DATA or CONTROLA7/CEEnables the device/M1/M1Z80 control signal/IORQ/IORQIO access in progress/RD/RDRead in progressCLOCKCLKZ80 clockThe use of A5-A7 means that any IO address (IORQ must be active) with A7 clear (CE is active LOW) will be received by the PIO and then A5 and A6 determine the type of access. This gives an IO address of the following:
b000x xxxx$xx0x or $xx1xPORT A DATAb001x xxxx$xx2x or $xx3xPORT B DATAb010x xxxx$xx4x or $xx5xPORT A CONTROLb011x xxxx$xx6x or $xx7xPORT B CONTROLThis equates to some pretty lazy IO address decoding, in that there are many, many equivalent IO addresses that would be decoded by the PIO.
Note that the CPC wiki lists port addresses in the range 0xFBEC-0xFBEF. These are the addresses used with the Amstrad CPC not the ZX Spectrum.
Looking at the provided source code for the ZX Spectrum, it appears to be using IO instructions (OUT, IN) using ports 31 ($1F), 63 ($3F), 95 ($5F), and 127 ($7F).
The schematic shows that /IORQ from the PIO is connected to /IORQ from the Z80 via a SPDT switch which allows selection between Z80 /IORQ and fixed pulled HIGH. This allows the PIO to be inhibited by stopping it responding to /IORQ.
The interrupt control lines for the PIO are not used. INT and IEO are not connected and IEI is pulled HIGH. The hand-shake signals (ARDY, ASTB, BRDY, BSTB) are not used either.
ZX Spectrum PDS Interface
The ZX Spectrum side of the PDS interface has the following:
- PIO PORT A – goes via the 74LS245 octal buffer to the 8 data lines of the PDS link.
- PIO PORT B – goes via the 74LS04 for certain control signals from the PDS link, and the direction control for the 74LS245.
- Bit 0 – Pin 3 of the PDS interface (PC to target)
- Bit 1-4 – not used
- Bit 5 – Pin 7 of the PDS interface
- Bit 6 – 245 direction control
- Bit 7 – Pin 5 of the PDS interface (target to PC)
Note that half the PDS control signals are not used for the Spectrum interface. From the previous discussion we can interpret bits 0 and 7 to be the two clock/ack signals. Bit 5’s use is currently unknown. I’ll have to go to the code to see what is going on there.
ZX Spectrum PDS Monitor
I’ve not been able to find any source code for the PC side of things, some assembler has been issued for the target machines, which can be assembled into the run-time PDS monitor for that system.
The PDS Manual does have this to say:
“The software is designed to be machine independent, so the same protocols can be
used regardless of the target machines processor or make. All the communication is basically
the same, there are four major routines, SEND BYTE, GET BYTE and two direction
swapping routines.”There are three versions of the monitor code for the ZX Spectrum:
- DL0 – the most minimal implementation, providing assembling and downloading only.
- DL1 – the long downloader, providing support for everything apart from the “analyze” command, which requires interrupts.
- DL2 – the full interrupt driven downloader.
The PDS manual contains some information about the ZX Spectrum downloader. Section 6.2 details the three versions of the code and then goes on to describe the available commands.
To get a feel for how the monitor functions, and some insights into how the hardware works, I’m looking at some extracts of DL0.
Code initialisation
START DI
LD A,255
OUT (127),A ; $7F=CB=$FF Mode 3
OUT (63),A ; $3F=DB=$FF PORT B=$FF (B0-7=HIGH)
LD A,63
OUT (127),A ; $7F=CB=$3F B6/B7=OUTPUT B0-B5=INPUT
LD A,255
OUT (95),A ; $5F=CA=$FF Mode 3
OUT (95),A ; $5F=CA=$FF A0-A7=INPUTCTRL = $FF means all bits of the control register are set. The Z8020 datasheet lists the control register as follows:
76543210M1M0xx1111Where M1/M0 signify which of the four modes is to be used. In this case both PORTs are set to Mode 3, which allows for either IN or OUT on a per bit basis. I am guessing the writing of $FF to DB (PORT B DATA) happens to ensure that when then ports are configured as 2 OUT and 6 IN, the OUT lines are already HIGH, giving a known starting point.
Note: Setting B6 to HIGH means that the direction control for the 74LS245 will be LOW as it goes through an inverter. This sets the 74LS245 to work in the direction “B to A” which would correspond to when PORT A is set to all INPUTs later in the code.
GETBYTE
This is the lowest level function and it retrieves a single byte of data from over the PDS interface. This is used during the main protocol handling to both obtain commands over PDS and then receive data.
The essential function is as follows:
- Ensure PORT A setup for INPUT
- WAIT for a change in the PC->TARGET CLOCK
- Read the data from PORT A
- WRITE the TARGET->PC CLOCK/ACK
- Toggle the two CLOCK signals ready for next time
- Return
;On first entry D=64=b0100 0000
GETBYTE IN A,(63) ;Read DB - control values
XOR D ;Toggle FLAGS
RRCA ;Pushes B0->Carry
JC GETBYTE ;Wait for B0 to have changed
IN A,(31) ;Read data from DA
LD E,A ;And store in E
LD A,D ;Reload FLAGS
OUT (63),A ;And write them out ie write B7
XOR 129 ;Toggle B0+B7 (129, $81) for next time
LD D,A ;And store back in D
RETSo I think the key features for this are:
- Control FLAGS are stored in the D register. Only B0, B6, B7 are significant. B0 is what we’re looking for on reception; B7 is what we will send in acknowledgement; B6 is the DIRection and is preset to INPUT for this.
- FLAGS are initialised to 64 i.e. B0=B7=0; B6=1.
- Every pass through the GETBYTE function toggles B0 and B7 between b0xxxxxx0 and b1xxxxxx1.
- Read data is stored in the E register.
- RRCA is used to take the read in control value and shift B0 into the carry flag so it can be checked with JC (JP C).
- Nothing else in the code works with the D register so it will always reflect the required status of the required PORT B CTRL word flags.
So this shows how the flags change through several passes of the function:
D=64 D=0100 0000 ($40)
CALL GETBYTE D=1100 0001 ($C1)
CALL GETBYTE D=0100 0000 ($40)
CALL GETBYTE D=1100 0001 ($C1)The PDS Manual describes the protocol as follows:
“Note that the protocol does not set the control lines directly, but toggles the lines to
communicate. All the protocols are designed so one computer can never get ahead of the
other, even if there is a big speed difference. There are no error checking protocols, as the
interfaces are very reliable, and error checking will slow down processes, and no real action
can be taken, even if an error was detected.”Main Loop
The main loop essentially reads a byte from the interface and treats it as a control command. It will keep doing this until it finds a command it can process.
MAINLOOP CALL GETBYTE ;Get 'command byte'
LD A,E
CP 180 ;Download code into aabb, len=ccdd
JZ DLOAD
CP 183 ;Select bank aa
JZ SBANK
CP 181 ;Execute code from aabb?
JNZ MAINLOOP ;Not recognised - keep looping.The comments are the original comments. There is a not a function for command 181, as this relies on “fall through”. It is the next function in the code.
The commands have values 180-187 as follows:
- 180: Download code
- 181: Jump to an address
- 182: Upload memory
- 183: Select bank
- 184: Send all registers to the main computer
- 185: Get registers from the main computer
- 186: Trace code buffer
- 187: Return analyze address
The various functions and message protocol layer are described in the PDS manual, so I won’t go into them in detail here, but by way of example, here is the description for 181:
The corresponding code is as follows:
;
; Function 181, Execute code from aabb
;
CALL GETBYTE
LD H,E ;Get address of routine
CALL GETBYTE
LD L,E
LD BC,MAINLOOP
PUSH BC ;Put return address on stack and jump to routine
JP (HL)It is interesting to note that in the PDS manual, some commands appear to start with a padding byte (179). Apparently this is to ensure that all command messages are an even number of bytes long.
Any variable length commands (e.g. download) include an expected length field.
To retrieve data from the target, the protocol has the concept of “reverse ports”. After receiving upload command, ports are reversed to allow the sending of the appropriate amount of data before being reversed once again to restore the original direction ready for the next command.
Uploading is not supported in the simple D0 downloader. That requires the more complete D1 or D2 implementations. I’ve not gone into more detail here.
Conclusion
I’m going to leave this here for now. I think I’ve got a reasonable grasp of what is going on and I’d like to see if I can recreate the interfaces used at some point.
The ZX Spectrum one should be relatively straight forward. To do something with the PC end though is going to require a lot of work as I just don’t believe I can rely on that schematic.
I have to question though whether it would be worth it though. Given that an Intel 8255 is no longer available I’ll be using reclaimed parts and I also don’t have a PC with ISA anymore. I must admit I am wondering if an alternative PC end would be possible using a microcontroller to implement the PDS protocol and connect to the PC over USB (for example).
In fact, with something like a Raspberry Pi Pico, it would be quite possible to implement the entire target interface through to emulating the Z80 PIO on the ZX Spectrum board and potentially have a replacement system that is “USB direct to Spectrum”.
At this point of course, this is not really the PDS anymore and I’m sure there are already many modern alternatives to getting code running on a ZX Spectrum from a modern system, so that too might be a little pointless. And that is before we get into emulation.
But for its time, this is a really interesting system and it is a shame that information about it seems to have slowly disappeared.
I am still quite keen to recreate it though, so I might be on the look out for an old PC with ISA…
Oh, and as always, if you know about the PDS and are able to confirm or refute anything I’ve said here, do let me know in the comments!
Kevin
#intel8255 #pds #programmersDevelopmentSystem #z80 #z80Pio #zxSpectrum -
PDS – the Programmers Development System
I was directed towards this recently – it is a means of developing for 8-bit computers using early PCs or an Atari ST developed by Andy Glaister. Information about it seems quite sparse online, the main references seem to be:
- https://www.cpcwiki.eu/index.php/PDS_development_system
- https://www.worldofsam.org/products/pds-development-system (largely a repeat of the above)
- https://trastero.speccy.org/cosas/JL/PDS/Introduccion.html (link via Internet Archive)
- https://lemmings.info/pds-programmers-development-system/ and https://lemmings.info/pds-recreating-the-system/
- It is also talked about and demonstrated here: https://youtu.be/S6DlSfEj0as?si=gEOmOA53eiqXRWc_&t=589
As far as I can tell the original system was developed in the 1980s and there have been two attempts at recreating it since, as listed above.
The original reimplementation is from the Spanish site and provides a schematic and Eagle files. The next link was an attempt at using these design files by importing into KiCAD and getting Gerber files built which seemed to be pretty successful.
I must admit that when I first heard about it, I wondered if it was the same one that Dean Belfield was using with his Tatung Einstein at the 2025 RetroFest, but having read a bit more about it, there are definitely similarities, but I’m not sure its the same. Details of Dean’s setup here:
- http://www.breakintoprogram.co.uk/computers/recreating-my-80s-dev-system-part-1
- https://github.com/breakintoprogram/einstein-ide
It uses a similar principle to the PDS, in that development is performed on the Tatung and then code is transferred across to the target system using a combination of hardware and code running on both sides.
Basic Operation
As I understand things, with the PDS there was an interface card for the PC which linked via a 16-wire IDC cable to another interface card for the target computer. There were versions for the ZX Spectrum, Amstrad CPC, C64 and MSX (and possibly others). I’m only really interested in the ZX Spectrum version.
The PC card is based around the Intel 8255 parallel IO chip sitting on an 8-bit ISA bus. The target interface is usually based around the Z80 PIO (Z84C20) interfacing to the bus of the host system. The PC card supports two target interfaces and both cards include some logic chips to handle addressing and the IO interface.
Details of the 16-way IO link seem very sparse and will probably have to be worked through and inferred from the source code that has been uncovered.
From what I can tell, most of the protocol handling is done in the code and the interfaces are essentially IO “passthroughs”. The target has to run some monitor code to react to PDS commands and interface with the memory as required, setting, reading, updating, and so on.
The CPC wiki seems to be the most complete source of information so far, and includes photos of the remade boards and schematics for the PC card and ZX Spectrum interface.
The PDS Link
The PDS link itself is via a 16-way IDC ribbon cable and 2×8 IDC connectors. Unfortunately I’ve not found a pin-out anywhere so far, but from various sources, this is what I know so far.
GND12DATA 0PC to Target Clock34DATA 1Target to PC Clock/Ack56DATA 2Unknown78DATA 3Not used910DATA 4Not used1112DATA 5Not used1314DATA 6Not used1516DATA 7This is using the pin numbering from the ZX Spectrum schematic.
Unfortunately the schematic labelling of the two PDS sockets for the PC card is backwards compared to the ZX Spectrum card. Pin 16 for the PC version is GND, but that is pin 1 for the ZX Spectrum version. It would also appear that the socket shroud is also reversed. This means that D0 is pin 15 for the PC and pin 2 for the Spectrum.
The CPC wiki has a photo of the cable used, showing how pins 1-16 are wired to pins 16-1:
The PC Card
The schematic for the PC card can be found on the CPC wiki here: https://www.cpcwiki.eu/index.php/PDS_development_system
Main Components required:
- Intel 8255 Programmable Peripheral Interface (PPI).
- 74LS138 – 3 to 8 line decoder (for the addressing).
- 3x 74LS244 – 8 channel non-inverting buffers.
- 74LS04 – Hex Inverter (only one inverter is used).
It probably goes without saying for this era technology, but everything is 5V TTL levels.
The Intel 8255 PPI
The Intel 8255 Programmable Peripheral Interface (PPI) device provides access to 3 bidirectional 8-bit IO ports. There is a good summary here.
From https://en.wikipedia.org/wiki/Intel_8255:
The 8255 gives a CPU or digital system access to programmable parallel I/O. The 8255 has 24 input/output pins. These are divided into three 8-bit ports (A, B, C). Port A and port B can be used as 8-bit input/output ports. Port C can be used as an 8-bit input/output port or as two 4-bit input/output ports or to produce handshake signals for ports A and B.
The three ports are further grouped as follows:
- Group A consisting of port A and upper part of port C.
- Group B consisting of port B and lower part of port C.
There are two address lines that are used to select one of four registers as follows:
A1A0Register00Port A01Port B10Port C11Control RegisterThe device is selected on the bus when CS is active. It also uses RD and WR to know if it is reading from or writing to the registers.
Things get a bit complicated pretty quickly, but there is a good summary of the various modes of operation on the Wikipedia page, and of course, a comprehensive datasheet.
PC PDS Interface
According to the schematic, this is how the three 8255 IO ports map onto the two PDS connections:
8255 IO PortPDS Connection74LS244 UsedEnabled byPORT A 0-3Link 2: Data 0-3IC 3B/PC2PORT A 4-7Link 1: Data 0-3IC 4B/PC2PORT B 0-3Link 1: Data 4-7IC 3APC2PORT B 4-7Link 2: Data 4-7IC 4APC2PORT C 0-3Link 1 and 2: ControlIC 5AAlways OnPORT C 4-7Link 1 and 2: ControlIC 5BAlways OnIt is also worth noting that the three 74LS244 buffers are enabled in different ways according to the state of PC2. Also, as the enable is active LOW, the inverter on PC2 generates a “NOT PC2” signal, which itself must be LOW to activate IC3A/IC4A – i.e. it is a “active on NOT NOT PC2” signal. PC2 appears to be used to decide which nibble of the data port should be active. It is also passed through to the link control pins (see below).
The 8 control lines map onto the two links in an interesting way. Note this is using “PC interface” pin numbering which as previously mentioned is different to the ZX Spectrum side.
Link 1 PinsLink 2 PinsPC0144PC1414PC266PC388PC4122PC5212PC610N/CPC7N/C10So we can see that PC2 and PC3 are common; that PC0/PC1, PC4/PC5 are swapped; and that PC6 is link 1 only; and PC7 is link 2 only. Recall PC2 appears to select which nibble is active.
When mapped onto the ZX Spectrum card, anything on pins 2,4,6,8 are mapped onto unused pins.
I must say I’m struggling to make sense of this. This seems to be implying that when data is written to one of the PPI IO PORTs, it is striped across both link 1 and 2. Surely it would make more sense to select one or the other and write all 8 data values in one go?
I did wonder if this was related to the different IO modes of the 8255, but on re-reading how the modes work, this still doesn’t make much sense to me.
Unfortunately there doesn’t appear to be any source code for the PC end of things to see what it is doing.
Ok, so finding a print of the traces for the PCB and overlaying them on a light box gives me the following:
I’ve highlighted the connection for D0. We can clearly see that on the PCB D0 for both links is connected, and not only that, it is connected to both input side 2A1 and output side 1Y4 on the /same/ IC. This would make sense for a bi-directional bus, but it is quite a long way from the schematic.
At this point I have to conclude that the schematic is just plain wrong so I’m leaving the PC card for now.
The ZX Spectrum Card
The spectrum side is based on the Z80 PIO (Z8420/Z84C20). There is also a schematic and PCB for that on the CPC wki, but after the experiences with the PC card, I’m now treating it with a little skepticism…
Z80 PIO
There is a lot of information about using the Z80 PIO around. Key references:
- Z80 PIO Users Guide: http://www.z80.info/zip/z80piomn.pdf
- Spectrum Hardware Guide Chapter 15: https://worldofspectrum.net/item/2000357/
Key features:
- Two fully bidirectional 8-bit IO ports.
- Handshaking (not used for the PDS).
- Close compatibility with Z80 control signals (most not used for the PDS).
- Four modes of operation:
- Byte output
- Byte input
- Byte bidirectional (port A only)
- Bit control
- Six registers addressable via 4 IO ports in the Z80 IO map.
The signals involved in address decoding are:
ZX BusPIOFunctionA5PORTSELSelects PORT A or PORT BA6CONTSELSelects DATA or CONTROLA7/CEEnables the device/M1/M1Z80 control signal/IORQ/IORQIO access in progress/RD/RDRead in progressCLOCKCLKZ80 clockThe use of A5-A7 means that any IO address (IORQ must be active) with A7 clear (CE is active LOW) will be received by the PIO and then A5 and A6 determine the type of access. This gives an IO address of the following:
b000x xxxx$xx0x or $xx1xPORT A DATAb001x xxxx$xx2x or $xx3xPORT B DATAb010x xxxx$xx4x or $xx5xPORT A CONTROLb011x xxxx$xx6x or $xx7xPORT B CONTROLThis equates to some pretty lazy IO address decoding, in that there are many, many equivalent IO addresses that would be decoded by the PIO.
Note that the CPC wiki lists port addresses in the range 0xFBEC-0xFBEF. These are the addresses used with the Amstrad CPC not the ZX Spectrum.
Looking at the provided source code for the ZX Spectrum, it appears to be using IO instructions (OUT, IN) using ports 31 ($1F), 63 ($3F), 95 ($5F), and 127 ($7F).
The schematic shows that /IORQ from the PIO is connected to /IORQ from the Z80 via a SPDT switch which allows selection between Z80 /IORQ and fixed pulled HIGH. This allows the PIO to be inhibited by stopping it responding to /IORQ.
The interrupt control lines for the PIO are not used. INT and IEO are not connected and IEI is pulled HIGH. The hand-shake signals (ARDY, ASTB, BRDY, BSTB) are not used either.
ZX Spectrum PDS Interface
The ZX Spectrum side of the PDS interface has the following:
- PIO PORT A – goes via the 74LS245 octal buffer to the 8 data lines of the PDS link.
- PIO PORT B – goes via the 74LS04 for certain control signals from the PDS link, and the direction control for the 74LS245.
- Bit 0 – Pin 2 of the PDS interface
- Bit 1-4 – not used
- Bit 5 – Pin 7 of the PDS interface
- Bit 6 – 245 direction control
- Bit 7 – Pin 5 of the PDS interface
Note that half the PDS control signals are not used for the Spectrum interface. From the previous discussion we can interpret bits 2 and 7 to be the two clock/ack signals. Bit 5’s use is currently unknown. I’ll have to go to the code to see what is going on there.
ZX Spectrum PDS Monitor
I’ve not been able to find any source code for the PC side of things, some assembler has been issued for the target machines, which can be assembled into the run-time PDS monitor for that system.
The PDS Manual does have this to say:
“The software is designed to be machine independent, so the same protocols can be
used regardless of the target machines processor or make. All the communication is basically
the same, there are four major routines, SEND BYTE, GET BYTE and two direction
swapping routines.”There are three versions of the monitor code for the ZX Spectrum:
- DL0 – the most minimal implementation, providing assembling and downloading only.
- DL1 – the long downloader, providing support for everything apart from the “analyze” command, which requires interrupts.
- DL2 – the full interrupt driven downloader.
The PDS manual contains some information about the ZX Spectrum downloader. Section 6.2 details the three versions of the code and then goes on to describe the available commands.
To get a feel for how the monitor functions, and some insights into how the hardware works, I’m looking at some extracts of DL0.
Code initialisation
START DI
LD A,255
OUT (127),A ; $7F=CB=$FF Mode 3
OUT (63),A ; $3F=DB=$FF PORT B=$FF (B0-7=HIGH)
LD A,63
OUT (127),A ; $7F=CB=$3F B6/B7=OUTPUT B0-B5=INPUT
LD A,255
OUT (95),A ; $5F=CA=$FF Mode 3
OUT (95),A ; $5F=CA=$FF A0-A7=INPUTCTRL = $FF means all bits of the control register are set. The Z8020 datasheet lists the control register as follows:
76543210M1M0xx1111Where M1/M0 signify which of the four modes is to be used. In this case both PORTs are set to Mode 3, which allows for either IN or OUT on a per bit basis. I am guessing the writing of $FF to DB (PORT B DATA) happens to ensure that when then ports are configured as 2 OUT and 6 IN, the OUT lines are already HIGH, giving a known starting point.
Note: Setting B6 to HIGH means that the direction control for the 74LS245 will be LOW as it goes through an inverter. This sets the 74LS245 to work in the direction “B to A” which would correspond to when PORT A is set to all INPUTs later in the code.
GETBYTE
This is the lowest level function and it retrieves a single byte of data from over the PDS interface. This is used during the main protocol handling to both obtain commands over PDS and then receive data.
The essential function is as follows:
- Ensure PORT A setup for INPUT
- WAIT for a change in the PC->TARGET CLOCK
- Read the data from PORT A
- WRITE the TARGET->PC CLOCK/ACK
- Toggle the two CLOCK signals ready for next time
- Return
;On first entry D=64=b0100 0000
GETBYTE IN A,(63) ;Read DB - control values
XOR D ;Toggle FLAGS
RRCA ;Pushes B0->Carry
JC GETBYTE ;Wait for B0 to have changed
IN A,(31) ;Read data from DA
LD E,A ;And store in E
LD A,D ;Reload FLAGS
OUT (63),A ;And write them out ie write B7
XOR 129 ;Toggle B0+B7 (129, $81) for next time
LD D,A ;And store back in D
RETSo I think the key features for this are:
- Control FLAGS are stored in the D register. Only B0, B6, B7 are significant. B0 is what we’re looking for on reception; B7 is what we will send in acknowledgement; B6 is the DIRection and is preset to INPUT for this.
- FLAGS are initialised to 64 i.e. B0=B7=0; B6=1.
- Every pass through the GETBYTE function toggles B0 and B7 between b0xxxxxx0 and b1xxxxxx1.
- Read data is stored in the E register.
- RRCA is used to take the read in control value and shift B0 into the carry flag so it can be checked with JC (JP C).
- Nothing else in the code works with the D register so it will always reflect the required status of the required PORT B CTRL word flags.
So this shows how the flags change through several passes of the function:
D=64 D=0100 0000 ($40)
CALL GETBYTE D=1100 0001 ($C1)
CALL GETBYTE D=0100 0000 ($40)
CALL GETBYTE D=1100 0001 ($C1)The PDS Manual describes the protocol as follows:
“Note that the protocol does not set the control lines directly, but toggles the lines to
communicate. All the protocols are designed so one computer can never get ahead of the
other, even if there is a big speed difference. There are no error checking protocols, as the
interfaces are very reliable, and error checking will slow down processes, and no real action
can be taken, even if an error was detected.”Main Loop
The main loop essentially reads a byte from the interface and treats it as a control command. It will keep doing this until it finds a command it can process.
MAINLOOP CALL GETBYTE ;Get 'command byte'
LD A,E
CP 180 ;Download code into aabb, len=ccdd
JZ DLOAD
CP 183 ;Select bank aa
JZ SBANK
CP 181 ;Execute code from aabb?
JNZ MAINLOOP ;Not recognised - keep looping.The comments are the original comments. There is a not a function for command 181, as this relies on “fall through”. It is the next function in the code.
The commands have values 180-187 as follows:
- 180: Download code
- 181: Jump to an address
- 182: Upload memory
- 183: Select bank
- 184: Send all registers to the main computer
- 185: Get registers from the main computer
- 186: Trace code buffer
- 187: Return analyze address
The various functions and message protocol layer are described in the PDS manual, so I won’t go into them in detail here, but by way of example, here is the description for 181:
The corresponding code is as follows:
;
; Function 181, Execute code from aabb
;
CALL GETBYTE
LD H,E ;Get address of routine
CALL GETBYTE
LD L,E
LD BC,MAINLOOP
PUSH BC ;Put return address on stack and jump to routine
JP (HL)It is interesting to note that in the PDS manual, some commands appear to start with a padding byte (179). Apparently this is to ensure that all command messages are an even number of bytes long.
Any variable length commands (e.g. download) include an expected length field.
To retrieve data from the target, the protocol has the concept of “reverse ports”. After receiving upload command, ports are reversed to allow the sending of the appropriate amount of data before being reversed once again to restore the original direction ready for the next command.
Uploading is not supported in the simple D0 downloader. That requires the more complete D1 or D2 implementations. I’ve not gone into more detail here.
Conclusion
I’m going to leave this here for now. I think I’ve got a reasonable grasp of what is going on and I’d like to see if I can recreate the interfaces used at some point.
The ZX Spectrum one should be relatively straight forward. To do something with the PC end though is going to require a lot of work as I just don’t believe I can rely on that schematic.
I have to question though whether it would be worth it though. Given that an Intel 8255 is no longer available I’ll be using reclaimed parts and I also don’t have a PC with ISA anymore. I must admit I am wondering if an alternative PC end would be possible using a microcontroller to implement the PDS protocol and connect to the PC over USB (for example).
In fact, with something like a Raspberry Pi Pico, it would be quite possible to implement the entire target interface through to emulating the Z80 PIO on the ZX Spectrum board and potentially have a replacement system that is “USB direct to Spectrum”.
At this point of course, this is not really the PDS anymore and I’m sure there are already many modern alternatives to getting code running on a ZX Spectrum from a modern system, so that too might be a little pointless. And that is before we get into emulation.
But for its time, this is a really interesting system and it is a shame that information about it seems to have slowly disappeared.
I am still quite keen to recreate it though, so I might be on the look out for an old PC with ISA…
Oh, and as always, if you know about the PDS and are able to confirm or refute anything I’ve said here, do let me know in the comments!
Kevin
#intel8255 #pds #programmersDevelopmentSystem #z80 #z80Pio #zxSpectrum -
PDS – the Programmers Development System
I was directed towards this recently – it is a means of developing for 8-bit computers using early PCs or an Atari ST developed by Andy Glaister. Information about it seems quite sparse online, the main references seem to be:
- https://www.cpcwiki.eu/index.php/PDS_development_system
- https://www.worldofsam.org/products/pds-development-system (largely a repeat of the above)
- https://trastero.speccy.org/cosas/JL/PDS/Introduccion.html (link via Internet Archive)
- https://lemmings.info/pds-programmers-development-system/ and https://lemmings.info/pds-recreating-the-system/
- It is also talked about and demonstrated here: https://youtu.be/S6DlSfEj0as?si=gEOmOA53eiqXRWc_&t=589
As far as I can tell the original system was developed in the 1980s and there have been two attempts at recreating it since, as listed above.
The original reimplementation is from the Spanish site and provides a schematic and Eagle files. The next link was an attempt at using these design files by importing into KiCAD and getting Gerber files built which seemed to be pretty successful.
I must admit that when I first heard about it, I wondered if it was the same one that Dean Belfield was using with his Tatung Einstein at the 2025 RetroFest, but having read a bit more about it, there are definitely similarities, but I’m not sure its the same. Details of Dean’s setup here:
- http://www.breakintoprogram.co.uk/computers/recreating-my-80s-dev-system-part-1
- https://github.com/breakintoprogram/einstein-ide
It uses a similar principle to the PDS, in that development is performed on the Tatung and then code is transferred across to the target system using a combination of hardware and code running on both sides.
Basic Operation
As I understand things, with the PDS there was an interface card for the PC which linked via a 16-wire IDC cable to another interface card for the target computer. There were versions for the ZX Spectrum, Amstrad CPC, C64 and MSX (and possibly others). I’m only really interested in the ZX Spectrum version.
The PC card is based around the Intel 8255 parallel IO chip sitting on an 8-bit ISA bus. The target interface is usually based around the Z80 PIO (Z84C20) interfacing to the bus of the host system. The PC card supports two target interfaces and both cards include some logic chips to handle addressing and the IO interface.
Details of the 16-way IO link seem very sparse and will probably have to be worked through and inferred from the source code that has been uncovered.
From what I can tell, most of the protocol handling is done in the code and the interfaces are essentially IO “passthroughs”. The target has to run some monitor code to react to PDS commands and interface with the memory as required, setting, reading, updating, and so on.
The CPC wiki seems to be the most complete source of information so far, and includes photos of the remade boards and schematics for the PC card and ZX Spectrum interface.
The PDS Link
The PDS link itself is via a 16-way IDC ribbon cable and 2×8 IDC connectors. Unfortunately I’ve not found a pin-out anywhere so far, but from various sources, this is what I know so far.
GND12DATA 0PC to Target Clock34DATA 1Target to PC Clock/Ack56DATA 2Unknown78DATA 3Not used910DATA 4Not used1112DATA 5Not used1314DATA 6Not used1516DATA 7This is using the pin numbering from the ZX Spectrum schematic.
Unfortunately the schematic labelling of the two PDS sockets for the PC card is backwards compared to the ZX Spectrum card. Pin 16 for the PC version is GND, but that is pin 1 for the ZX Spectrum version. It would also appear that the socket shroud is also reversed. This means that D0 is pin 15 for the PC and pin 2 for the Spectrum.
The CPC wiki has a photo of the cable used, showing how pins 1-16 are wired to pins 16-1:
The PC Card
The schematic for the PC card can be found on the CPC wiki here: https://www.cpcwiki.eu/index.php/PDS_development_system
Main Components required:
- Intel 8255 Programmable Peripheral Interface (PPI).
- 74LS138 – 3 to 8 line decoder (for the addressing).
- 3x 74LS244 – 8 channel non-inverting buffers.
- 74LS04 – Hex Inverter (only one inverter is used).
It probably goes without saying for this era technology, but everything is 5V TTL levels.
The Intel 8255 PPI
The Intel 8255 Programmable Peripheral Interface (PPI) device provides access to 3 bidirectional 8-bit IO ports. There is a good summary here.
From https://en.wikipedia.org/wiki/Intel_8255:
The 8255 gives a CPU or digital system access to programmable parallel I/O. The 8255 has 24 input/output pins. These are divided into three 8-bit ports (A, B, C). Port A and port B can be used as 8-bit input/output ports. Port C can be used as an 8-bit input/output port or as two 4-bit input/output ports or to produce handshake signals for ports A and B.
The three ports are further grouped as follows:
- Group A consisting of port A and upper part of port C.
- Group B consisting of port B and lower part of port C.
There are two address lines that are used to select one of four registers as follows:
A1A0Register00Port A01Port B10Port C11Control RegisterThe device is selected on the bus when CS is active. It also uses RD and WR to know if it is reading from or writing to the registers.
Things get a bit complicated pretty quickly, but there is a good summary of the various modes of operation on the Wikipedia page, and of course, a comprehensive datasheet.
PC PDS Interface
According to the schematic, this is how the three 8255 IO ports map onto the two PDS connections:
8255 IO PortPDS Connection74LS244 UsedEnabled byPORT A 0-3Link 2: Data 0-3IC 3B/PC2PORT A 4-7Link 1: Data 0-3IC 4B/PC2PORT B 0-3Link 1: Data 4-7IC 3APC2PORT B 4-7Link 2: Data 4-7IC 4APC2PORT C 0-3Link 1 and 2: ControlIC 5AAlways OnPORT C 4-7Link 1 and 2: ControlIC 5BAlways OnIt is also worth noting that the three 74LS244 buffers are enabled in different ways according to the state of PC2. Also, as the enable is active LOW, the inverter on PC2 generates a “NOT PC2” signal, which itself must be LOW to activate IC3A/IC4A – i.e. it is a “active on NOT NOT PC2” signal. PC2 appears to be used to decide which nibble of the data port should be active. It is also passed through to the link control pins (see below).
The 8 control lines map onto the two links in an interesting way. Note this is using “PC interface” pin numbering which as previously mentioned is different to the ZX Spectrum side.
Link 1 PinsLink 2 PinsPC0144PC1414PC266PC388PC4122PC5212PC610N/CPC7N/C10So we can see that PC2 and PC3 are common; that PC0/PC1, PC4/PC5 are swapped; and that PC6 is link 1 only; and PC7 is link 2 only. Recall PC2 appears to select which nibble is active.
When mapped onto the ZX Spectrum card, anything on pins 2,4,6,8 are mapped onto unused pins.
I must say I’m struggling to make sense of this. This seems to be implying that when data is written to one of the PPI IO PORTs, it is striped across both link 1 and 2. Surely it would make more sense to select one or the other and write all 8 data values in one go?
I did wonder if this was related to the different IO modes of the 8255, but on re-reading how the modes work, this still doesn’t make much sense to me.
Unfortunately there doesn’t appear to be any source code for the PC end of things to see what it is doing.
Ok, so finding a print of the traces for the PCB and overlaying them on a light box gives me the following:
I’ve highlighted the connection for D0. We can clearly see that on the PCB D0 for both links is connected, and not only that, it is connected to both input side 2A1 and output side 1Y4 on the /same/ IC. This would make sense for a bi-directional bus, but it is quite a long way from the schematic.
At this point I have to conclude that the schematic is just plain wrong so I’m leaving the PC card for now.
The ZX Spectrum Card
The spectrum side is based on the Z80 PIO (Z8420/Z84C20). There is also a schematic and PCB for that on the CPC wki, but after the experiences with the PC card, I’m now treating it with a little skepticism…
Z80 PIO
There is a lot of information about using the Z80 PIO around. Key references:
- Z80 PIO Users Guide: http://www.z80.info/zip/z80piomn.pdf
- Spectrum Hardware Guide Chapter 15: https://worldofspectrum.net/item/2000357/
Key features:
- Two fully bidirectional 8-bit IO ports.
- Handshaking (not used for the PDS).
- Close compatibility with Z80 control signals (most not used for the PDS).
- Four modes of operation:
- Byte output
- Byte input
- Byte bidirectional (port A only)
- Bit control
- Six registers addressable via 4 IO ports in the Z80 IO map.
The signals involved in address decoding are:
ZX BusPIOFunctionA5PORTSELSelects PORT A or PORT BA6CONTSELSelects DATA or CONTROLA7/CEEnables the device/M1/M1Z80 control signal/IORQ/IORQIO access in progress/RD/RDRead in progressCLOCKCLKZ80 clockThe use of A5-A7 means that any IO address (IORQ must be active) with A7 clear (CE is active LOW) will be received by the PIO and then A5 and A6 determine the type of access. This gives an IO address of the following:
b000x xxxx$xx0x or $xx1xPORT A DATAb001x xxxx$xx2x or $xx3xPORT B DATAb010x xxxx$xx4x or $xx5xPORT A CONTROLb011x xxxx$xx6x or $xx7xPORT B CONTROLThis equates to some pretty lazy IO address decoding, in that there are many, many equivalent IO addresses that would be decoded by the PIO.
Note that the CPC wiki lists port addresses in the range 0xFBEC-0xFBEF. These are the addresses used with the Amstrad CPC not the ZX Spectrum.
Looking at the provided source code for the ZX Spectrum, it appears to be using IO instructions (OUT, IN) using ports 31 ($1F), 63 ($3F), 95 ($5F), and 127 ($7F).
The schematic shows that /IORQ from the PIO is connected to /IORQ from the Z80 via a SPDT switch which allows selection between Z80 /IORQ and fixed pulled HIGH. This allows the PIO to be inhibited by stopping it responding to /IORQ.
The interrupt control lines for the PIO are not used. INT and IEO are not connected and IEI is pulled HIGH. The hand-shake signals (ARDY, ASTB, BRDY, BSTB) are not used either.
ZX Spectrum PDS Interface
The ZX Spectrum side of the PDS interface has the following:
- PIO PORT A – goes via the 74LS245 octal buffer to the 8 data lines of the PDS link.
- PIO PORT B – goes via the 74LS04 for certain control signals from the PDS link, and the direction control for the 74LS245.
- Bit 0 – Pin 2 of the PDS interface
- Bit 1-4 – not used
- Bit 5 – Pin 7 of the PDS interface
- Bit 6 – 245 direction control
- Bit 7 – Pin 5 of the PDS interface
Note that half the PDS control signals are not used for the Spectrum interface. From the previous discussion we can interpret bits 2 and 7 to be the two clock/ack signals. Bit 5’s use is currently unknown. I’ll have to go to the code to see what is going on there.
ZX Spectrum PDS Monitor
I’ve not been able to find any source code for the PC side of things, some assembler has been issued for the target machines, which can be assembled into the run-time PDS monitor for that system.
The PDS Manual does have this to say:
“The software is designed to be machine independent, so the same protocols can be
used regardless of the target machines processor or make. All the communication is basically
the same, there are four major routines, SEND BYTE, GET BYTE and two direction
swapping routines.”There are three versions of the monitor code for the ZX Spectrum:
- DL0 – the most minimal implementation, providing assembling and downloading only.
- DL1 – the long downloader, providing support for everything apart from the “analyze” command, which requires interrupts.
- DL2 – the full interrupt driven downloader.
The PDS manual contains some information about the ZX Spectrum downloader. Section 6.2 details the three versions of the code and then goes on to describe the available commands.
To get a feel for how the monitor functions, and some insights into how the hardware works, I’m looking at some extracts of DL0.
Code initialisation
START DI
LD A,255
OUT (127),A ; $7F=CB=$FF Mode 3
OUT (63),A ; $3F=DB=$FF PORT B=$FF (B0-7=HIGH)
LD A,63
OUT (127),A ; $7F=CB=$3F B6/B7=OUTPUT B0-B5=INPUT
LD A,255
OUT (95),A ; $5F=CA=$FF Mode 3
OUT (95),A ; $5F=CA=$FF A0-A7=INPUTCTRL = $FF means all bits of the control register are set. The Z8020 datasheet lists the control register as follows:
76543210M1M0xx1111Where M1/M0 signify which of the four modes is to be used. In this case both PORTs are set to Mode 3, which allows for either IN or OUT on a per bit basis. I am guessing the writing of $FF to DB (PORT B DATA) happens to ensure that when then ports are configured as 2 OUT and 6 IN, the OUT lines are already HIGH, giving a known starting point.
Note: Setting B6 to HIGH means that the direction control for the 74LS245 will be LOW as it goes through an inverter. This sets the 74LS245 to work in the direction “B to A” which would correspond to when PORT A is set to all INPUTs later in the code.
GETBYTE
This is the lowest level function and it retrieves a single byte of data from over the PDS interface. This is used during the main protocol handling to both obtain commands over PDS and then receive data.
The essential function is as follows:
- Ensure PORT A setup for INPUT
- WAIT for a change in the PC->TARGET CLOCK
- Read the data from PORT A
- WRITE the TARGET->PC CLOCK/ACK
- Toggle the two CLOCK signals ready for next time
- Return
;On first entry D=64=b0100 0000
GETBYTE IN A,(63) ;Read DB - control values
XOR D ;Toggle FLAGS
RRCA ;Pushes B0->Carry
JC GETBYTE ;Wait for B0 to have changed
IN A,(31) ;Read data from DA
LD E,A ;And store in E
LD A,D ;Reload FLAGS
OUT (63),A ;And write them out ie write B7
XOR 129 ;Toggle B0+B7 (129, $81) for next time
LD D,A ;And store back in D
RETSo I think the key features for this are:
- Control FLAGS are stored in the D register. Only B0, B6, B7 are significant. B0 is what we’re looking for on reception; B7 is what we will send in acknowledgement; B6 is the DIRection and is preset to INPUT for this.
- FLAGS are initialised to 64 i.e. B0=B7=0; B6=1.
- Every pass through the GETBYTE function toggles B0 and B7 between b0xxxxxx0 and b1xxxxxx1.
- Read data is stored in the E register.
- RRCA is used to take the read in control value and shift B0 into the carry flag so it can be checked with JC (JP C).
- Nothing else in the code works with the D register so it will always reflect the required status of the required PORT B CTRL word flags.
So this shows how the flags change through several passes of the function:
D=64 D=0100 0000 ($40)
CALL GETBYTE D=1100 0001 ($C1)
CALL GETBYTE D=0100 0000 ($40)
CALL GETBYTE D=1100 0001 ($C1)The PDS Manual describes the protocol as follows:
“Note that the protocol does not set the control lines directly, but toggles the lines to
communicate. All the protocols are designed so one computer can never get ahead of the
other, even if there is a big speed difference. There are no error checking protocols, as the
interfaces are very reliable, and error checking will slow down processes, and no real action
can be taken, even if an error was detected.”Main Loop
The main loop essentially reads a byte from the interface and treats it as a control command. It will keep doing this until it finds a command it can process.
MAINLOOP CALL GETBYTE ;Get 'command byte'
LD A,E
CP 180 ;Download code into aabb, len=ccdd
JZ DLOAD
CP 183 ;Select bank aa
JZ SBANK
CP 181 ;Execute code from aabb?
JNZ MAINLOOP ;Not recognised - keep looping.The comments are the original comments. There is a not a function for command 181, as this relies on “fall through”. It is the next function in the code.
The commands have values 180-187 as follows:
- 180: Download code
- 181: Jump to an address
- 182: Upload memory
- 183: Select bank
- 184: Send all registers to the main computer
- 185: Get registers from the main computer
- 186: Trace code buffer
- 187: Return analyze address
The various functions and message protocol layer are described in the PDS manual, so I won’t go into them in detail here, but by way of example, here is the description for 181:
The corresponding code is as follows:
;
; Function 181, Execute code from aabb
;
CALL GETBYTE
LD H,E ;Get address of routine
CALL GETBYTE
LD L,E
LD BC,MAINLOOP
PUSH BC ;Put return address on stack and jump to routine
JP (HL)It is interesting to note that in the PDS manual, some commands appear to start with a padding byte (179). Apparently this is to ensure that all command messages are an even number of bytes long.
Any variable length commands (e.g. download) include an expected length field.
To retrieve data from the target, the protocol has the concept of “reverse ports”. After receiving upload command, ports are reversed to allow the sending of the appropriate amount of data before being reversed once again to restore the original direction ready for the next command.
Uploading is not supported in the simple D0 downloader. That requires the more complete D1 or D2 implementations. I’ve not gone into more detail here.
Conclusion
I’m going to leave this here for now. I think I’ve got a reasonable grasp of what is going on and I’d like to see if I can recreate the interfaces used at some point.
The ZX Spectrum one should be relatively straight forward. To do something with the PC end though is going to require a lot of work as I just don’t believe I can rely on that schematic.
I have to question though whether it would be worth it though. Given that an Intel 8255 is no longer available I’ll be using reclaimed parts and I also don’t have a PC with ISA anymore. I must admit I am wondering if an alternative PC end would be possible using a microcontroller to implement the PDS protocol and connect to the PC over USB (for example).
In fact, with something like a Raspberry Pi Pico, it would be quite possible to implement the entire target interface through to emulating the Z80 PIO on the ZX Spectrum board and potentially have a replacement system that is “USB direct to Spectrum”.
At this point of course, this is not really the PDS anymore and I’m sure there are already many modern alternatives to getting code running on a ZX Spectrum from a modern system, so that too might be a little pointless. And that is before we get into emulation.
But for its time, this is a really interesting system and it is a shame that information about it seems to have slowly disappeared.
I am still quite keen to recreate it though, so I might be on the look out for an old PC with ISA…
Oh, and as always, if you know about the PDS and are able to confirm or refute anything I’ve said here, do let me know in the comments!
Kevin
#intel8255 #pds #programmersDevelopmentSystem #z80 #z80Pio #zxSpectrum -
PDS – the Programmers Development System
I was directed towards this recently – it is a means of developing for 8-bit computers using early PCs or an Atari ST developed by Andy Glaister. Information about it seems quite sparse online, the main references seem to be:
- https://www.cpcwiki.eu/index.php/PDS_development_system
- https://www.worldofsam.org/products/pds-development-system (largely a repeat of the above)
- https://trastero.speccy.org/cosas/JL/PDS/Introduccion.html (link via Internet Archive)
- https://lemmings.info/pds-programmers-development-system/ and https://lemmings.info/pds-recreating-the-system/
- It is also talked about and demonstrated here: https://youtu.be/S6DlSfEj0as?si=gEOmOA53eiqXRWc_&t=589
As far as I can tell the original system was developed in the 1980s and there have been two attempts at recreating it since, as listed above.
The original reimplementation is from the Spanish site and provides a schematic and Eagle files. The next link was an attempt at using these design files by importing into KiCAD and getting Gerber files built which seemed to be pretty successful.
I must admit that when I first heard about it, I wondered if it was the same one that Dean Belfield was using with his Tatung Einstein at the 2025 RetroFest, but having read a bit more about it, there are definitely similarities, but I’m not sure its the same. Details of Dean’s setup here:
- http://www.breakintoprogram.co.uk/computers/recreating-my-80s-dev-system-part-1
- https://github.com/breakintoprogram/einstein-ide
It uses a similar principle to the PDS, in that development is performed on the Tatung and then code is transferred across to the target system using a combination of hardware and code running on both sides.
Basic Operation
As I understand things, with the PDS there was an interface card for the PC which linked via a 16-wire IDC cable to another interface card for the target computer. There were versions for the ZX Spectrum, Amstrad CPC, C64 and MSX (and possibly others). I’m only really interested in the ZX Spectrum version.
The PC card is based around the Intel 8255 parallel IO chip sitting on an 8-bit ISA bus. The target interface is usually based around the Z80 PIO (Z84C20) interfacing to the bus of the host system. The PC card supports two target interfaces and both cards include some logic chips to handle addressing and the IO interface.
Details of the 16-way IO link seem very sparse and will probably have to be worked through and inferred from the source code that has been uncovered.
From what I can tell, most of the protocol handling is done in the code and the interfaces are essentially IO “passthroughs”. The target has to run some monitor code to react to PDS commands and interface with the memory as required, setting, reading, updating, and so on.
The CPC wiki seems to be the most complete source of information so far, and includes photos of the remade boards and schematics for the PC card and ZX Spectrum interface.
The PDS Link
The PDS link itself is via a 16-way IDC ribbon cable and 2×8 IDC connectors. Unfortunately I’ve not found a pin-out anywhere so far, but from various sources, this is what I know so far.
GND12DATA 0PC to Target Clock34DATA 1Target to PC Clock/Ack56DATA 2Unknown78DATA 3Not used910DATA 4Not used1112DATA 5Not used1314DATA 6Not used1516DATA 7This is using the pin numbering from the ZX Spectrum schematic.
Unfortunately the schematic labelling of the two PDS sockets for the PC card is backwards compared to the ZX Spectrum card. Pin 16 for the PC version is GND, but that is pin 1 for the ZX Spectrum version. It would also appear that the socket shroud is also reversed. This means that D0 is pin 15 for the PC and pin 2 for the Spectrum.
The CPC wiki has a photo of the cable used, showing how pins 1-16 are wired to pins 16-1:
The PC Card
The schematic for the PC card can be found on the CPC wiki here: https://www.cpcwiki.eu/index.php/PDS_development_system
Main Components required:
- Intel 8255 Programmable Peripheral Interface (PPI).
- 74LS138 – 3 to 8 line decoder (for the addressing).
- 3x 74LS244 – 8 channel non-inverting buffers.
- 74LS04 – Hex Inverter (only one inverter is used).
It probably goes without saying for this era technology, but everything is 5V TTL levels.
The Intel 8255 PPI
The Intel 8255 Programmable Peripheral Interface (PPI) device provides access to 3 bidirectional 8-bit IO ports. There is a good summary here.
From https://en.wikipedia.org/wiki/Intel_8255:
The 8255 gives a CPU or digital system access to programmable parallel I/O. The 8255 has 24 input/output pins. These are divided into three 8-bit ports (A, B, C). Port A and port B can be used as 8-bit input/output ports. Port C can be used as an 8-bit input/output port or as two 4-bit input/output ports or to produce handshake signals for ports A and B.
The three ports are further grouped as follows:
- Group A consisting of port A and upper part of port C.
- Group B consisting of port B and lower part of port C.
There are two address lines that are used to select one of four registers as follows:
A1A0Register00Port A01Port B10Port C11Control RegisterThe device is selected on the bus when CS is active. It also uses RD and WR to know if it is reading from or writing to the registers.
Things get a bit complicated pretty quickly, but there is a good summary of the various modes of operation on the Wikipedia page, and of course, a comprehensive datasheet.
PC PDS Interface
According to the schematic, this is how the three 8255 IO ports map onto the two PDS connections:
8255 IO PortPDS Connection74LS244 UsedEnabled byPORT A 0-3Link 2: Data 0-3IC 3B/PC2PORT A 4-7Link 1: Data 0-3IC 4B/PC2PORT B 0-3Link 1: Data 4-7IC 3APC2PORT B 4-7Link 2: Data 4-7IC 4APC2PORT C 0-3Link 1 and 2: ControlIC 5AAlways OnPORT C 4-7Link 1 and 2: ControlIC 5BAlways OnIt is also worth noting that the three 74LS244 buffers are enabled in different ways according to the state of PC2. Also, as the enable is active LOW, the inverter on PC2 generates a “NOT PC2” signal, which itself must be LOW to activate IC3A/IC4A – i.e. it is a “active on NOT NOT PC2” signal. PC2 appears to be used to decide which nibble of the data port should be active. It is also passed through to the link control pins (see below).
The 8 control lines map onto the two links in an interesting way. Note this is using “PC interface” pin numbering which as previously mentioned is different to the ZX Spectrum side.
Link 1 PinsLink 2 PinsPC0144PC1414PC266PC388PC4122PC5212PC610N/CPC7N/C10So we can see that PC2 and PC3 are common; that PC0/PC1, PC4/PC5 are swapped; and that PC6 is link 1 only; and PC7 is link 2 only. Recall PC2 appears to select which nibble is active.
When mapped onto the ZX Spectrum card, anything on pins 2,4,6,8 are mapped onto unused pins.
I must say I’m struggling to make sense of this. This seems to be implying that when data is written to one of the PPI IO PORTs, it is striped across both link 1 and 2. Surely it would make more sense to select one or the other and write all 8 data values in one go?
I did wonder if this was related to the different IO modes of the 8255, but on re-reading how the modes work, this still doesn’t make much sense to me.
Unfortunately there doesn’t appear to be any source code for the PC end of things to see what it is doing.
Ok, so finding a print of the traces for the PCB and overlaying them on a light box gives me the following:
I’ve highlighted the connection for D0. We can clearly see that on the PCB D0 for both links is connected, and not only that, it is connected to both input side 2A1 and output side 1Y4 on the /same/ IC. This would make sense for a bi-directional bus, but it is quite a long way from the schematic.
At this point I have to conclude that the schematic is just plain wrong so I’m leaving the PC card for now.
The ZX Spectrum Card
The spectrum side is based on the Z80 PIO (Z8420/Z84C20). There is also a schematic and PCB for that on the CPC wki, but after the experiences with the PC card, I’m now treating it with a little skepticism…
Z80 PIO
There is a lot of information about using the Z80 PIO around. Key references:
- Z80 PIO Users Guide: http://www.z80.info/zip/z80piomn.pdf
- Spectrum Hardware Guide Chapter 15: https://worldofspectrum.net/item/2000357/
Key features:
- Two fully bidirectional 8-bit IO ports.
- Handshaking (not used for the PDS).
- Close compatibility with Z80 control signals (most not used for the PDS).
- Four modes of operation:
- Byte output
- Byte input
- Byte bidirectional (port A only)
- Bit control
- Six registers addressable via 4 IO ports in the Z80 IO map.
The signals involved in address decoding are:
ZX BusPIOFunctionA5PORTSELSelects PORT A or PORT BA6CONTSELSelects DATA or CONTROLA7/CEEnables the device/M1/M1Z80 control signal/IORQ/IORQIO access in progress/RD/RDRead in progressCLOCKCLKZ80 clockThe use of A5-A7 means that any IO address (IORQ must be active) with A7 clear (CE is active LOW) will be received by the PIO and then A5 and A6 determine the type of access. This gives an IO address of the following:
b000x xxxx$xx0x or $xx1xPORT A DATAb001x xxxx$xx2x or $xx3xPORT B DATAb010x xxxx$xx4x or $xx5xPORT A CONTROLb011x xxxx$xx6x or $xx7xPORT B CONTROLThis equates to some pretty lazy IO address decoding, in that there are many, many equivalent IO addresses that would be decoded by the PIO.
Note that the CPC wiki lists port addresses in the range 0xFBEC-0xFBEF. These are the addresses used with the Amstrad CPC not the ZX Spectrum.
Looking at the provided source code for the ZX Spectrum, it appears to be using IO instructions (OUT, IN) using ports 31 ($1F), 63 ($3F), 95 ($5F), and 127 ($7F).
The schematic shows that /IORQ from the PIO is connected to /IORQ from the Z80 via a SPDT switch which allows selection between Z80 /IORQ and fixed pulled HIGH. This allows the PIO to be inhibited by stopping it responding to /IORQ.
The interrupt control lines for the PIO are not used. INT and IEO are not connected and IEI is pulled HIGH. The hand-shake signals (ARDY, ASTB, BRDY, BSTB) are not used either.
ZX Spectrum PDS Interface
The ZX Spectrum side of the PDS interface has the following:
- PIO PORT A – goes via the 74LS245 octal buffer to the 8 data lines of the PDS link.
- PIO PORT B – goes via the 74LS04 for certain control signals from the PDS link, and the direction control for the 74LS245.
- Bit 0 – Pin 2 of the PDS interface
- Bit 1-4 – not used
- Bit 5 – Pin 7 of the PDS interface
- Bit 6 – 245 direction control
- Bit 7 – Pin 5 of the PDS interface
Note that half the PDS control signals are not used for the Spectrum interface. From the previous discussion we can interpret bits 2 and 7 to be the two clock/ack signals. Bit 5’s use is currently unknown. I’ll have to go to the code to see what is going on there.
ZX Spectrum PDS Monitor
I’ve not been able to find any source code for the PC side of things, some assembler has been issued for the target machines, which can be assembled into the run-time PDS monitor for that system.
The PDS Manual does have this to say:
“The software is designed to be machine independent, so the same protocols can be
used regardless of the target machines processor or make. All the communication is basically
the same, there are four major routines, SEND BYTE, GET BYTE and two direction
swapping routines.”There are three versions of the monitor code for the ZX Spectrum:
- DL0 – the most minimal implementation, providing assembling and downloading only.
- DL1 – the long downloader, providing support for everything apart from the “analyze” command, which requires interrupts.
- DL2 – the full interrupt driven downloader.
The PDS manual contains some information about the ZX Spectrum downloader. Section 6.2 details the three versions of the code and then goes on to describe the available commands.
To get a feel for how the monitor functions, and some insights into how the hardware works, I’m looking at some extracts of DL0.
Code initialisation
START DI
LD A,255
OUT (127),A ; $7F=CB=$FF Mode 3
OUT (63),A ; $3F=DB=$FF PORT B=$FF (B0-7=HIGH)
LD A,63
OUT (127),A ; $7F=CB=$3F B6/B7=OUTPUT B0-B5=INPUT
LD A,255
OUT (95),A ; $5F=CA=$FF Mode 3
OUT (95),A ; $5F=CA=$FF A0-A7=INPUTCTRL = $FF means all bits of the control register are set. The Z8020 datasheet lists the control register as follows:
76543210M1M0xx1111Where M1/M0 signify which of the four modes is to be used. In this case both PORTs are set to Mode 3, which allows for either IN or OUT on a per bit basis. I am guessing the writing of $FF to DB (PORT B DATA) happens to ensure that when then ports are configured as 2 OUT and 6 IN, the OUT lines are already HIGH, giving a known starting point.
Note: Setting B6 to HIGH means that the direction control for the 74LS245 will be LOW as it goes through an inverter. This sets the 74LS245 to work in the direction “B to A” which would correspond to when PORT A is set to all INPUTs later in the code.
GETBYTE
This is the lowest level function and it retrieves a single byte of data from over the PDS interface. This is used during the main protocol handling to both obtain commands over PDS and then receive data.
The essential function is as follows:
- Ensure PORT A setup for INPUT
- WAIT for a change in the PC->TARGET CLOCK
- Read the data from PORT A
- WRITE the TARGET->PC CLOCK/ACK
- Toggle the two CLOCK signals ready for next time
- Return
;On first entry D=64=b0100 0000
GETBYTE IN A,(63) ;Read DB - control values
XOR D ;Toggle FLAGS
RRCA ;Pushes B0->Carry
JC GETBYTE ;Wait for B0 to have changed
IN A,(31) ;Read data from DA
LD E,A ;And store in E
LD A,D ;Reload FLAGS
OUT (63),A ;And write them out ie write B7
XOR 129 ;Toggle B0+B7 (129, $81) for next time
LD D,A ;And store back in D
RETSo I think the key features for this are:
- Control FLAGS are stored in the D register. Only B0, B6, B7 are significant. B0 is what we’re looking for on reception; B7 is what we will send in acknowledgement; B6 is the DIRection and is preset to INPUT for this.
- FLAGS are initialised to 64 i.e. B0=B7=0; B6=1.
- Every pass through the GETBYTE function toggles B0 and B7 between b0xxxxxx0 and b1xxxxxx1.
- Read data is stored in the E register.
- RRCA is used to take the read in control value and shift B0 into the carry flag so it can be checked with JC (JP C).
- Nothing else in the code works with the D register so it will always reflect the required status of the required PORT B CTRL word flags.
So this shows how the flags change through several passes of the function:
D=64 D=0100 0000 ($40)
CALL GETBYTE D=1100 0001 ($C1)
CALL GETBYTE D=0100 0000 ($40)
CALL GETBYTE D=1100 0001 ($C1)The PDS Manual describes the protocol as follows:
“Note that the protocol does not set the control lines directly, but toggles the lines to
communicate. All the protocols are designed so one computer can never get ahead of the
other, even if there is a big speed difference. There are no error checking protocols, as the
interfaces are very reliable, and error checking will slow down processes, and no real action
can be taken, even if an error was detected.”Main Loop
The main loop essentially reads a byte from the interface and treats it as a control command. It will keep doing this until it finds a command it can process.
MAINLOOP CALL GETBYTE ;Get 'command byte'
LD A,E
CP 180 ;Download code into aabb, len=ccdd
JZ DLOAD
CP 183 ;Select bank aa
JZ SBANK
CP 181 ;Execute code from aabb?
JNZ MAINLOOP ;Not recognised - keep looping.The comments are the original comments. There is a not a function for command 181, as this relies on “fall through”. It is the next function in the code.
The commands have values 180-187 as follows:
- 180: Download code
- 181: Jump to an address
- 182: Upload memory
- 183: Select bank
- 184: Send all registers to the main computer
- 185: Get registers from the main computer
- 186: Trace code buffer
- 187: Return analyze address
The various functions and message protocol layer are described in the PDS manual, so I won’t go into them in detail here, but by way of example, here is the description for 181:
The corresponding code is as follows:
;
; Function 181, Execute code from aabb
;
CALL GETBYTE
LD H,E ;Get address of routine
CALL GETBYTE
LD L,E
LD BC,MAINLOOP
PUSH BC ;Put return address on stack and jump to routine
JP (HL)It is interesting to note that in the PDS manual, some commands appear to start with a padding byte (179). Apparently this is to ensure that all command messages are an even number of bytes long.
Any variable length commands (e.g. download) include an expected length field.
To retrieve data from the target, the protocol has the concept of “reverse ports”. After receiving upload command, ports are reversed to allow the sending of the appropriate amount of data before being reversed once again to restore the original direction ready for the next command.
Uploading is not supported in the simple D0 downloader. That requires the more complete D1 or D2 implementations. I’ve not gone into more detail here.
Conclusion
I’m going to leave this here for now. I think I’ve got a reasonable grasp of what is going on and I’d like to see if I can recreate the interfaces used at some point.
The ZX Spectrum one should be relatively straight forward. To do something with the PC end though is going to require a lot of work as I just don’t believe I can rely on that schematic.
I have to question though whether it would be worth it though. Given that an Intel 8255 is no longer available I’ll be using reclaimed parts and I also don’t have a PC with ISA anymore. I must admit I am wondering if an alternative PC end would be possible using a microcontroller to implement the PDS protocol and connect to the PC over USB (for example).
In fact, with something like a Raspberry Pi Pico, it would be quite possible to implement the entire target interface through to emulating the Z80 PIO on the ZX Spectrum board and potentially have a replacement system that is “USB direct to Spectrum”.
At this point of course, this is not really the PDS anymore and I’m sure there are already many modern alternatives to getting code running on a ZX Spectrum from a modern system, so that too might be a little pointless. And that is before we get into emulation.
But for its time, this is a really interesting system and it is a shame that information about it seems to have slowly disappeared.
I am still quite keen to recreate it though, so I might be on the look out for an old PC with ISA…
Oh, and as always, if you know about the PDS and are able to confirm or refute anything I’ve said here, do let me know in the comments!
Kevin
#intel8255 #pds #programmersDevelopmentSystem #z80 #z80Pio #zxSpectrum -
PDS – the Programmers Development System
This series of posts looks at the Programmers Development System (PDS).
- 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
I was directed towards this recently – it is a means of developing for 8-bit computers using early PCs or an Atari ST developed by Andy Glaister. Information about it seems quite sparse online, the main references seem to be:
- https://www.cpcwiki.eu/index.php/PDS_development_system
- https://www.worldofsam.org/products/pds-development-system (largely a repeat of the above)
- https://trastero.speccy.org/cosas/JL/PDS/Introduccion.html (link via Internet Archive)
- https://lemmings.info/pds-programmers-development-system/ and https://lemmings.info/pds-recreating-the-system/
- It is also talked about and demonstrated here: https://youtu.be/S6DlSfEj0as?si=gEOmOA53eiqXRWc_&t=589
As far as I can tell the original system was developed in the 1980s and there have been two attempts at recreating it since, as listed above.
The original reimplementation is from the Spanish site and provides a schematic and Eagle files. The next link was an attempt at using these design files by importing into KiCAD and getting Gerber files built which seemed to be pretty successful.
I must admit that when I first heard about it, I wondered if it was the same one that Dean Belfield was using with his Tatung Einstein at the 2025 RetroFest, but having read a bit more about it, there are definitely similarities, but I’m not sure its the same. Details of Dean’s setup here:
- http://www.breakintoprogram.co.uk/computers/recreating-my-80s-dev-system-part-1
- https://github.com/breakintoprogram/einstein-ide
It uses a similar principle to the PDS, in that development is performed on the Tatung and then code is transferred across to the target system using a combination of hardware and code running on both sides.
Basic Operation
As I understand things, with the PDS there was an interface card for the PC which linked via a 16-wire IDC cable to another interface card for the target computer. There were versions for the ZX Spectrum, Amstrad CPC, C64 and MSX (and possibly others). I’m only really interested in the ZX Spectrum version.
The PC card is based around the Intel 8255 parallel IO chip sitting on an 8-bit ISA bus. The target interface is usually based around the Z80 PIO (Z84C20) interfacing to the bus of the host system. The PC card supports two target interfaces and both cards include some logic chips to handle addressing and the IO interface.
Details of the 16-way IO link seem very sparse and will probably have to be worked through and inferred from the source code that has been uncovered.
From what I can tell, most of the protocol handling is done in the code and the interfaces are essentially IO “passthroughs”. The target has to run some monitor code to react to PDS commands and interface with the memory as required, setting, reading, updating, and so on.
The CPC wiki seems to be the most complete source of information so far, and includes photos of the remade boards and schematics for the PC card and ZX Spectrum interface.
The PDS Link
The PDS link itself is via a 16-way IDC ribbon cable and 2×8 IDC connectors. Unfortunately I’ve not found a pin-out anywhere so far, but from various sources, this is what I know so far.
GND12DATA 0PC to Target Clock34DATA 1Target to PC Clock/Ack56DATA 2Unknown78DATA 3Not used910DATA 4Not used1112DATA 5Not used1314DATA 6Not used1516DATA 7This is using the pin numbering from the ZX Spectrum schematic.
Unfortunately the schematic labelling of the two PDS sockets for the PC card is backwards compared to the ZX Spectrum card. Pin 16 for the PC version is GND, but that is pin 1 for the ZX Spectrum version. It would also appear that the socket shroud is also reversed. This means that D0 is pin 15 for the PC and pin 2 for the Spectrum.
The CPC wiki has a photo of the cable used, showing how pins 1-16 are wired to pins 16-1:
The PC Card
The schematic for the PC card can be found on the CPC wiki here: https://www.cpcwiki.eu/index.php/PDS_development_system
Main Components required:
- Intel 8255 Programmable Peripheral Interface (PPI).
- 74LS138 – 3 to 8 line decoder (for the addressing).
- 3x 74LS244 – 8 channel non-inverting buffers.
- 74LS04 – Hex Inverter (only one inverter is used).
It probably goes without saying for this era technology, but everything is 5V TTL levels.
The Intel 8255 PPI
The Intel 8255 Programmable Peripheral Interface (PPI) device provides access to 3 bidirectional 8-bit IO ports. There is a good summary here.
From https://en.wikipedia.org/wiki/Intel_8255:
The 8255 gives a CPU or digital system access to programmable parallel I/O. The 8255 has 24 input/output pins. These are divided into three 8-bit ports (A, B, C). Port A and port B can be used as 8-bit input/output ports. Port C can be used as an 8-bit input/output port or as two 4-bit input/output ports or to produce handshake signals for ports A and B.
The three ports are further grouped as follows:
- Group A consisting of port A and upper part of port C.
- Group B consisting of port B and lower part of port C.
There are two address lines that are used to select one of four registers as follows:
A1A0Register00Port A01Port B10Port C11Control RegisterThe device is selected on the bus when CS is active. It also uses RD and WR to know if it is reading from or writing to the registers.
Things get a bit complicated pretty quickly, but there is a good summary of the various modes of operation on the Wikipedia page, and of course, a comprehensive datasheet.
PC PDS Interface
According to the schematic, this is how the three 8255 IO ports map onto the two PDS connections:
8255 IO PortPDS Connection74LS244 UsedEnabled byPORT A 0-3Link 2: Data 0-3IC 3B/PC2PORT A 4-7Link 1: Data 0-3IC 4B/PC2PORT B 0-3Link 1: Data 4-7IC 3APC2PORT B 4-7Link 2: Data 4-7IC 4APC2PORT C 0-3Link 1 and 2: ControlIC 5AAlways OnPORT C 4-7Link 1 and 2: ControlIC 5BAlways OnIt is also worth noting that the three 74LS244 buffers are enabled in different ways according to the state of PC2. Also, as the enable is active LOW, the inverter on PC2 generates a “NOT PC2” signal, which itself must be LOW to activate IC3A/IC4A – i.e. it is a “active on NOT NOT PC2” signal. PC2 appears to be used to decide which nibble of the data port should be active. It is also passed through to the link control pins (see below).
The 8 control lines map onto the two links in an interesting way. Note this is using “PC interface” pin numbering which as previously mentioned is different to the ZX Spectrum side.
Link 1 PinsLink 2 PinsPC0144PC1414PC266PC388PC4122PC5212PC610N/CPC7N/C10So we can see that PC2 and PC3 are common; that PC0/PC1, PC4/PC5 are swapped; and that PC6 is link 1 only; and PC7 is link 2 only. Recall PC2 appears to select which nibble is active.
When mapped onto the ZX Spectrum card, anything on pins 2,4,6,8 are mapped onto unused pins.
I must say I’m struggling to make sense of this. This seems to be implying that when data is written to one of the PPI IO PORTs, it is striped across both link 1 and 2. Surely it would make more sense to select one or the other and write all 8 data values in one go?
I did wonder if this was related to the different IO modes of the 8255, but on re-reading how the modes work, this still doesn’t make much sense to me.
Unfortunately there doesn’t appear to be any source code for the PC end of things to see what it is doing.
Ok, so finding a print of the traces for the PCB and overlaying them on a light box gives me the following:
I’ve highlighted the connection for D0. We can clearly see that on the PCB D0 for both links is connected, and not only that, it is connected to both input side 2A1 and output side 1Y4 on the /same/ IC. This would make sense for a bi-directional bus, but it is quite a long way from the schematic.
At this point I have to conclude that the schematic is just plain wrong so I’m leaving the PC card for now.
The ZX Spectrum Card
The spectrum side is based on the Z80 PIO (Z8420/Z84C20). There is also a schematic and PCB for that on the CPC wki, but after the experiences with the PC card, I’m now treating it with a little skepticism…
Z80 PIO
There is a lot of information about using the Z80 PIO around. Key references:
- Z80 PIO Users Guide: http://www.z80.info/zip/z80piomn.pdf
- Spectrum Hardware Guide Chapter 15: https://worldofspectrum.net/item/2000357/
Key features:
- Two fully bidirectional 8-bit IO ports.
- Handshaking (not used for the PDS).
- Close compatibility with Z80 control signals (most not used for the PDS).
- Four modes of operation:
- Byte output
- Byte input
- Byte bidirectional (port A only)
- Bit control
- Six registers addressable via 4 IO ports in the Z80 IO map.
The signals involved in address decoding are:
ZX BusPIOFunctionA5PORTSELSelects PORT A or PORT BA6CONTSELSelects DATA or CONTROLA7/CEEnables the device/M1/M1Z80 control signal/IORQ/IORQIO access in progress/RD/RDRead in progressCLOCKCLKZ80 clockThe use of A5-A7 means that any IO address (IORQ must be active) with A7 clear (CE is active LOW) will be received by the PIO and then A5 and A6 determine the type of access. This gives an IO address of the following:
b000x xxxx$xx0x or $xx1xPORT A DATAb001x xxxx$xx2x or $xx3xPORT B DATAb010x xxxx$xx4x or $xx5xPORT A CONTROLb011x xxxx$xx6x or $xx7xPORT B CONTROLThis equates to some pretty lazy IO address decoding, in that there are many, many equivalent IO addresses that would be decoded by the PIO.
Note that the CPC wiki lists port addresses in the range 0xFBEC-0xFBEF. These are the addresses used with the Amstrad CPC not the ZX Spectrum.
Looking at the provided source code for the ZX Spectrum, it appears to be using IO instructions (OUT, IN) using ports 31 ($1F), 63 ($3F), 95 ($5F), and 127 ($7F).
The schematic shows that /IORQ from the PIO is connected to /IORQ from the Z80 via a SPDT switch which allows selection between Z80 /IORQ and fixed pulled HIGH. This allows the PIO to be inhibited by stopping it responding to /IORQ.
The interrupt control lines for the PIO are not used. INT and IEO are not connected and IEI is pulled HIGH. The hand-shake signals (ARDY, ASTB, BRDY, BSTB) are not used either.
ZX Spectrum PDS Interface
The ZX Spectrum side of the PDS interface has the following:
- PIO PORT A – goes via the 74LS245 octal buffer to the 8 data lines of the PDS link.
- PIO PORT B – goes via the 74LS04 for certain control signals from the PDS link, and the direction control for the 74LS245.
- Bit 0 – Pin 3 of the PDS interface (PC to target)
- Bit 1-4 – not used
- Bit 5 – Pin 7 of the PDS interface
- Bit 6 – 245 direction control
- Bit 7 – Pin 5 of the PDS interface (target to PC)
Note that half the PDS control signals are not used for the Spectrum interface. From the previous discussion we can interpret bits 0 and 7 to be the two clock/ack signals. Bit 5’s use is currently unknown. I’ll have to go to the code to see what is going on there.
ZX Spectrum PDS Monitor
I’ve not been able to find any source code for the PC side of things, some assembler has been issued for the target machines, which can be assembled into the run-time PDS monitor for that system.
The PDS Manual does have this to say:
“The software is designed to be machine independent, so the same protocols can be
used regardless of the target machines processor or make. All the communication is basically
the same, there are four major routines, SEND BYTE, GET BYTE and two direction
swapping routines.”There are three versions of the monitor code for the ZX Spectrum:
- DL0 – the most minimal implementation, providing assembling and downloading only.
- DL1 – the long downloader, providing support for everything apart from the “analyze” command, which requires interrupts.
- DL2 – the full interrupt driven downloader.
The PDS manual contains some information about the ZX Spectrum downloader. Section 6.2 details the three versions of the code and then goes on to describe the available commands.
To get a feel for how the monitor functions, and some insights into how the hardware works, I’m looking at some extracts of DL0.
Code initialisation
START DI
LD A,255
OUT (127),A ; $7F=CB=$FF Mode 3
OUT (63),A ; $3F=DB=$FF PORT B=$FF (B0-7=HIGH)
LD A,63
OUT (127),A ; $7F=CB=$3F B6/B7=OUTPUT B0-B5=INPUT
LD A,255
OUT (95),A ; $5F=CA=$FF Mode 3
OUT (95),A ; $5F=CA=$FF A0-A7=INPUTCTRL = $FF means all bits of the control register are set. The Z8020 datasheet lists the control register as follows:
76543210M1M0xx1111Where M1/M0 signify which of the four modes is to be used. In this case both PORTs are set to Mode 3, which allows for either IN or OUT on a per bit basis. I am guessing the writing of $FF to DB (PORT B DATA) happens to ensure that when then ports are configured as 2 OUT and 6 IN, the OUT lines are already HIGH, giving a known starting point.
Note: Setting B6 to HIGH means that the direction control for the 74LS245 will be LOW as it goes through an inverter. This sets the 74LS245 to work in the direction “B to A” which would correspond to when PORT A is set to all INPUTs later in the code.
GETBYTE
This is the lowest level function and it retrieves a single byte of data from over the PDS interface. This is used during the main protocol handling to both obtain commands over PDS and then receive data.
The essential function is as follows:
- Ensure PORT A setup for INPUT
- WAIT for a change in the PC->TARGET CLOCK
- Read the data from PORT A
- WRITE the TARGET->PC CLOCK/ACK
- Toggle the two CLOCK signals ready for next time
- Return
;On first entry D=64=b0100 0000
GETBYTE IN A,(63) ;Read DB - control values
XOR D ;Toggle FLAGS
RRCA ;Pushes B0->Carry
JC GETBYTE ;Wait for B0 to have changed
IN A,(31) ;Read data from DA
LD E,A ;And store in E
LD A,D ;Reload FLAGS
OUT (63),A ;And write them out ie write B7
XOR 129 ;Toggle B0+B7 (129, $81) for next time
LD D,A ;And store back in D
RETSo I think the key features for this are:
- Control FLAGS are stored in the D register. Only B0, B6, B7 are significant. B0 is what we’re looking for on reception; B7 is what we will send in acknowledgement; B6 is the DIRection and is preset to INPUT for this.
- FLAGS are initialised to 64 i.e. B0=B7=0; B6=1.
- Every pass through the GETBYTE function toggles B0 and B7 between b0xxxxxx0 and b1xxxxxx1.
- Read data is stored in the E register.
- RRCA is used to take the read in control value and shift B0 into the carry flag so it can be checked with JC (JP C).
- Nothing else in the code works with the D register so it will always reflect the required status of the required PORT B CTRL word flags.
So this shows how the flags change through several passes of the function:
D=64 D=0100 0000 ($40)
CALL GETBYTE D=1100 0001 ($C1)
CALL GETBYTE D=0100 0000 ($40)
CALL GETBYTE D=1100 0001 ($C1)The PDS Manual describes the protocol as follows:
“Note that the protocol does not set the control lines directly, but toggles the lines to
communicate. All the protocols are designed so one computer can never get ahead of the
other, even if there is a big speed difference. There are no error checking protocols, as the
interfaces are very reliable, and error checking will slow down processes, and no real action
can be taken, even if an error was detected.”Main Loop
The main loop essentially reads a byte from the interface and treats it as a control command. It will keep doing this until it finds a command it can process.
MAINLOOP CALL GETBYTE ;Get 'command byte'
LD A,E
CP 180 ;Download code into aabb, len=ccdd
JZ DLOAD
CP 183 ;Select bank aa
JZ SBANK
CP 181 ;Execute code from aabb?
JNZ MAINLOOP ;Not recognised - keep looping.The comments are the original comments. There is a not a function for command 181, as this relies on “fall through”. It is the next function in the code.
The commands have values 180-187 as follows:
- 180: Download code
- 181: Jump to an address
- 182: Upload memory
- 183: Select bank
- 184: Send all registers to the main computer
- 185: Get registers from the main computer
- 186: Trace code buffer
- 187: Return analyze address
The various functions and message protocol layer are described in the PDS manual, so I won’t go into them in detail here, but by way of example, here is the description for 181:
The corresponding code is as follows:
;
; Function 181, Execute code from aabb
;
CALL GETBYTE
LD H,E ;Get address of routine
CALL GETBYTE
LD L,E
LD BC,MAINLOOP
PUSH BC ;Put return address on stack and jump to routine
JP (HL)It is interesting to note that in the PDS manual, some commands appear to start with a padding byte (179). Apparently this is to ensure that all command messages are an even number of bytes long.
Any variable length commands (e.g. download) include an expected length field.
To retrieve data from the target, the protocol has the concept of “reverse ports”. After receiving upload command, ports are reversed to allow the sending of the appropriate amount of data before being reversed once again to restore the original direction ready for the next command.
Uploading is not supported in the simple D0 downloader. That requires the more complete D1 or D2 implementations. I’ve not gone into more detail here.
Conclusion
I’m going to leave this here for now. I think I’ve got a reasonable grasp of what is going on and I’d like to see if I can recreate the interfaces used at some point.
The ZX Spectrum one should be relatively straight forward. To do something with the PC end though is going to require a lot of work as I just don’t believe I can rely on that schematic.
I have to question though whether it would be worth it though. Given that an Intel 8255 is no longer available I’ll be using reclaimed parts and I also don’t have a PC with ISA anymore. I must admit I am wondering if an alternative PC end would be possible using a microcontroller to implement the PDS protocol and connect to the PC over USB (for example).
In fact, with something like a Raspberry Pi Pico, it would be quite possible to implement the entire target interface through to emulating the Z80 PIO on the ZX Spectrum board and potentially have a replacement system that is “USB direct to Spectrum”.
At this point of course, this is not really the PDS anymore and I’m sure there are already many modern alternatives to getting code running on a ZX Spectrum from a modern system, so that too might be a little pointless. And that is before we get into emulation.
But for its time, this is a really interesting system and it is a shame that information about it seems to have slowly disappeared.
I am still quite keen to recreate it though, so I might be on the look out for an old PC with ISA…
Oh, and as always, if you know about the PDS and are able to confirm or refute anything I’ve said here, do let me know in the comments!
Kevin
#intel8255 #pds #programmersDevelopmentSystem #z80 #z80Pio #zxSpectrum