Last modified on 11 March 2018, at 07:39

PDS download source code

Here is the original Amstrad CPC source code of the PDS development system download functions. Below DLn files (and other versions for C64, BBC, Spectrum) are also found in Media:PDS source code.zip.

AMSTRAD.DL0 (short version, 114 bytes)

;   Amstrad short download software
;
;
;Only to be used for assembling and downloading, most monitor functions
;will not opperate with this download software. It has been kept as short
;as possible. Note that the interupts are disabled. This is to prevent
;your own interupt routines crashing if they are overwritten.
;The code is 114 bytes long. It may be ORG'ed anywhere.
;
;
        ORG 8000H
;
START   LD A,255
        LD BC,0FBEEH
        OUT (C),A
        OUT (C),A
        INC C
        OUT (C),A       ;Initial port setup
        LD C,0EDH
        OUT (C),A
        LD C,0EFH
        LD A,63
        OUT (C),A
        LD D,64 ;Protocol flags to input from main computer
        DI
;
; Main loop
;
MAINLOOP        CALL GETBYTE    ;Get 'command byte'
        LD A,E
        CP 180  ;Download code into aabb, len=ccdd
        JZ DLOAD
        CP 183
        JZ BANK
        CP 181
        JNZ MAINLOOP    ;If unknown, keep looping
;
; Function 181, Execute code from aabb
;
        CALL GETBYTE
        LD H,E  ;Get address
        CALL GETBYTE
        LD L,E
        LD BC,MAINLOOP  ;CALL it.
        PUSH BC
        JP (HL)
;
; Function 183, Select bank aa
;
BANK    CALL GETBYTE
        LD B,7FH        ;You may write your own routine here.
        LD C,E  ;You may corrupt everything except E
        OUT (C),C       ;This allows you to page in rom and ram
        JR MAINLOOP
;
; Function 180, Download code into aabb, length=ccdd
;
DLOAD   CALL GETBYTE
        LD H,E
        CALL GETBYTE    ;Get start address of code
        LD L,E
        CALL GETBYTE
        LD B,E
        CALL GETBYTE    ;Get length of code
        LD C,E
DLOAD1  CALL GETBYTE
        LD (HL),E       ;Get and store bytes
        INC HL
        DEC BC
        LD A,B
        OR C
        JNZ DLOAD1
        JR MAINLOOP     ;Go back into main download loop
;
; Get a byte from the main computer into E
;
GETBYTE PUSH BC
        LD BC,0FBEDH
$1      IN A,(C)
        XOR D           ;Wait for 'sent the byte'
        RRCA
        JC $1
        DEC C
        IN E,(C)        ;Get the byte
        INC C
        LD A,D
        OUT (C),A       ;Say 'byte received'
        XOR 129
        LD D,A  ;Flip flags ready for next byte
        POP BC
        RET
;
;
; The end of the PDS download software.
;
; Now is a short routine to return to basic from the ASMSTRAD download
; software supplied with the system. Note that to run the download software
; you must use the following :
;
; LOAD "D" : CALL 40000
;
; When you assemble and download this program you will return to basic, to
; save to disk or tape use the following:
;
; SAVE "DLOAD",B,start address,114,start address
;
; Now it will be saved so it will auto run when RUN "DLOAD is typed.
;
;
        ORG START-3
        POP HL  ;Get rid of return to PDS software
        EI
        RET             ;Start interupts and return
;
;
;
        SEND COMPUTER1
        END

AMSTRAD.DL1 (long version, 374 bytes)

;   Amstrad long download software
;
;
;This download software can be used for assembling and download, and will
;work with all the monitor functions, such as trace, upload etc...It will
;not work with the Analyze command, which requires the DL2 software.
;Interupts are disabled. Jump to START the first time, this will setup all
;the ports. If you wish to enter the download software again, jump to
;MONITOR. The length of the code is 374 bytes.
;
;
        ORG 8000H
;
;
; Initial setup code
;
START   PUSH AF
        LD A,255
        LD BC,0FBEEH
        OUT (C),A
        OUT (C),A
        INC C
        OUT (C),A       ;Initial port setup
        LD C,0EDH
        OUT (C),A
        LD C,0EFH
        LD A,63
        OUT (C),A
        INC A
        LD (FLAGIO),A   ;Initial flags 0 - Input
        POP AF
