diff options
| author | Jeff Armstrong <jeff@approximatrix.com> | 2026-10-25 17:42:06 -0400 |
|---|---|---|
| committer | Jeff Armstrong <jeff@approximatrix.com> | 2026-10-25 17:42:06 -0400 |
| commit | ebb2ff2af569d5822b70ee555a32d27cf7494816 (patch) | |
| tree | 7ac5e7b3fa73f7a8d996129086932ecce66374ad /src/cpxcom.asm | |
| download | kermit-80-ebb2ff2af569d5822b70ee555a32d27cf7494816.tar.gz kermit-80-ebb2ff2af569d5822b70ee555a32d27cf7494816.zip | |
Diffstat (limited to 'src/cpxcom.asm')
| -rw-r--r-- | src/cpxcom.asm | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/src/cpxcom.asm b/src/cpxcom.asm new file mode 100644 index 0000000..7c3034e --- /dev/null +++ b/src/cpxcom.asm @@ -0,0 +1,486 @@ +IF NOT lasm +.printx * CPXCOM.ASM * +ENDIF ; NOT lasm +; KERMIT - (Celtic for "FREE") +; +; This is the CP/M-80 implementation of the Columbia University +; KERMIT file transfer protocol. +; +; Version 4.0 +; +; Copyright June 1981,1982,1983,1984,1985 +; Columbia University +; +; Originally written by Bill Catchings of the Columbia University Center for +; Computing Activities, 612 W. 115th St., New York, NY 10025. +; +; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben, +; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many +; others. +; +; This file contains part common code required for most if not all +; systems. Specifiacally, SYSINIT, INIADR, MOVER, and DELAY to name +; the most important ones. +; +; revision history: +; +; edit 1, 21st July 1987 by OBSchou. Regretably, I have had to include +; some system dependent IFs, mainly for CRT, TORCH and OSI. Inclusion +; here means simpler family files later on. (Regrettably, the delay +; loop for APMMDM differs too.) +; +; Set the fuzzy timeout value. Range is 1 (VERY short) through 0ffffH to zero +; (maximum). The actual duration is a function of the loop length and the +; processor speed. For now, we'll make it zero for everybody, but feel free +; to change it for your system. +; [OBS] make it a little less than max, say 1000H. More useful. +fuzval EQU 1000H + +; +; System-dependent initialization +; Called once at program start. +sysinit: +; +; [13] Had to move this call to here, as the prtstr routine needs this +; before the config message is sent out. It has only been moved. +; + call iniadr ;Initialize the BIOS addresses + mvi c,gtiob ;Get current I/O byte + call bdos ;From CP/M + sta coniob ;Remember where console is + mvi c,getvnm ; get the BDOS version number (e.g. 22H, 31H) + call bdos + mov a,l + sta bdosvr ; and store it away for future reference + lxi d,cfgmsg ; "configured for " + call prtstr + lxi d,sysver ; get configuration we're configured for + call prtstr ; print it. +; +; If we're set up to do special terminal handling, say what kind +; of terminal we expect... (unless it's the generic 'crt') +IF termin + lxi d,witmsg ; " with " + call prtstr + lxi d,ttytyp ; terminal type + call prtstr +ENDIF;termin + call prcrlf ; print CR/LF +; +; now, to work... +; +; locate large buffer for multi-sector I/O +; What we want to do here is find the ccp. Space between ovlend and the ccp +; is available for buffering, except we don't want to use more than maxsec +; buffers (if we use too many, the remote end could time out while we're +; writing to disk). maxsec is system-dependent, but for now we'll just +; use 8Kbytes. If you get retransmissions and other protocol errors after +; transferring the first maxsec sectors, lower maxsec. + +maxsec EQU (8*1024)/bufsiz ; 8K / number of bytes per sector + + lxi h,ovlend ; get start of buffer + shld bufadr ; store in linkage section + mvi a,maxsec ; get size of buffer, in sectors + sta bufsec ; store that, too. + + call sysxin ; call system specific init code + + ret ; return from system-dependent routine + +bdosvr: ds 1 ; space to save the BDOS version number +IF NOT iobyt +coniob: ds 1 ; space to save copy of IO byte +ENDIF ;NOT iobyt +; +; This one is hopefully the last "improvement" in view of GENERIC +;Kermit. It uses for Character-I/O the BIOS-routines ( instead of the +;"normal" BDOS routines. What does it give us (hopefully) : More speed, +;higher chance of success ( I/O byte implemented in BIOS [if at all]), +;but no "extra" device handling - that's done by BDOS. +; +; How do we "get" the call-adresses? Location 0 has a JMP Warm-Boot +;in CP/M which points into the second location of the BIOS JMP-Vector. The +;next three locations of the JMP-Vector point to the CONSTAT,CONIN,CONOUT +;BIOS-routines. CONOUT wants the character in C. +; +;- Bernie Eiben + +iniadr: lhld 1 ;get BIOS Warmstart-address + lxi d,3 ;next adress is CONSTAT in BIOS + dad d + shld bconst+1 ;stuff it into the call-instruction + lxi d,3 ;next adress is CONIN in BIOS + dad d + shld bconin+1 ; + lxi d,3 ;next adress is CONOUT in BIOS + dad d + shld bcnout+1 + lxi d,3 ;next address is LIST in BIOS + dad d + shld blsout+1 + lxi d,10*3 ; get printer status routine + dad d + shld bprtst + ret ;And return + +bconst: jmp $-$ ;Call BIOS directly (filled in by iniadr) + +bconin: jmp $-$ ;Call BIOS directly (filled in by iniadr) + +bcnout: jmp $-$ ;Call BIOS directly (filled in by iniadr) + +blsout: jmp $-$ ; .... + +bprtst: jmp $-$ ; Call BIOS directly for printer status + +IF NOT apmmdm ; Shame about this, but the Apple needs a different delay +; +;[cjc] Delay routine. Called with time (hundredths of seconds) in A. +; The inner loop delays 1001 T-states, assuming no wait states are +; inserted; this is repeated CPUSPD times, for a total delay of just +; over 0.01 second. (CPUSPD should be set to the system clock rate, +; in units of 100KHz: for an unmodified Kaypro II, that's 25 for +; 2.5 MHz. Some enterprising soul could determine whether or not the +; Kaypro actually inserts a wait state on instruction fetch (a common +; practice); if so, the magic number at delay2 needs to be decreased. +; (We also neglect to consider time spent at interrupt level). +; +; called by: sendbr +; destroys BC + +delay: mvi c,cpuspd ; Number of times to wait 1000 T-states to + ; make .01 second delay +delay2: mvi b,70 ; Number of times to execute inner loop to + ; make 1000 T-state delay +delay3: dcr b ; 4 T-states (* 70 * cpuspd) + jnz delay3 ; 10 T-states (* 70 * cpuspd) + dcr c ; 4 T-states (* cpuspd) + jnz delay2 ; 10 T-states (* cpuspd) + ; total delay: ((14 * 70) + 14) * cpuspd + ; = 1001 * cpuspd + dcr a ; 4 T-states + jnz delay ; 10 T-states + ret ; grand total: ((1001 * cpuspd) + 14) * a +ENDIF ; NOT apmmdm +; +; +; Set up screen display for file transfer +; called with kermit version in DE +; +sysscr: push d ; save version for a bit + lxi d,outlin ; clear screen, position cursor + call prtstr ; do it + pop d ; get Kermit's version +IF NOT (osi OR crt) ; got cursor control? + call prtstr ; print it + mvi e,'[' ; open bracket + call outcon ; print it (close bracket is in outln2) + lxi d,sysver ; get name and version of system module + call prtstr + lxi d,outln2 ; yes, print field names + call prtstr + lda dbgflg ; is debugging enabled? + ora a + rz ; finished if no debugging + lxi d,outln3 ; set up debugging fields + call prtstr +ENDIF;NOT (osi OR crt) + ret +; +; Calculate free space for current drive +; returns value in HL +sysspc: + lda bdosvr ;cpm3's alloc vect may be in another bank + cpi 30H ;cpm3 or later? + jm cp2spc ;no: use cp/m 2 algorithm + lda fcb ;If no drive, get + ora a ; logged in drive + jz dir180 + dcr a ;FCB drive A=1 normalize to be A=0 + jmp dir18a + +dir180: mvi c,rddrv + call bdos +dir18a: mov e,a ;drive in e + mvi c,getfs ;get free space BDOS funct + call bdos ;returns free recs (3 bytes in buff..buff+2) + mvi b,3 ;conv recs to K by 3 bit shift +dir18b: xra a ;clear carry + mvi c,3 ;for 3 bytes + lxi h,buff+3 ;point to addr + 1 +dir18c: dcx h ;point to less sig. byte + mov a,m ;get byte + rar ;carry -> A -> carry + mov m,a ;put back byte + dcr c ;for all bytes (carry not mod) + jnz dir18c + dcr b ;shift 1 bit 3 times + jnz dir18b + mov e,m ;get least sig byte + inx h + mov d,m ;get most sig byte + xchg ;get K free in HL + ret + +; the rest are CP/M 2.2 systems, so use the alloc vector +cp2spc: mvi c,getalv ;Address of CP/M Allocation Vector + call bdos + xchg ;Get its length + lhld bmax + inx h + lxi b,0 ;Initialize Block count to zero +dir19: push d ;Save allocation address + ldax d + mvi e,8 ;set to process 8 blocks +dir20: ral ;Test bit + jc dir20a + inx b +dir20a: mov d,a ;Save bits + dcx h + mov a,l + ora h + jz dir21 ;Quit if out of blocks + mov a,d ;Restore bits + dcr e ;count down 8 bits + jnz dir20 ;do another bit + pop d ;Bump to next count of Allocation Vector + inx d + jmp dir19 ;process it + +dir21: pop d ;Clear Allocation vector from stack + mov l,c ;Copy block to 'HL' + mov h,b + lda bshiftf ;Get Block Shift Factor + sui 3 ;Convert from records to thousands + rz ;Skip shifts if 1K blocks +dir22: dad h ;Multiply blocks by 'K per Block' + dcr a + jnz dir22 + ret + +; +----|----|----|----|----|----|----|... +; 1 | +; 2 | Kermit-80 v4.0 [system] +; 3 | +; 4 |Number of packets: ____ +; 5 |Number of retries: ____ +; 6 |File name: ____________ +; 7 |<error>... +; 8 |<status>... +; 9 |RPack: ___(if debugging)... +; 10 | +; 11 |SPack: ___(if debugging)... +; 12 | +; 13 |Kermit-80 A:> (when finished) +; +; For the PX-8, the display looks like: +; 5 10 15 20 25 30 35 40 45 50 55 +; +----|----|----|----|----|----|----|----|----|----|----|----|---- +; 1 |Kermit-80 v4.05 [Epson PX-8] Number of retries: ____ +; 2 |Number of packets: ____ File name: ________.___ +; 3 |<error>... +; 4 |<status>... +; 5 |RPack: ___ (if debugging)... +; 6 | +; 7 |SPack: ___ (if debugging)... +; 8 | +; 9 |Kermit-80 A:> (when finished) +; + +IF NOT px8 ; [29] +nppos EQU 4*100h+20 +rtpos EQU 5*100h+20 +fnpos EQU 6*100h+12 +errlin EQU 7 +stlin EQU 8 +rplin EQU 9 +splin EQU 11 +prplin EQU 13 +ENDIF ; NOT px8 + +IF px8 +nppos EQU 2*100h+20 +rtpos EQU 1*100h+59 +fnpos EQU 2*100h+51 +errlin EQU 3 +stlin EQU 4 +rplin EQU 5 +splin EQU 7 +prplin EQU 9 +ENDIF ; px8 [29] + + +IF NOT (osi OR crt );[26] +scrnp: lxi b,nppos + jmp csrpos + +scrnrt: lxi b,rtpos + jmp csrpos + +scrfln: lxi b,fnpos + call csrpos +clreol: + lxi d,tk + jmp prtstr + +screrr: lxi b,errlin*100H+1 + call csrpos + jmp clreol + +scrst: lxi b,stlin*100H+1 + call csrpos + jmp clreol + +rppos: lxi b,rplin*100H+8 + call csrpos + jmp clreol + +sppos: lxi b,splin*100H+8 + call csrpos + jmp clreol + +; [29] Modify scrend to make the cursor line conditional on use of debugging +; This means that in most cases the entire file transfer will fit on PX-8 lcd +scrend: lda dbgflg + ora a + jz scr1nd + lxi b,prplin*100H+1 ; debugging in use [29] + jmp scr2nd +scr1nd: lxi b,rplin*100H+1 ; no debugging +scr2nd: call csrpos +clreos: lxi d,tj + jmp prtstr +; [29] and nop out the rest for now... +; +;scrend: lxi b,prplin*100H+1 +; call csrpos +;clreos: lxi d,tj +; jmp prtstr +ENDIF;NOT (osi OR crt ) [26] + + +IF osi OR crt ; no cursor control +scrnp: mvi e,' ' + jmp outcon + +scrnrt: mvi e,' ' + call outcon + mvi e,'%' + jmp outcon + +scrfln: +screrr: +scrst: +scrend: jmp prcrlf ;Print CR/LF [Toad Hall] + +rppos: lxi d,prpack + jmp prtstr + +sppos: lxi d,pspack + jmp prtstr +ENDIF;osi OR crt + +; Some frequently-used routines (duplicates of those in CPSMIT): +; prcrlf - output a CR/LF +; prtstr - output string in DE +; rskp - return, skipping over error return +prcrlf: lxi d,crlf +prtstr: +; [17] added this to avoid prtstr.. emulate function 9 call. +; Works on most machines. +IF (torch OR px8 OR z80mu) +; +; Modified print string as the CP/N (for Nut) system traps control +; characters in a function 9 call.. rot its cotton socks. + push h + push d + push b +prtst1: + ldax d + inx d + cpi '$' ; if a dollar then end of string + jz prtst2 + push d + mov e,a + mov c,a ; also to c if its via conout in BIOS + call outcon ; send it to the screen + pop d + jmp prtst1 + +prtst2: pop b + pop d + pop h + ret ; regs restored.. just in case +ENDIF ;(torch OR px8 OR z80mu) + +IF NOT (torch OR px8 or z80mu) ;ie any machine that can send ctrl chrs via dos call 9 + PUSH H + PUSH D + push b + mvi c,9 ; Dos call 9 (print a string) + call bdos + pop b + POP D + POP H + ret ; all done for good machines +ENDIF ;NOT (torch OR px8 OR z80mu) + +; +; rskp - return to calling address + 3. +rskp: pop h ; Get the return address + inx h ; Increment by three + inx h + inx h + pchl + +; Copy block of data +; source in HL, destination in DE, byte count in BC +; called by: cpxsys, mfname +; +mover: +;IF NOT z80 ; 8080's have to do it the hard way +;OBS assume its an 8080 for now - this will work on Z80s anyway. + mov a,m + stax d + inx h + inx d + dcx b + mov a,b + ora c + jnz mover +;ENDIF;NOT z80 +;IF z80 +; db 0EDh,0B0h ; Z80 LDIR instruction +;ENDIF;z80 + ret + +; +; Miscellaneous messages +; +crlf: db cr,lf,'$' +cfgmsg: db 'configured for $' +witmsg: db ' with $' ; Its included if we get here ('with terminal') + +IF NOT (osi OR crt OR px8) ; [29] got cursor control? +outln2: db ']',cr,lf,cr,lf,'Number of packets:' + db cr,lf,'Number of retries:' + db cr,lf,'File name:$' +ENDIF;NOT (osi OR crt OR px8) + +IF px8 ; [29] +outln2: db '] Number of retries:', cr, lf + db 'Number of packets: File name:$' +ENDIF ; px8 [29] + +IF NOT (osi OR crt) ; [29] +outln3: db cr,lf,cr,lf ; debugging messages + db cr,lf,'Rpack:' + db cr,lf ; Blank line in case of long packet + db cr,lf,'Spack:$' +ENDIF ; NOT (osi OR crt) [29] + +IF lasm +LINK CPXSWT.ASM +ENDIF ;lasm + |
