0001 0000 ; 0002 0000 ; PCGET - This CP/M program receives a file from a PC via a serial 0003 0000 ; port and writes it to a file on the CP/M system. The file transfer uses 0004 0000 ; the XMODEM protocol. 0005 0000 ; 0006 0000 ; Note this program is gutted from the Ward Christenson Modem program. 0007 0000 ; 0008 0000 ; Hacked together by Mike Douglas for the Altair 2SIO serial interface board. 0009 0000 ; Ver Date Desc 0010 0000 ; 1.0 11/7/12 Initial version 0011 0000 ; 1.1 2/20/14 Allow transfer to occur over 2SIO port B 0012 0000 ; 1.2 12/21/14 Send NAK immediately after file open to speed 0013 0000 ; up the start-up of file transfer (four second 0014 0000 ; delay otherwise). 0015 0000 ; 2.0 5/11/17 Update for CPUVille system 0016 0000 ; Serial Port Equates 0017 0000 0018 0000 SIOACR: .EQU 003H ;2SIO port A control register 0019 0000 SIOADR: .EQU 002H ;2SIO port A data register 0020 0000 SIOBCR: .EQU 012H ;2SIO port B control register 0021 0000 SIOBDR .EQU 013H ;2SIO port B data register 0022 0000 0023 0000 XMTMASK: .EQU 1 ;MASK TO ISOLATE XMIT READY BIT 0024 0000 XMTRDY: .EQU 1 ;VALUE WHEN READY 0025 0000 RCVMASK: .EQU 2 ;MASK TO ISOLATE RECEIVE READY BIT 0026 0000 RCVRDY: .EQU 2 ;BIT ON WHEN READY 0027 0000 0028 0000 ; Transfer related equates 0029 0000 0030 0000 SOH: .EQU 1 0031 0000 EOT: .EQU 4 0032 0000 ACK: .EQU 6 0033 0000 NAK: .EQU 15H 0034 0000 CTRLC: .EQU 3 ;Control-C 0035 0000 LF: .EQU 10 0036 0000 CR: .EQU 13 0037 0000 0038 0100 .ORG 100H 0039 0100 0040 0100 ; Verify a file name was specified 0041 0100 0042 0100 3A 5D 00 lda PARAM1 ;A=1st character of parameter 1 0043 0103 FE 20 cpi ' ' ;make sure something entered 0044 0105 C2 11 01 jnz doXfer 0045 0108 11 E2 02 lxi d,mHelp ;display usage message 0046 010B 0E 09 mvi c,PRINT 0047 010D CD 05 00 call BDOS 0048 0110 C9 ret ;return to CPM 0049 0111 0050 0111 0051 0111 ; doXfer - Switch to local stack and do the transfer 0052 0111 0053 0111 doXfer: 0054 0111 11 C0 02 lxi d,mSendA ;port a send message 0055 0114 21 00 00 LXI H,0 ;HL=0 0056 0117 39 DAD SP ;HL=STACK FROM CP/M 0057 0118 22 70 03 SHLD STACK ;..SAVE IT 0058 011B 31 70 03 LXI SP,STACK ;SP=MY STACK 0059 011E AF xra a 0060 011F 32 73 03 sta SECTNO ;init sector number to zero 0061 0122 CD BB 02 CALL INIT_ACIA ;MASTER RESET THE ACIA 0062 0125 0E 09 MVI C,PRINT ;print the send message 0063 0127 CD 05 00 CALL BDOS ;PRINT ID MESSAGE 0064 012A 0065 012A ; GOBBLE UP GARBAGE CHARS FROM THE LINE 0066 012A 0067 012A 06 01 purge: MVI B,1 ;times out after 1 second if no data 0068 012C CD 7D 02 CALL RECV 0069 012F DA 3A 01 jc RECEIVE_FILE ;line is clear, go receive the file 0070 0132 FE 03 cpi CTRLC ;exit if abort requested 0071 0134 CA 2F 03 jz abort 0072 0137 C3 2A 01 jmp purge 0073 013A ; 0074 013A ;**************RECEIVE FILE**************** 0075 013A ; 0076 013A RECEIVE_FILE: 0077 013A CD 18 02 CALL ERASE_OLD_FILE 0078 013D CD 2B 02 CALL MAKE_NEW_FILE 0079 0140 3E 15 MVI A,NAK 0080 0142 CD AB 02 CALL SEND ;SEND NAK 0081 0145 0082 0145 RECV_LOOP: 0083 0145 RECV_HDR: 0084 0145 06 03 MVI B,3 ;3 SEC TIMEOUT 0085 0147 CD 7D 02 CALL RECV 0086 014A D2 5D 01 JNC RHNTO ;NO TIMEOUT 0087 014D 0088 014D RECV_HDR_TIMEOUT: 0089 014D RECV_SECT_ERR: ;PURGE THE LINE OF INPUT CHARS 0090 014D 06 01 MVI B,1 ;1 SEC W/NO CHARS 0091 014F CD 7D 02 CALL RECV 0092 0152 D2 4D 01 JNC RECV_SECT_ERR ;LOOP UNTIL SENDER DONE 0093 0155 3E 15 MVI A,NAK 0094 0157 CD AB 02 CALL SEND ;SEND NAK 0095 015A C3 45 01 JMP RECV_HDR 0096 015D 0097 015D ;GOT CHAR - MUST BE SOH OR CTRL-C TO ABORT 0098 015D 0099 015D FE 01 RHNTO: CPI SOH 0100 015F CA 6F 01 JZ GOT_SOH 0101 0162 FE 03 cpi CTRLC ;control-c to abort? 0102 0164 CA 2F 03 jz abort 0103 0167 FE 04 CPI EOT 0104 0169 CA EC 01 JZ GOT_EOT 0105 016C C3 4D 01 JMP RECV_SECT_ERR 0106 016F 0107 016F GOT_SOH: 0108 016F 06 01 MVI B,1 0109 0171 CD 7D 02 CALL RECV 0110 0174 DA 4D 01 JC RECV_HDR_TIMEOUT 0111 0177 57 MOV D,A ;D=BLK # 0112 0178 06 01 MVI B,1 0113 017A CD 7D 02 CALL RECV ;GET CMA'D SECT # 0114 017D DA 4D 01 JC RECV_HDR_TIMEOUT 0115 0180 2F CMA 0116 0181 BA CMP D ;GOOD SECTOR #? 0117 0182 CA 88 01 JZ RECV_SECTOR 0118 0185 C3 4D 01 JMP RECV_SECT_ERR 0119 0188 0120 0188 ; Receive Sector 0121 0188 0122 0188 RECV_SECTOR: 0123 0188 7A MOV A,D ;GET SECTOR # 0124 0189 32 72 03 STA RSECTNO 0125 018C 0E 00 MVI C,0 ;INIT CKSUM 0126 018E 21 80 00 LXI H,80H ;POINT TO BUFFER 0127 0191 RECV_CHAR: 0128 0191 06 01 MVI B,1 ;1 SEC TIMEOUT 0129 0193 CD 7D 02 CALL RECV ;GET CHAR 0130 0196 DA 4D 01 JC RECV_HDR_TIMEOUT 0131 0199 77 MOV M,A ;STORE CHAR 0132 019A 2C INR L ;DONE? 0133 019B C2 91 01 JNZ RECV_CHAR 0134 019E 0135 019E ;VERIFY CHECKSUM 0136 019E 0137 019E 51 MOV D,C ;SAVE CHECKSUM 0138 019F 06 01 MVI B,1 ;TIMEOUT 0139 01A1 CD 7D 02 CALL RECV ;GET CHECKSUM 0140 01A4 DA 4D 01 JC RECV_HDR_TIMEOUT 0141 01A7 BA CMP D ;CHECK 0142 01A8 C2 4D 01 JNZ RECV_SECT_ERR 0143 01AB ; 0144 01AB ;GOT A SECTOR, WRITE IF = 1+PREV SECTOR 0145 01AB ; 0146 01AB 3A 72 03 LDA RSECTNO 0147 01AE 47 MOV B,A ;SAVE IT 0148 01AF 3A 73 03 LDA SECTNO ;GET PREV 0149 01B2 3C INR A ;CALC NEXT SECTOR # 0150 01B3 B8 CMP B ;MATCH? 0151 01B4 C2 C9 01 JNZ DO_ACK 0152 01B7 0153 01B7 ;GOT NEW SECTOR - WRITE IT 0154 01B7 0155 01B7 11 5C 00 LXI D,FCB 0156 01BA 0E 15 MVI C,WRITE 0157 01BC CD 05 00 CALL BDOS 0158 01BF B7 ORA A 0159 01C0 C2 D1 01 JNZ WRITE_ERROR 0160 01C3 3A 72 03 LDA RSECTNO 0161 01C6 32 73 03 STA SECTNO ;UPDATE SECTOR # 0162 01C9 3E 06 DO_ACK: MVI A,ACK 0163 01CB CD AB 02 CALL SEND 0164 01CE C3 45 01 JMP RECV_LOOP 0165 01D1 0166 01D1 WRITE_ERROR: 0167 01D1 CD 70 02 CALL ERXIT 0168 01D4 0D0A0A457272 .DB 13,10,10,"Error Writing File",13,10,'$' 0168 01DA 6F722057726974696E672046696C650D0A24 0169 01EC 0170 01EC GOT_EOT: 0171 01EC 3E 06 MVI A,ACK ;ACK THE EOT 0172 01EE CD AB 02 CALL SEND 0173 01F1 11 5C 00 LXI D,FCB 0174 01F4 0E 10 MVI C,CLOSE 0175 01F6 CD 05 00 CALL BDOS 0176 01F9 3C INR A 0177 01FA C2 15 03 JNZ XFER_CPLT 0178 01FD CD 70 02 CALL ERXIT 0179 0200 0D0A0A457272 .DB 13,10,10,"Error Closing File",13,10,'$' 0179 0206 6F7220436C6F73696E672046696C650D0A24 0180 0218 ; 0181 0218 ERASE_OLD_FILE: 0182 0218 11 5C 00 LXI D,FCB 0183 021B 0E 11 MVI C,SRCHF ;SEE IF IT EXISTS 0184 021D CD 05 00 CALL BDOS 0185 0220 3C INR A ;FOUND? 0186 0221 C8 RZ ;NO, RETURN 0187 0222 11 5C 00 ERAY: LXI D,FCB 0188 0225 0E 13 MVI C,ERASE 0189 0227 CD 05 00 CALL BDOS 0190 022A C9 RET 0191 022B ; 0192 022B MAKE_NEW_FILE: 0193 022B 11 5C 00 LXI D,FCB 0194 022E 0E 16 MVI C,MAKE 0195 0230 CD 05 00 CALL BDOS 0196 0233 3C INR A ;FF=BAD 0197 0234 C0 RNZ ;OPEN OK 0198 0235 0199 0235 ;DIRECTORY FULL - CAN'T MAKE FILE 0200 0235 CD 70 02 CALL ERXIT 0201 0238 0D0A0A457272 .DB 13,10,10,"Error - Cannot Make File",13,10 0201 023E 6F72202D2043616E6E6F74204D616B652046696C650D0A 0202 0255 286469726563 .DB "(directory must be full)",13,10,'$' 0202 025B 746F7279206D7573742062652066756C6C290D0A24 0203 0270 ; 0204 0270 ; S U B R O U T I N E S 0205 0270 ; 0206 0270 ; - - - - - - - - - - - - - - - 0207 0270 0208 0270 ;EXIT PRINTING MESSAGE FOLLOWING 'CALL ERXIT' 0209 0270 0210 0270 D1 ERXIT: POP D ;GET MESSAGE 0211 0271 0E 09 MVI C,PRINT 0212 0273 CD 05 00 CALL BDOS ;PRINT MESSAGE 0213 0276 2A 70 03 EXIT: LHLD STACK ;GET ORIGINAL STACK 0214 0279 F9 SPHL ;RESTORE IT 0215 027A ; RET ;--EXIT-- TO CP/M 0216 027A C3 00 00 jmp 0 ; For interrupting system 0217 027D 0218 027D ; - - - - - - - - - - - - - - - 0219 027D ;MODEM RECV 0220 027D ;------------------------------------- 0221 027D D5 RECV: PUSH D ;SAVE 0222 027E MSEC: 0223 027E ; lxi d,(159 shl 8) ;49 cycle loop, 6.272ms/wrap * 159 = 1 second 0224 027E 11 00 9F lxi d,09F00H ;49 cycle loop, 6.272ms/wrap * 159 = 1 second 0225 0281 0226 0281 ; port A input 0227 0281 0228 0281 DB 03 MWTI: IN SIOACR 0229 0283 E6 02 ANI RCVMASK 0230 0285 FE 02 CPI RCVRDY 0231 0287 CA 99 02 JZ MCHAR ;GOT CHAR 0232 028A 1D DCR E ;COUNT DOWN 0233 028B C2 81 02 JNZ MWTI ;FOR TIMEOUT 0234 028E 15 DCR D 0235 028F C2 81 02 JNZ MWTI 0236 0292 05 DCR B ;DCR # OF SECONDS 0237 0293 C2 7E 02 JNZ MSEC 0238 0296 0239 0296 ;MODEM TIMED OUT RECEIVING 0240 0296 0241 0296 D1 POP D ;RESTORE D,E 0242 0297 37 STC ;CARRY SHOWS TIMEOUT 0243 0298 C9 RET 0244 0299 0245 0299 ;GOT MODEM CHAR 0246 0299 0247 0299 DB 02 MCHAR: IN SIOADR 0248 029B D1 POP D ;RESTORE DE 0249 029C F5 PUSH PSW ;CALC CHECKSUM 0250 029D 81 ADD C 0251 029E 4F MOV C,A 0252 029F F1 POP PSW 0253 02A0 B7 ORA A ;TURN OFF CARRY TO SHOW NO TIMEOUT 0254 02A1 C9 RET 0255 02A2 0256 02A2 0257 02A2 ;GOT MODEM CHAR 0258 02A2 0259 02A2 DB 13 MCHARB: IN SIOBDR 0260 02A4 D1 POP D ;RESTORE DE 0261 02A5 F5 PUSH PSW ;CALC CHECKSUM 0262 02A6 81 ADD C 0263 02A7 4F MOV C,A 0264 02A8 F1 POP PSW 0265 02A9 B7 ORA A ;TURN OFF CARRY TO SHOW NO TIMEOUT 0266 02AA C9 RET 0267 02AB 0268 02AB ; - - - - - - - - - - - - - - - 0269 02AB ;MODEM SEND CHAR ROUTINE 0270 02AB ;---------------------------------- 0271 02AB ; 0272 02AB F5 SEND: PUSH PSW ;CHECK IF MONITORING OUTPUT 0273 02AC 81 ADD C ;CALC CKSUM 0274 02AD 4F MOV C,A 0275 02AE 0276 02AE DB 03 SENDW: IN SIOACR 0277 02B0 E6 01 ANI XMTMASK 0278 02B2 FE 01 CPI XMTRDY 0279 02B4 C2 AE 02 JNZ SENDW 0280 02B7 F1 POP PSW ;GET CHAR 0281 02B8 D3 02 OUT SIOADR 0282 02BA C9 RET 0283 02BB 0284 02BB 0285 02BB ; INITITIALIZE THE SERIAL PORT 0286 02BB 0287 02BB INIT_ACIA: 0288 02BB ; mvi a,003h ;don't reset console port 0289 02BB ; out SIOACR 0290 02BB 3E 15 mvi a,015h ;rts on, 8N1 0291 02BD D3 03 out SIOACR 0292 02BF C9 ret 0293 02C0 0294 02C0 0295 02C0 53656E642074mSendA: .db "Send the file now using " 0295 02C6 68652066696C65206E6F77207573696E6720 0296 02D8 584D4F44454D .db "XMODEM...",'$' 0296 02DE 2E2E2E24 0297 02E2 0298 02E2 0D0A50434745mHelp: .db CR,LF,"PCGET 2.0 for CPUVille",CR,LF,LF 0298 02E8 5420322E3020666F722043505556696C6C650D0A0A 0299 02FD 55736167653A .db "Usage: PCGET file.ext",CR,LF 0299 0303 2050434745542066696C652E6578740D0A 0300 0314 24 .DB '$' 0301 0315 0302 0315 ;DONE - CLOSE UP SHOP 0303 0315 0304 0315 XFER_CPLT: 0305 0315 CD 70 02 CALL ERXIT 0306 0318 0D0A0A547261 .DB 13,10,10,"Transfer Complete",13,10,'$' 0306 031E 6E7366657220436F6D706C6574650D0A24 0307 032F 0308 032F CD 70 02 abort: call ERXIT 0309 0332 0D0A0A547261 .db 13,10,10,"Transfer Aborted",13,10,'$' 0309 0338 6E736665722041626F727465640D0A24 0310 0348 0311 0348 .DS 40 ;STACK AREA 0312 0370 STACK: .DS 2 ;STACK POINTER 0313 0372 RSECTNO: .DS 1 ;RECEIVED SECTOR NUMBER 0314 0373 SECTNO: .DS 1 ;CURRENT SECTOR NUMBER 0315 0374 0316 0374 ; 0317 0374 ; BDOS EQUATES (VERSION 2) 0318 0374 ; 0319 0374 RDCON .EQU 1 0320 0374 WRCON .EQU 2 0321 0374 PRINT .EQU 9 0322 0374 CONST .EQU 11 ;CONSOLE STAT 0323 0374 OPEN .EQU 15 ;0FFH=NOT FOUND 0324 0374 CLOSE .EQU 16 ; " " 0325 0374 SRCHF .EQU 17 ; " " 0326 0374 SRCHN .EQU 18 ; " " 0327 0374 ERASE .EQU 19 ;NO RET CODE 0328 0374 READ .EQU 20 ;0=OK, 1=EOF 0329 0374 WRITE .EQU 21 ;0=OK, 1=ERR, 2=?, 0FFH=NO DIR SPC 0330 0374 MAKE .EQU 22 ;0FFH=BAD 0331 0374 REN .EQU 23 ;0FFH=BAD 0332 0374 STDMA .EQU 26 0333 0374 BDOS .EQU 5 0334 0374 REIPL .EQU 0 0335 0374 FCB .EQU 5CH ;DEFAULT FCB 0336 0374 PARAM1 .EQU FCB+1 ;COMMAND LINE PARAMETER 1 IN FCB 0337 0374 PARAM2 .EQU PARAM1+16 ;COMMAND LINE PARAMETER 2 0338 0374 .END tasm: Number of errors = 0