;
; Now main part of download software
;
MONITOR DI              ;Interupts would corrupt the stack
        LD (ZHL),HL     ;Save HL
        LD (ZSP),SP     ;Save SP
        POP HL  ;Get 'return' address
        LD (ZPC),HL     ;Where I was called from
        LD SP,ZHL       ;Top of register block
        PUSH DE
        PUSH BC
        EXX
        PUSH HL
        PUSH DE
        PUSH BC ;All registers are saved for PDS
        PUSH IX
        PUSH IY
        PUSH AF
        LD A,I
        LD H,A
        LD A,R
        LD L,A
        PUSH HL
        EX AF,AF'
        PUSH AF
        LD D,0  ;D is the download flag
FLAGIO  EQU $-1
;
; Mainloop
;
MAINLOOP        CALL GETBYTE
        LD A,E
        CP 180  ;Download code into aabb, len=ccdd
        JZ DLOAD
        CP 186  ;Run code aa,bb,cc,dd
        JP Z,EXECUTE
        CP 184  ;Send register block to Apricot
        JP Z,SENDREG
        CP 185  ;Get register block from Apricot
        JP Z,GETREG
        CP 183  ;Select bank aa
        JZ SBANK
        CP 182  ;Upload code from aabb len=ccdd
        JZ UPLOAD
        CP 181  ;Execute code from aabb?
        JNZ MAINLOOP    ;Not recognised - keep looping.
;
; Function 181, Execute code from aabb
;
        CALL GETBYTE
        LD H,E
        CALL GETBYTE    ;Notice that the address is downloaded H then L
        LD L,E
        LD (EXEC+2),HL  ;Put NOP, CALL <xxxx> into execution buffer
        LD HL,0CD00H
        LD (EXEC),HL
        JP RUNIT
;
; Function 180, Download code into aabb, length=ccdd
;
DLOAD   CALL GETBYTE
        LD H,E
        CALL GETBYTE    ;Get start address of code
        LD L,E
        CALL GETBYTE
        LD B,E
        CALL GETBYTE    ;Get length of code
        LD C,E
DLOAD1  CALL GETBYTE
        LD (HL),E       ;Get and store bytes
        INC HL
        DEC BC
        LD A,B
        OR C
        JNZ DLOAD1
        JR MAINLOOP     ;Go back into main download loop
;
; Function 183, select bank aa
;
SBANK   CALL GETBYTE
        LD B,7FH        ;You may write your own routine here.
        LD C,E  ;You may corrupt everything except E
        OUT (C),C       ;This allows you to page in rom and ram
        JR MAINLOOP
;
; Function 184, upload register block to the main computer.
;
SENDREG LD HL,REGISTERS
        LD BC,26
        JR UPLOAD1      ;Upload the register block
;
; Function 185, download register block from the main computer.
;
GETREG  LD HL,REGISTERS
        LD BC,26
        JR DLOAD1       ;Download the register block
;
; Upload code, from aabb, length ccdd
;
UPLOAD  CALL GETBYTE
        LD H,E
        CALL GETBYTE    ;Get start address of code
        LD L,E
        CALL GETBYTE
        LD B,E
        CALL GETBYTE    ;Get length of code
        LD C,E
;
UPLOAD1 PUSH BC
        LD BC,0FBEDH
$0      IN A,(C)
        XOR D
        RRCA
        JC $0
        INC C
        LD A,255
        OUT (C),A       ;This swaps the PDS interface direction around
        INC A
        OUT (C),A       ;The Amstrad now transmitts to the Apricot
        LD A,D
        XOR 65
        LD D,A
        POP BC
;
$1      LD A,(HL)
        CALL SENDBYTE
        INC HL  ;Send the area of memory
        DEC BC
        LD A,B
        OR C
        JNZ $1
;
        DEC A
        LD BC,0FBEEH
        OUT (C),A
        OUT (C),A
        DEC C
        LD A,D
        XOR 64  ;Swap the ports back to normal
        OUT (C),A
        XOR 128
        LD D,A
;
        JP MAINLOOP
;
; Function 186, execute the next 4 bytes, and reenter monitor
;
EXECUTE CALL GETBYTE
        LD L,E
        CALL GETBYTE
        LD H,E
        LD (EXEC),HL
        CALL GETBYTE    ;Get the 4 bytes to be run
        LD L,E
        CALL GETBYTE    ;Store in execution buffer
        LD H,E
        LD (EXEC+2),HL
