0001 0000 ; 0002 0000 ; PCPUT - This CP/M program sends a file from the CP/M machine to a PC using 0003 0000 ; a serial port. The file transfer uses the XMODEM protocol. 0004 0000 ; 0005 0000 ; Note this program is gutted from the Ward Christenson Modem program. 0006 0000 ; 0007 0000 ; Hacked together by Mike Douglas for the Altair 2SIO serial interface board. 0008 0000 ; Ver Date Desc 0009 0000 ; 1.0 11/8/12 Initial version 0010 0000 ; 1.1 2/20/14 Allow transfer to occur over 2SIO port B 0011 0000 ; 1.2 12/21/14 Support CRC as well as checksum 0012 0000 ; 1.3 10/16/15 Set initial CRC flag state in software. Was 0013 0000 ; previously random from load. 0014 0000 ; 2.0 5/11/2017 Update for CPUVille system 0015 0000 ; 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 GET XMIT READY BIT 0024 0000 XMTRDY .EQU 1 ;VALUE WHEN READY 0025 0000 RCVMASK .EQU 2 ;MASK TO GET RECEIVE DATA AVAILABLE 0026 0000 RCVRDY .EQU 2 ;BIT ON WHEN READY 0027 0000 0028 0000 ERRLMT .EQU 5 ;MAX ALLOWABLE ERRORS 0029 0000 0030 0000 ;DEFINE ASCII CHARACTERS USED 0031 0000 0032 0000 SOH .EQU 1 0033 0000 EOT .EQU 4 0034 0000 ACK .EQU 6 0035 0000 NAK .EQU 15H 0036 0000 CTRLC .EQU 3 ;Control-C 0037 0000 LF .EQU 10 0038 0000 CR .EQU 13 0039 0000 0040 0100 .ORG 100h 0041 0100 0042 0100 ; Verify a file name was specified 0043 0100 0044 0100 3A 5D 00 lda PARAM1 ;A=1st character of parameter 1 0045 0103 FE 20 cpi ' ' ;make sure something entered 0046 0105 C2 11 01 jnz doXfer ;-found 0047 0108 11 25 03 lxi d,mHelp ;display usage message 0048 010B 0E 09 mvi c,PRINT 0049 010D CD 05 00 call BDOS 0050 0110 C9 ret ;return to CPM 0051 0111 0052 0111 0053 0111 0054 0111 ; doXfer - Switch to local stack and do the transfer 0055 0111 0056 0111 doXfer: 0057 0111 0058 0111 21 00 00 LXI H,0 ;HL=0 0059 0114 39 DAD SP ;HL=STACK FROM CP/M 0060 0115 22 D4 03 SHLD STACK ;..SAVE IT 0061 0118 31 D4 03 LXI SP,STACK ;SP=MY STACK 0062 011B AF xra a 0063 011C 32 D6 03 sta SECTNO ;initialize sector number to zero 0064 011F CD BB 01 CALL OPEN_FILE ;OPEN THE FILE 0065 0122 CD 28 02 CALL INIT_ACIA ;MASTER RESET THE ACIA 0066 0125 11 04 03 lxi d,mRcvA ;assume using port A 0067 0128 0E 09 sendA MVI C,PRINT 0068 012A CD 05 00 CALL BDOS ;PRINT ID MESSAGE 0069 012D 0070 012D ; GOBBLE UP GARBAGE CHARS FROM THE LINE 0071 012D 0072 012D 06 01 purge MVI B,1 ;times out after 1 second if no data 0073 012F CD EA 01 CALL RECV 0074 0132 DA 3D 01 jc lineClr ;line is clear, go wait for initial NAK 0075 0135 FE 03 cpi CTRLC ;exit if abort requested 0076 0137 CA CB 02 jz abort 0077 013A C3 2D 01 jmp purge 0078 013D 0079 013D ; WAIT FOR INITIAL NAK, THEN SEND THE FILE 0080 013D 0081 013D AF lineClr xra a ;clear crc flag = checksum mode 0082 013E 32 D8 03 sta crcFlag 0083 0141 06 01 WAITNAK MVI B,1 ;TIMEOUT DELAY 0084 0143 CD EA 01 CALL RECV 0085 0146 DA 41 01 JC WAITNAK 0086 0149 FE 03 cpi CTRLC ;abort requested? 0087 014B CA CB 02 jz abort 0088 014E FE 15 CPI NAK ;NAK RECEIVED? 0089 0150 CA 5B 01 jz SENDB ;yes, send file in checksum mode 0090 0153 FE 43 cpi 'C' ;'C' for CRC mode received? 0091 0155 C2 41 01 JNZ WAITNAK ;no, keep waiting 0092 0158 32 D8 03 sta crcFlag ;set CRC flag non-zero = true 0093 015B ;fall through to start the send operation 0094 015B ; 0095 015B ;*****************SEND A FILE*************** 0096 015B ; 0097 015B 0098 015B ;READ SECTOR, SEND IT 0099 015B 0100 015B CD 2D 02 SENDB CALL READ_SECTOR 0101 015E 3A D6 03 LDA SECTNO ;INCR SECT NO. 0102 0161 3C INR A 0103 0162 32 D6 03 STA SECTNO 0104 0165 0105 0165 ;SEND OR REPEAT SECTOR 0106 0165 0107 0165 3E 01 REPTB MVI A,SOH 0108 0167 CD 18 02 CALL SEND 0109 016A 3A D6 03 LDA SECTNO 0110 016D CD 18 02 CALL SEND 0111 0170 3A D6 03 LDA SECTNO 0112 0173 2F CMA 0113 0174 CD 18 02 CALL SEND 0114 0177 21 00 00 lxi h,0 ;init crc to zero 0115 017A 22 D9 03 shld crc16 0116 017D 4C mov c,h ;init checksum in c to zero 0117 017E 21 80 00 LXI H,80H 0118 0181 7E SENDC MOV A,M 0119 0182 CD 18 02 CALL SEND 0120 0185 CD E4 02 call calCrc ;update CRC 0121 0188 23 INX H 0122 0189 7C MOV A,H 0123 018A FE 01 CPI 1 ;DONE WITH SECTOR? 0124 018C C2 81 01 JNZ SENDC 0125 018F 0126 018F ; Send checksum or CRC based on crcFlag 0127 018F 0128 018F 3A D8 03 lda crcFlag ;crc or checksum? 0129 0192 B7 ora a 0130 0193 CA A2 01 jz sndCsum ;flag clear = checksum 0131 0196 3A DA 03 lda crc16+1 ;a=high byte of CRC 0132 0199 CD 18 02 call SEND ;send it 0133 019C 3A D9 03 lda crc16 ;a=low byte of crc 0134 019F C3 A3 01 jmp sndSkip ;skip next instruction 0135 01A2 79 sndCsum mov a,c ;send the checksum byte 0136 01A3 CD 18 02 sndSkip call SEND 0137 01A6 0138 01A6 ;GET ACK ON SECTOR 0139 01A6 0140 01A6 06 04 MVI B,4 ;WAIT 4 SECONDS MAX 0141 01A8 CD EA 01 CALL RECV 0142 01AB DA 65 01 JC REPTB ;TIMEOUT, SEND AGAIN 0143 01AE 0144 01AE ;NO TIMEOUT SENDING SECTOR 0145 01AE 0146 01AE FE 06 CPI ACK ;ACK RECIEVED? 0147 01B0 CA 5B 01 JZ SENDB ;..YES, SEND NEXT SECT 0148 01B3 FE 03 cpi CTRLC ;control-c to abort? 0149 01B5 CA CB 02 jz abort 0150 01B8 C3 65 01 JMP REPTB ;PROBABLY NAK - TRY AGAIN 0151 01BB ; 0152 01BB ; 0153 01BB ; S U B R O U T I N E S 0154 01BB ; 0155 01BB ;OPEN FILE 0156 01BB 11 5C 00 OPEN_FILE LXI D,FCB 0157 01BE 0E 0F MVI C,OPEN 0158 01C0 CD 05 00 CALL BDOS 0159 01C3 3C INR A ;OPEN OK? 0160 01C4 C0 RNZ ;GOOD OPEN 0161 01C5 CD DD 01 CALL ERXIT 0162 01C8 0D0A43616E6E .DB 13,10,"Cannot Open File",13,10,'$' 0162 01CE 6F74204F70656E2046696C650D0A24 0163 01DD 0164 01DD ; - - - - - - - - - - - - - - - 0165 01DD ;EXIT PRINTING MESSAGE FOLLOWING 'CALL ERXIT' 0166 01DD D1 ERXIT POP D ;GET MESSAGE 0167 01DE 0E 09 MVI C,PRINT 0168 01E0 CD 05 00 CALL BDOS ;PRINT MESSAGE 0169 01E3 2A D4 03 EXIT LHLD STACK ;GET ORIGINAL STACK 0170 01E6 F9 SPHL ;RESTORE IT 0171 01E7 ; RET ;--EXIT-- TO CP/M 0172 01E7 C3 00 00 jmp 0 0173 01EA 0174 01EA ; - - - - - - - - - - - - - - - 0175 01EA ;MODEM RECV 0176 01EA ;------------------------------------- 0177 01EA D5 RECV PUSH D ;SAVE 0178 01EB MSEC 0179 01EB ; LXI D,(159 shl 8) ;49 cycle loop, 6.272ms/wrap * 159 = 1 second 0180 01EB 11 00 9F lxi d,09F00H ;49 cycle loop, 6.272ms/wrap * 159 = 1 second 0181 01EE 0182 01EE ; port A input 0183 01EE 0184 01EE DB 03 MWTI IN SIOACR 0185 01F0 E6 02 ANI RCVMASK 0186 01F2 FE 02 CPI RCVRDY 0187 01F4 CA 06 02 JZ MCHAR ;GOT CHAR 0188 01F7 1D DCR E ;COUNT DOWN 0189 01F8 C2 EE 01 JNZ MWTI ;FOR TIMEOUT 0190 01FB 15 DCR D 0191 01FC C2 EE 01 JNZ MWTI 0192 01FF 05 DCR B ;DCR # OF SECONDS 0193 0200 C2 EB 01 JNZ MSEC 0194 0203 0195 0203 ;MODEM TIMED OUT RECEIVING 0196 0203 0197 0203 D1 POP D ;RESTORE D,E 0198 0204 37 STC ;CARRY SHOWS TIMEOUT 0199 0205 C9 RET 0200 0206 0201 0206 ;GOT MODEM CHAR 0202 0206 0203 0206 DB 02 MCHAR IN SIOADR 0204 0208 D1 POP D ;RESTORE DE 0205 0209 F5 PUSH PSW ;CALC CHECKSUM 0206 020A 81 ADD C 0207 020B 4F MOV C,A 0208 020C F1 POP PSW 0209 020D B7 ORA A ;TURN OFF CARRY TO SHOW NO TIMEOUT 0210 020E C9 RET 0211 020F 0212 020F 0213 020F 0214 020F ;GOT MODEM CHAR 0215 020F 0216 020F DB 13 MCHARB IN SIOBDR 0217 0211 D1 POP D ;RESTORE DE 0218 0212 F5 PUSH PSW ;CALC CHECKSUM 0219 0213 81 ADD C 0220 0214 4F MOV C,A 0221 0215 F1 POP PSW 0222 0216 B7 ORA A ;TURN OFF CARRY TO SHOW NO TIMEOUT 0223 0217 C9 RET 0224 0218 0225 0218 ; - - - - - - - - - - - - - - - 0226 0218 ;MODEM SEND CHAR ROUTINE 0227 0218 ;---------------------------------- 0228 0218 ; 0229 0218 F5 SEND PUSH PSW ;CHECK IF MONITORING OUTPUT 0230 0219 81 ADD C ;CALC CKSUM 0231 021A 4F MOV C,A 0232 021B 0233 021B ; Use port A 0234 021B 0235 021B DB 03 SENDW IN SIOACR 0236 021D E6 01 ANI XMTMASK 0237 021F FE 01 CPI XMTRDY 0238 0221 C2 1B 02 JNZ SENDW 0239 0224 F1 POP PSW ;GET CHAR 0240 0225 D3 02 OUT SIOADR 0241 0227 C9 RET 0242 0228 0243 0228 0244 0228 0245 0228 ; INITITIALIZE THE SERIAL PORT 0246 0228 0247 0228 INIT_ACIA: 0248 0228 0249 0228 ; mvi a,003h ;don't reset console port 0250 0228 ; out SIOACR 0251 0228 3E 15 mvi a,015h ;rts on, 8N1 0252 022A D3 03 out SIOACR 0253 022C C9 ret 0254 022D 0255 022D 0256 022D ; 0257 022D ;FILE READ ROUTINE 0258 022D ; 0259 022D READ_SECTOR: 0260 022D 11 5C 00 LXI D,FCB 0261 0230 0E 14 MVI C,READ 0262 0232 CD 05 00 CALL BDOS 0263 0235 B7 ORA A 0264 0236 C8 RZ 0265 0237 3D DCR A ;EOF? 0266 0238 C2 9A 02 JNZ RDERR 0267 023B 0268 023B ;EOF 0269 023B 0270 023B AF XRA A 0271 023C 32 D7 03 STA ERRCT 0272 023F 3E 04 SEOT MVI A,EOT 0273 0241 CD 18 02 CALL SEND 0274 0244 06 03 MVI B,3 ;WAIT 3 SEC FOR TIMEOUT 0275 0246 CD EA 01 CALL RECV 0276 0249 DA 97 02 JC EOTTOT ;EOT TIMEOUT 0277 024C FE 06 CPI ACK 0278 024E CA B1 02 JZ XFER_CPLT 0279 0251 0280 0251 ;ACK NOT RECIEVED 0281 0251 0282 0251 3A D7 03 EOTERR LDA ERRCT 0283 0254 3C INR A 0284 0255 32 D7 03 STA ERRCT 0285 0258 FE 05 CPI ERRLMT 0286 025A DA 3F 02 JC SEOT 0287 025D CD DD 01 CALL ERXIT 0288 0260 0D 0A 0A .db 13,10,10 0289 0263 4E6F2041434B .db "No ACK received on EOT, " 0289 0269 207265636569766564206F6E20454F542C20 0290 027B 627574207472 .db "but transfer is complete.",13,10,'$' 0290 0281 616E7366657220697320636F6D706C6574652E0D0A24 0291 0297 ; 0292 0297 ;TIMEOUT ON EOT 0293 0297 ; 0294 0297 C3 51 02 EOTTOT JMP EOTERR 0295 029A ; 0296 029A ;READ ERROR 0297 029A ; 0298 029A CD DD 01 RDERR CALL ERXIT 0299 029D 0D0A46696C65 .DB 13,10,"File Read Error",13,10,'$' 0299 02A3 2052656164204572726F720D0A24 0300 02B1 0301 02B1 ;DONE - CLOSE UP SHOP 0302 02B1 0303 02B1 XFER_CPLT: 0304 02B1 CD DD 01 CALL ERXIT 0305 02B4 0D0A0A547261 .DB 13,10,10,"Transfer Complete",13,10,'$' 0305 02BA 6E7366657220436F6D706C6574650D0A24 0306 02CB 0307 02CB CD DD 01 abort call ERXIT 0308 02CE 0D0A0A547261 .DB 13,10,10,"Transfer Aborted",13,10,'$' 0308 02D4 6E736665722041626F727465640D0A24 0309 02E4 0310 02E4 ;----------------------------------------------------------------------------- 0311 02E4 ; calCrc - update the 16-bit CRC with one more byte. 0312 02E4 ; (Copied from M. Eberhard) 0313 02E4 ; On Entry: 0314 02E4 ; a has the new byte 0315 02E4 ; crc16 is current except this byte 0316 02E4 ; On Exit: 0317 02E4 ; crc16 has been updated 0318 02E4 ; Trashes a,de 0319 02E4 ;----------------------------------------------------------------------------- 0320 02E4 C5 calCrc push b ;save bc, hl 0321 02E5 E5 push h 0322 02E6 2A D9 03 lhld crc16 ;get CRC so far 0323 02E9 AC xra h ;XOR into CRC top byte 0324 02EA 67 mov h,a 0325 02EB 01 21 10 lxi b,1021h ;bc=CRC16 polynomial 0326 02EE 16 08 mvi d,8 ;prepare to rotate 8 bits 0327 02F0 0328 02F0 ; do 8 bit shift/divide by CRC polynomial 0329 02F0 0330 02F0 29 cRotLp dad h ;16-bit shift 0331 02F1 D2 FA 02 jnc cClr ;skip if bit 15 was 0 0332 02F4 7C mov a,h ;CRC=CRC xor 1021H 0333 02F5 A8 xra b 0334 02F6 67 mov h,a 0335 02F7 7D mov a,l 0336 02F8 A9 xra c 0337 02F9 6F mov l,a 0338 02FA 15 cClr dcr d 0339 02FB C2 F0 02 jnz cRotLp ;rotate 8 times 0340 02FE 0341 02FE ; save the updated CRC and exit 0342 02FE 0343 02FE 22 D9 03 shld crc16 ;save updated CRC 0344 0301 E1 pop h ;restore hl, bc 0345 0302 C1 pop b 0346 0303 C9 ret 0347 0304 0348 0304 ; Messages 0349 0304 0350 0304 537461727420mRcvA .db "Start XMODEM file " 0350 030A 584D4F44454D2066696C6520 0351 0316 726563656976 .db "receive now...",'$' 0351 031C 65206E6F772E2E2E24 0352 0325 0353 0325 0D0A50435055mHelp .db CR,LF,"PCPUT 2.0 for CPUVille",CR,LF,LF 0353 032B 5420322E3020666F722043505556696C6C650D0A0A 0354 0340 5472616E736D .db "Transmits a file to a " 0354 0346 69747320612066696C6520746F206120 0355 0356 504320746872 .db "PC through an 88-2SIO",CR,LF 0355 035C 6F75676820616E2038382D3253494F0D0A 0356 036D 73657269616C .db "serial port using the " 0356 0373 20706F7274207573696E672074686520 0357 0383 584D4F44454D .db "XMODEM protocol.",CR,LF,LF 0357 0389 2070726F746F636F6C2E0D0A0A 0358 0396 55736167653A .db "Usage: PCPUT file.ext" 0358 039C 2050435055542066696C652E657874 0359 03AB 24 .db '$' 0360 03AC 0361 03AC 0362 03AC ; Data area 0363 03AC 0364 03AC .DS 40 ;STACK AREA 0365 03D4 STACK .DS 2 ;STACK POINTER 0366 03D6 SECTNO .DS 1 ;CURRENT SECTOR NUMBER 0367 03D7 ERRCT .DS 1 ;ERROR COUNT 0368 03D8 0369 03D8 crcFlag .ds 1 ;non-zero if using CRC 0370 03D9 crc16 .ds 2 ;computed crc 0371 03DB ; 0372 03DB ; BDOS EQUATES (VERSION 2) 0373 03DB ; 0374 03DB RDCON .EQU 1 0375 03DB WRCON .EQU 2 0376 03DB PRINT .EQU 9 0377 03DB CONST .EQU 11 ;CONSOLE STAT 0378 03DB OPEN .EQU 15 ;0FFH=NOT FOUND 0379 03DB CLOSE .EQU 16 ; " " 0380 03DB SRCHF .EQU 17 ; " " 0381 03DB SRCHN .EQU 18 ; " " 0382 03DB ERASE .EQU 19 ;NO RET CODE 0383 03DB READ .EQU 20 ;0=OK, 1=EOF 0384 03DB WRITE .EQU 21 ;0=OK, 1=ERR, 2=?, 0FFH=NO DIR SPC 0385 03DB MAKE .EQU 22 ;0FFH=BAD 0386 03DB REN .EQU 23 ;0FFH=BAD 0387 03DB STDMA .EQU 26 0388 03DB BDOS .EQU 5 0389 03DB REIPL .EQU 0 0390 03DB FCB .EQU 5CH ;SYSTEM FCB 0391 03DB PARAM1 .EQU FCB+1 ;COMMAND LINE PARAMETER 1 IN FCB 0392 03DB PARAM2 .EQU PARAM1+16 ;COMMAND LINE PARAMETER 2 0393 03DB .END tasm: Number of errors = 0