1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
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
|