RUNIT   LD A,D
        LD (FLAGIO),A
        POP AF
        EX AF,AF'
        POP HL
        LD A,H
        LD I,A
        LD A,L
        LD R,A
        POP AF
        POP IY
        POP IX  ;Get all registers off stack
        POP BC
        POP DE
        POP HL
        EXX
        POP BC
        POP DE
        POP HL
        LD SP,(ZSP)
EXEC    DS 4            ;All code to be run is placed here
        JP MONITOR
;
; Get a byte from the main computer into E
;
GETBYTE PUSH BC
        LD BC,0FBEDH
$1      IN A,(C)
        XOR D           ;Wait for 'sent byte'
        RRCA
        JC $1
        DEC C
        IN E,(C)        ;Get the byte
        INC C
        LD A,D
        OUT (C),A       ;Set 'byte received'
        XOR 129
        LD D,A  ;Flip flags for next byte
        POP BC
        RET
;
; Send A to the main computer
;
SENDBYTE        PUSH BC
        LD BC,0FBECH
        OUT (C),A       ;Send the byte
        INC C
        LD A,D
        OUT (C),A       ;Set 'sent the byte'
        XOR 129
        LD D,A
$1      IN A,(C)
        XOR D           ;Wait for 'byte received'
        RRCA
        JNC $1
        POP BC
        RET
;
        DW 0,0  ;Uses two levels of stack
REGISTERS       DS 20           ;Other registers stored here
ZHL     DW 0            ;HL stored here
ZPC     DW 0            ;PC stored here
ZSP     DW 0            ;SP stored here
;
;
;
; The end of the PDS download software.
;
; Now is a short routine to return to basic from the ASMSTRAD download
; software supplied with the system. Note that to run the download software
; you must use the following :
;
; LOAD "D" : CALL 40000
;
; When you assemble and download this program you will return to basic, to
; save to disk or tape use the following:
;
; SAVE "DLOAD",B,start address,374,start address
;
; Now it will be saved so it will auto run when RUN "DLOAD is typed.
;
;
        ORG START-3
        EXEC $
        EI
        POP HL
        RET
;
;
;
        SEND COMPUTER1
        END

AMSTRAD.DL2 (interrupt driven)

;   This is the interupt driven download software for the Amstrad
;
; To use this software, insert a CALL to the routine PDSSETUP in the
; 'cold start' or 'once only' part of your program. Also insert a CALL
; to the routine MONITOR in your interupt routine. PDS corrupts HL,DE,BC
; and AF. The call to monitor must have HL containing the address where
; the interupt occured.
; You will now be able to use most of the monitor functions while your
; program is running and interupts enabled. Note that you cannot alter
; the registers or trace as this would not make sense under the interupts.
; The analyze command will also opperate now.
;
; Note that if you try and download programs, containing the PDS download
; software, chances are that you will crash the system as the download
; software contains self modifiying code that would get overwritten.
; To download programs just make sure you never download over the
; download software currently running.
;
; Below is the PDS download software and a short program that sets up the
; amstrad and returns you to basic, so you may modify memory while you
; are running basic programs.
; To run this, use the download software disk supplied and type :
;
; LOAD "D
; CALL 40000
;
; If you had used RUN"D you would not have been able to return to basic
; Now you can download the program
;
;
;
        ORG 39000
        EXEC $
;
; Setup interupts and return to basic
;
        CALL PDSSETUP   ;Initialize PDS software
        DI
        LD HL,(39H)
        LD (INTEND+1),HL        ;Redirect interupt vector
        LD HL,INTR
        LD (39H),HL
        EI
        POP HL  ;Remove PDS return to download software address
        RET
;
; End of example program
;
;
;
;
; Now the main PDS download software routines
;
;
; Initial setup code - only called once.
;
PDSSETUP        LD A,255
        LD BC,0FBEEH
        OUT (C),A
        OUT (C),A
        INC C
        OUT (C),A       ;Initial port setup
        LD C,0EDH
        OUT (C),A
        LD C,0EFH
        LD A,63
        OUT (C),A
        INC A
        LD (FLAGIO),A   ;Initial protocol flags, input
        RET
;
; An example interupt routine
;
INTR    LD (STKSTO+1),SP
        PUSH HL
        PUSH DE
STKSTO  LD HL,1
        LD E,(HL)
        INC HL  ;Get HL=old PC address
        LD D,(HL)
        EX DE,HL
        CALL MONITOR    ;Do download software
        POP DE
        POP HL  ;Now go back into AMSTRAD routines
