; ; MFA Mikrocomputer version ; ; PCPUT - This CP/M program sends a file from a CP/M system to a PC ; via a serial The file transfer uses the XMODEM protocol. ; ; Note this program is gutted from the Ward Christenson Modem program. ; ; Hacked together by Mike Douglas for the VG Bitstreamer II board; ; Adaptation for the MFA system with Mike Douglas' help by Robert Flossmann ; ; Ver Date Desc ; --- -------- ----------------------------------------------- ; 1.0 10/7/15 Initial version. This code is almost the same ; as the Vector Graphic version as both use the ; same 8251 ports for serial I/O. ; ; Serial Port Equates 00A1 = SIOACR EQU 0A1h ;Port A Control Register (main serial) 00A0 = SIOADR EQU 0A0h ;Port A Data Register 0091 = SIOBCR EQU 091h ;Port B Control Register (secondary serial) 0090 = SIOBDR EQU 090h ;Port B Data Register 0001 = XMTMASK EQU 1 ;MASK TO ISOLATE XMIT READY BIT 0001 = XMTRDY EQU 1 ;VALUE WHEN READY 0002 = RCVMASK EQU 2 ;MASK TO ISOLATE RECEIVE READY BIT 0002 = RCVRDY EQU 2 ;VALUE WHEN READY 0005 = ERRLMT EQU 5 ;MAX ALLOWABLE ERRORS ;DEFINE ASCII CHARACTERS USED 0001 = SOH EQU 1 0004 = EOT EQU 4 0006 = ACK EQU 6 0015 = NAK EQU 15H 0003 = CTRLC EQU 3 ;Control-C 000A = LF EQU 10 000D = CR EQU 13 0100 org 100h ; Verify a file name was specified 0100 3A5D00 lda PARAM1 ;A=1st character of parameter 1 0103 FE20 cpi ' ' ;make sure file name present 0105 C21101 jnz haveFn ;yes, have a file name 0108 118D03 lxi d,mHelp ;display usage message 010B 0E09 mvi c,print 010D CD0500 call bdos 0110 C9 ret ;return to CPM ; See if port "B" specified (2nd parameter) 0111 06A0 haveFn mvi b,SIOADR ;assume port b not used 0113 3A6D00 lda PARAM2 ;A=1st character of parameter 2 0116 E65F ani 5fh ;force upper case 0118 FE42 cpi 'B' ;port b specified? 011A C21F01 jnz doXfer ;no, go do the transfer 011D 0690 mvi b,SIOBDR ;use port b ; doXfer - Switch to local stack and do the transfer 011F 78 doXfer mov a,b ;a=address of serial port to use 0120 322C02 sta rcvSDR ;modify IN instruction for data register 0123 324202 sta sndSDR ;modify OUT instruction for data register 0126 3C inr a ;a=serial port control register address 0127 321002 sta rcvSCR ;modify IN for control register in RECV 012A 323802 sta sndSCR ;modify IN for control register in SEND 012D 210000 LXI H,0 ;HL=0 0130 39 DAD SP ;HL=STACK FROM CP/M 0131 22A204 SHLD STACK ;..SAVE IT 0134 31A204 LXI SP,STACK ;SP=MY STACK 0137 AF xra a 0138 32A404 sta SECTNO ;initialize sector number to zero 013B CDDF01 CALL OPEN$FILE ;OPEN THE FILE 013E 111B03 lxi d,mRcvA ;assume using port A 0141 3A2C02 lda rcvSDR ;using port A or B? 0144 FEA0 cpi SIOADR 0146 CA4C01 jz sendA 0149 115303 lxi d,mRcvB ;using port B 014C 0E09 sendA MVI C,PRINT 014E CD0500 CALL BDOS ;PRINT ID MESSAGE ; GOBBLE UP GARBAGE CHARS FROM THE LINE 0151 0601 purge MVI B,1 ;times out after 1 second if no data 0153 CD0B02 CALL RECV 0156 DA6101 jc lineClr ;line is clear, go wait for initial NAK 0159 FE03 cpi ctrlc ;exit if abort requested 015B CAE202 jz abort 015E C35101 jmp purge ; WAIT FOR INITIAL NAK, THEN SEND THE FILE 0161 AF lineClr xra a ;clear crc flag = checksum mode 0162 32A604 sta crcFlag 0165 0601 WAITNAK MVI B,1 ;TIMEOUT DELAY 0167 CD0B02 CALL RECV 016A DA6501 JC WAITNAK 016D FE03 cpi ctrlc ;abort requested? 016F CAE202 jz abort 0172 FE15 CPI NAK ;NAK RECEIVED? 0174 CA7F01 jz SENDB ;yes, send file in checksum mode 0177 FE43 cpi 'C' ;'C' for CRC mode received? 0179 C26501 JNZ WAITNAK ;no, keep waiting 017C 32A604 sta crcFlag ;set CRC flag non-zero = true ;fall through to start the send operation ; ;*****************SEND A FILE*************** ; ;READ SECTOR, SEND IT 017F CD4402 SENDB CALL READ$SECTOR 0182 3AA404 LDA SECTNO ;INCR SECT NO. 0185 3C INR A 0186 32A404 STA SECTNO ;SEND OR REPEAT SECTOR 0189 3E01 REPTB MVI A,SOH 018B CD3402 CALL SEND 018E 3AA404 LDA SECTNO 0191 CD3402 CALL SEND 0194 3AA404 LDA SECTNO 0197 2F CMA 0198 CD3402 CALL SEND 019B 210000 lxi h,0 ;init crc to zero 019E 22A704 shld crc16 01A1 4C mov c,h ;init checksum in c to zero 01A2 218000 LXI H,80H 01A5 7E SENDC MOV A,M 01A6 CD3402 CALL SEND 01A9 CDFB02 call calCrc ;update CRC 01AC 23 INX H 01AD 7C MOV A,H 01AE FE01 CPI 1 ;DONE WITH SECTOR? 01B0 C2A501 JNZ SENDC ; Send checksum or CRC based on crcFlag 01B3 3AA604 lda crcFlag ;crc or checksum? 01B6 B7 ora a 01B7 CAC601 jz sndCsum ;flag clear = checksum 01BA 3AA804 lda crc16+1 ;a=high byte of CRC 01BD CD3402 call SEND ;send it 01C0 3AA704 lda crc16 ;a=low byte of crc 01C3 C3C701 jmp sndSkip ;skip next instruction 01C6 79 sndCsum mov a,c ;send the checksum byte 01C7 CD3402 sndSkip call SEND ;GET ACK ON SECTOR 01CA 0604 MVI B,4 ;WAIT 4 SECONDS MAX 01CC CD0B02 CALL RECV 01CF DA8901 JC REPTB ;TIMEOUT, SEND AGAIN ;NO TIMEOUT SENDING SECTOR 01D2 FE06 CPI ACK ;ACK RECIEVED? 01D4 CA7F01 JZ SENDB ;..YES, SEND NEXT SECT 01D7 FE03 cpi ctrlc ;control-c to abort? 01D9 CAE202 jz abort 01DC C38901 JMP REPTB ;PROBABLY NAK - TRY AGAIN ; ; ; S U B R O U T I N E S ; ;OPEN FILE 01DF 115C00 OPEN$FILE LXI D,FCB 01E2 0E0F MVI C,OPEN 01E4 CD0500 CALL BDOS 01E7 3C INR A ;OPEN OK? 01E8 C0 RNZ ;GOOD OPEN 01E9 CD0002 CALL ERXIT 01EC 0D0A43616E DB 13,10,'Can''t Open File',13,10,'$' ; - - - - - - - - - - - - - - - ;EXIT PRINTING MESSAGE FOLLOWING 'CALL ERXIT' 0200 D1 ERXIT POP D ;GET MESSAGE 0201 0E09 MVI C,PRINT 0203 CD0500 CALL BDOS ;PRINT MESSAGE 0206 2AA204 EXIT LHLD STACK ;GET ORIGINAL STACK 0209 F9 SPHL ;RESTORE IT 020A C9 RET ;--EXIT-- TO CP/M ; - - - - - - - - - - - - - - - ;MODEM RECV ;------------------------------------- 020B D5 RECV PUSH D ;SAVE 020C 11007C MSEC lxi d,(124 shl 8) ;63 cycles, 8.064ms/wrap*124 = 1 sec 0210 = rcvSCR equ $+1 ;address of I/O port for the following IN 020F DBA1 MWTI IN SIOACR ;(10) 0211 E602 ANI RCVMASK ;(7) 0213 FE02 CPI RCVRDY ;(7) 0215 CA2B02 JZ MCHAR ;(10) GOT CHAR ; no character present, decrement timeout 0218 FE00 cpi 0 ;(7) waste some time 021A FE00 cpi 0 ;(7) waste some time 021C 1D DCR E ;(5) COUNT DOWN 021D C20F02 JNZ MWTI ;(10) FOR TIMEOUT 0220 15 DCR D ;do msb every 256th time 0221 C20F02 JNZ MWTI 0224 05 DCR B ;DCR # OF SECONDS 0225 C20C02 JNZ MSEC ;MODEM TIMED OUT RECEIVING 0228 D1 POP D ;RESTORE D,E 0229 37 STC ;CARRY SHOWS TIMEOUT 022A C9 RET ;GOT MODEM CHAR 022C = rcvSDR equ $+1 ;address of I/O port for the following IN 022B DBA0 MCHAR IN SIOADR 022D D1 POP D ;RESTORE DE 022E F5 PUSH PSW ;CALC CHECKSUM 022F 81 ADD C 0230 4F MOV C,A 0231 F1 POP PSW 0232 B7 ORA A ;TURN OFF CARRY TO SHOW NO TIMEOUT 0233 C9 RET ; - - - - - - - - - - - - - - - ;MODEM SEND CHAR ROUTINE ;---------------------------------- ; 0234 F5 SEND PUSH PSW ;CHECK IF MONITORING OUTPUT 0235 81 ADD C ;CALC CKSUM 0236 4F MOV C,A 0238 = sndSCR equ $+1 ;address of I/O port for the following IN 0237 DBA1 SENDW IN SIOACR 0239 E601 ANI XMTMASK 023B FE01 CPI XMTRDY 023D C23702 JNZ SENDW 0240 F1 POP PSW ;GET CHAR 0242 = sndSDR equ $+1 ;address of I/O port for the following IN 0241 D3A0 OUT SIOADR 0243 C9 RET ; ;FILE READ ROUTINE ; READ$SECTOR: 0244 115C00 LXI D,FCB 0247 0E14 MVI C,READ 0249 CD0500 CALL BDOS 024C B7 ORA A 024D C8 RZ 024E 3D DCR A ;EOF? 024F C2B102 JNZ RDERR ;EOF 0252 AF XRA A 0253 32A504 STA ERRCT 0256 3E04 SEOT MVI A,EOT 0258 CD3402 CALL SEND 025B 0603 MVI B,3 ;WAIT 3 SEC FOR TIMEOUT 025D CD0B02 CALL RECV 0260 DAAE02 JC EOTTOT ;EOT TIMEOUT 0263 FE06 CPI ACK 0265 CAC802 JZ XFER$CPLT ;ACK NOT RECIEVED 0268 3AA504 EOTERR LDA ERRCT 026B 3C INR A 026C 32A504 STA ERRCT 026F FE05 CPI ERRLMT 0271 DA5602 JC SEOT 0274 CD0002 CALL ERXIT 0277 0D0A0A db 13,10,10 027A 4E6F204143 db 'No ACK received on EOT, but transfer is complete.',13,10,'$' ; ;TIMEOUT ON EOT ; 02AE C36802 EOTTOT JMP EOTERR ; ;READ ERROR ; 02B1 CD0002 RDERR CALL ERXIT 02B4 0D0A46696C DB 13,10,'File Read Error',13,10,'$' ;DONE - CLOSE UP SHOP XFER$CPLT: 02C8 CD0002 CALL ERXIT 02CB 0D0A0A5472 DB 13,10,10,'Transfer Complete',13,10,'$' 02E2 CD0002 abort call erxit 02E5 0D0A0A5472 DB 13,10,10,'Transfer Aborted',13,10,'$' ;----------------------------------------------------------------------------- ; calCrc - update the 16-bit CRC with one more byte. ; (Copied from M. Eberhard) ; On Entry: ; a has the new byte ; crc16 is current except this byte ; On Exit: ; crc16 has been updated ; Trashes a,de ;----------------------------------------------------------------------------- 02FB C5 calCrc push b ;save bc, hl 02FC E5 push h 02FD 2AA704 lhld crc16 ;get CRC so far 0300 AC xra h ;XOR into CRC top byte 0301 67 mov h,a 0302 012110 lxi b,1021h ;bc=CRC16 polynomial 0305 1608 mvi d,8 ;prepare to rotate 8 bits ; do 8 bit shift/divide by CRC polynomial 0307 29 cRotLp dad h ;16-bit shift 0308 D21103 jnc cClr ;skip if bit 15 was 0 030B 7C mov a,h ;CRC=CRC xor 1021H 030C A8 xra b 030D 67 mov h,a 030E 7D mov a,l 030F A9 xra c 0310 6F mov l,a 0311 15 cClr dcr d 0312 C20703 jnz cRotLp ;rotate 8 times ; save the updated CRC and exit 0315 22A704 shld crc16 ;save updated CRC 0318 E1 pop h ;restore hl, bc 0319 C1 pop b 031A C9 ret ;----------------------------------------- ; messages ;----------------------------------------- 031B 5374617274mRcvA db 'Start XMODEM file receive on Console Port (0xA0) now...$' 0353 5374617274mRcvB db 'Start XMODEM file receive on Secondary Port (0x90) now...$' 038D 0D0A504350mHelp db CR,LF,'PCPUT Ver 1.0 for MFA Mikrocomputer',CR,LF,LF 03B5 5472616E73 db 'Transmits a file to a PC through a serial port',CR,LF 03E5 7573696E67 db 'using the XMODEM protocol.',CR,LF,LF 0402 5573616765 db 'Usage: PCPUT file.ext [B]',CR,LF 041D 202020436F db ' Console serial port at 0xA0 used by default',CR,LF 044D 2020205370 db ' Specify B to use secondary port at 0x90',CR,LF,'$' ; Data Area 047A DS 40 ;STACK AREA 04A2 STACK DS 2 ;STACK POINTER 04A4 SECTNO DS 1 ;CURRENT SECTOR NUMBER 04A5 ERRCT DS 1 ;ERROR COUNT 04A6 crcFlag ds 1 ;non-zero if using CRC 04A7 crc16 ds 2 ;computed crc ; ; BDOS EQUATES (VERSION 2) ; 0001 = RDCON EQU 1 0002 = WRCON EQU 2 0009 = PRINT EQU 9 000B = CONST EQU 11 ;CONSOLE STAT 000F = OPEN EQU 15 ;0FFH=NOT FOUND 0010 = CLOSE EQU 16 ; " " 0011 = SRCHF EQU 17 ; " " 0012 = SRCHN EQU 18 ; " " 0013 = ERASE EQU 19 ;NO RET CODE 0014 = READ EQU 20 ;0=OK, 1=EOF 0015 = WRITE EQU 21 ;0=OK, 1=ERR, 2=?, 0FFH=NO DIR SPC 0016 = MAKE EQU 22 ;0FFH=BAD 0017 = REN EQU 23 ;0FFH=BAD 001A = STDMA EQU 26 0005 = BDOS EQU 5 0000 = REIPL EQU 0 005C = FCB EQU 5CH ;SYSTEM FCB 005D = PARAM1 EQU FCB+1 ;COMMAND LINE PARAMETER 1 IN FCB 006D = PARAM2 EQU PARAM1+16 ;COMMAND LINE PARAMETER 2 04A9 END