INTEND  JP 1
;
;
; Call this address from your interupt routine
;
MONITOR PUSH AF
        PUSH BC ;Save all regs from your program
        PUSH DE
        PUSH HL
        LD D,0  ;D is the download flag
FLAGIO  EQU $-1
;
        LD BC,0FBEDH
        IN A,(C)
        XOR D           ;WAIT UNTIL GOT=I
        RRCA
        JC EXIT
        DEC C
        IN E,(C)        ;GET BYTE
        INC C
        LD A,D
        OUT (C),A       ;SET SEND=I
        XOR 129
        LD D,A  ;I=1-I (ready for next byte)
;
        LD A,E
        SUB 180
        JZ DLOAD
        DEC A
        JZ EXECUTE
        DEC A
        JZ UPLOAD
        DEC A
        JZ SBANK
        CP 4
        JZ ANALYZE
;
EXIT    LD A,D
        LD (FLAGIO),A
        POP HL
        POP DE  ;Return to your program
        POP BC
        POP AF
        RET
;
; Send PC address back to main computer
;
ANALYZE CALL PORTOUT
        LD A,L
        CALL SENDA
        LD A,H
        CALL SENDA
        CALL PORTIN
        JR EXIT
;
; Execute code from aaaa - does a jump note! (call would be silly from ints)
;
EXECUTE CALL GETA
        LD H,E
        CALL GETA       ;Notice that the address is downloaded H then L
        LD L,E
        JP (HL)
;
; Download code into aaaa, length=bbbb
;
DLOAD   CALL GETA
        LD H,E
        CALL GETA       ;Get start address
        LD L,E
        CALL GETA
        LD B,E
        CALL GETA       ;Get length of code
        LD C,E
DLOAD1  CALL GETA
        LD (HL),E       ;Get and store code
        INC HL
        DEC BC
        LD A,B
        OR C
        JNZ DLOAD1
        JR EXIT
;
; Upload code, from aaaa, length bbbb
;
UPLOAD  CALL GETA
        LD H,E
        CALL GETA       ;Get start address
        LD L,E
        CALL GETA
        LD B,E
        CALL GETA       ;Get length of code
        LD C,E
        CALL PORTOUT
$1      LD A,(HL)
        CALL SENDA
        INC HL  ;Send the area of memory
        DEC BC
        LD A,B
        OR C
        JNZ $1
        CALL PORTIN
        JP EXIT
;
; Function 183, select bank xx (This is different for each computer)
;
SBANK   CALL GETA
;
; HL, BC and A may be corrupted here
; Please write your own bank changing routine, for example it could just
; be LD BC,nnnn  then  OUT (C),A. Note that A contains the number of the
; bank, sent from the PDS BANK n command in the assembler
;
        JP EXIT
;
; Turn port direction TO main computer
;
PORTOUT PUSH BC
        LD BC,0FBEDH
$R      IN A,(C)
        XOR D
        RRCA
        JC $R
        INC C
        LD A,255
        OUT (C),A       ;This swaps the PDS interface direction around
        INC A
        OUT (C),A       ;The Spectrum now transmitts to the Apricot
        LD A,D
        XOR 65
        LD D,A
        POP BC
        RET
;
; Turn port direction FROM main computer
;
PORTIN  LD A,255
        LD BC,0FBEEH
        OUT (C),A
        OUT (C),A
        DEC C
        LD A,D
        XOR 64  ;Swap the ports round again
        OUT (C),A
        XOR 128
        LD D,A
        RET
;
; Get a byte from the APRICOT in E
;
GETA    PUSH BC
        LD BC,0FBEDH
$1      IN A,(C)
        XOR D           ;WAIT UNTIL GOT=I
        RRCA
        JC $1
        DEC C
        IN E,(C)        ;GET BYTE
        INC C
        LD A,D
        OUT (C),A       ;SET SEND=I
        XOR 129
        LD D,A  ;I=1-I (ready for next byte)
        POP BC
        RET
;
; Send A to the APRICOT
;
SENDA   PUSH BC
        LD BC,0FBECH
        OUT (C),A
        INC C
        LD A,D
        OUT (C),A
        XOR 129
        LD D,A
$1      IN A,(C)
        XOR D
        RRCA
        JNC $1
        POP BC
        RET
;
;
;
        SEND COMPUTER1
        END