-
Notifications
You must be signed in to change notification settings - Fork 27
/
bdos.asm
2973 lines (2786 loc) · 65.6 KB
/
bdos.asm
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
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; Reformatted and converted for cross-assembly by Macro Assembler AS
; Eric Smith <[email protected]> 2018-01-24
; from original source os3bdos.asm from
; http://www.cpm.z80.de/download/cpm2-plm.zip
; includes Digital Research CP/M V2.2 Patch 01 (cpm22pat.01) from
; http://www.cpm.z80.de/download/cpm22pat.zip
; Changes:
; multiple instructions per line split to separate lines
; dollar sign in labels replaced by underscore
; dollar sign (as digit separator) in binary constants removed
; no colons for labels for equates
; single quotes around strings replaced with double quotes
; true and false replaced with _true and _false
; eliminated equates for 8080 registers, added comments introduced with %
; replaced "not", "and" operators with "~", "&"
; removed empty comments
; added ifdef origin to allow origin to be specified from command line
; added commments about serial number
.cpu 8080
patch1 equ 1
title "Bdos Interface, Bdos, Version 2.2 Feb, 1980"
;*****************************************************************
;*****************************************************************
;** **
;** B a s i c D i s k O p e r a t i n g S y s t e m **
;** I n t e r f a c e M o d u l e **
;** **
;*****************************************************************
;*****************************************************************
;
; Copyright (c) 1978, 1979, 1980
; Digital Research
; Box 579, Pacific Grove
; California
;
;
; 20 january 1980
;
;
on equ 0ffffh
off equ 00000h
test equ off
ifdef origin
org origin
else
if test
org 0dc00h
else
org 0800h
endif
endif
; bios value defined at end of module
ssize equ 24 ;24 level stack
; low memory locations
reboot equ 0000h ;reboot system
ioloc equ 0003h ;i/o byte location
bdosa equ 0006h ;address field of jmp BDOS
; bios access constants
bootf set bios+3*0 ;cold boot function
wbootf set bios+3*1 ;warm boot function
constf set bios+3*2 ;console status function
coninf set bios+3*3 ;console input function
conoutf set bios+3*4 ;console output function
listf set bios+3*5 ;list output function
punchf set bios+3*6 ;punch output function
readerf set bios+3*7 ;reader input function
homef set bios+3*8 ;disk home function
seldskf set bios+3*9 ;select disk function
settrkf set bios+3*10 ;set track function
setsecf set bios+3*11 ;set sector function
setdmaf set bios+3*12 ;set dma function
readf set bios+3*13 ;read disk function
writef set bios+3*14 ;write disk function
liststf set bios+3*15 ;list status function
sectran set bios+3*16 ;sector translate
; equates for non graphic characters
ctlc equ 03h ;control c
ctle equ 05h ;physical eol
ctlh equ 08h ;backspace
ctlp equ 10h ;prnt toggle
ctlr equ 12h ;repeat line
ctls equ 13h ;stop/start screen
ctlu equ 15h ;line delete
ctlx equ 18h ;=ctl-u
ctlz equ 1ah ;end of file
rubout equ 7fh ;char delete
tab equ 09h ;tab char
cr equ 0dh ;carriage return
lf equ 0ah ;line feed
ctl equ 5eh ;up arrow
; serial number (not documented in original DRI source file)
db 0 ; OEM number, low byte
db 0 ; CP/M version, 16h = 2.2
db 0 ; OEM number, high byte
db 0,0,0 ; serial number, big-endian
; enter here from the user's program with function number in c,
; and information address in d,e
jmp bdose ;past parameter block
; ************************************************
; *** relative locations 0009 - 000e ***
; ************************************************
pererr: dw persub ;permanent error subroutine
selerr: dw selsub ;select error subroutine
roderr: dw rodsub ;ro disk error subroutine
roferr: dw rofsub ;ro file error subroutine
bdose: ;arrive here from user programs
xchg ;info=DE, DE=info
shld info
xchg
mov a,e ;linfo = low(info) - don't equ
sta linfo
lxi h,0 ;return value defaults to 0000
shld aret
;save user's stack pointer, set to local stack
dad sp ;entsp = stackptr
shld entsp
lxi sp,lstack ;local stack setup
xra a ;fcbdsk,resel=false
sta fcbdsk
sta resel
lxi h,goback ;return here after all functions
push h ;jmp goback equivalent to ret
mov a,c ;skip if invalid #
cpi nfuncs
rnc
mov c,e ;possible output character to C
lxi h,functab ;DE=func, HL=.ciotab
mov e,a
mvi d,0
dad d ;DE=functab(func)
dad d
mov e,m
inx h
mov d,m
lhld info ;info in DE for later xchg
xchg ;dispatched
pchl
; dispatch table for functions
functab:
dw wbootf, func1, func2, func3
dw punchf, listf, func6, func7
dw func8, func9, func10,func11
diskf equ ($-functab)/2 ;disk funcs
dw func12,func13,func14,func15
dw func16,func17,func18,func19
dw func20,func21,func22,func23
dw func24,func25,func26,func27
dw func28,func29,func30,func31
dw func32,func33,func34,func35
dw func36,func37,func38,func39
dw func40
nfuncs equ ($-functab)/2
; error subroutines
persub: ;report permanent error
lxi h,permsg ;to report the error
call errflg
cpi ctlc ;reboot if response is ctlc
jz reboot
ret ;and ignore the error
selsub: ;report select error
lxi h,selmsg ;wait console before boot
jmp wait_err
;
rodsub: ;report write to read/only disk
lxi h,rodmsg ;wait console
jmp wait_err
;
rofsub: ;report read/only file
lxi h,rofmsg ;drop through to wait for console
;
wait_err:
;wait for response before boot
call errflg
jmp reboot
; error messages
dskmsg: db "Bdos Err On "
dskerr: db " : $" ;filled in by errflg
permsg: db "Bad Sector$"
selmsg: db "Select$"
rofmsg: db "File "
rodmsg: db "R/O$"
errflg:
;report error to console, message address in HL
push h ;stack mssg address, new line
call crlf
lda curdsk ;current disk name
adi 'A'
sta dskerr
lxi b,dskmsg ;the error message
call print
pop b ;error mssage tail
call print
;jmp conin ;to get the input character
;(drop through to conin)
;ret
; console handlers
conin:
;read console character to A
lxi h,kbchar
mov a,m
mvi m,0
ora a
rnz
;no previous keyboard character ready
jmp coninf ;get character externally
;ret
conech:
;read character with echo
call conin ;echo character?
call echoc
rc
;character must be echoed before return
push psw
mov c,a
call tabout
pop psw
ret ;with character in A
echoc:
;echo character if graphic
;cr, lf, tab, or backspace
cpi cr ;carriage return?
rz
cpi lf ;line feed?
rz
cpi tab ;tab?
rz
cpi ctlh ;backspace?
rz
cpi ' ' ;carry set if not graphic
ret
conbrk: ;check for character ready
lda kbchar ;skip if active kbchar
ora a
jnz conb1
;no active kbchar, check external break
call constf ;return if no char ready
ani 1
rz
;character ready, read it
call coninf ;to A
cpi ctls ;check stop screen function
jnz conb0
;found ctls, read next character
call coninf ;to A
cpi ctlc ;ctlc implies re-boot
jz reboot
;not a reboot, act as if nothing has happened
xra a ;with zero in accumulator
ret
conb0: ;character in accum, save it
sta kbchar
conb1: ;return with true set in accumulator
mvi a,1
ret
conout:
;compute character position/write console char from C
;compcol = true if computing column position
lda compcol
ora a
jnz compout
;write the character, then compute the column
;write console character from C
push b ;check for screen stop function
call conbrk
pop b ;recall/save character
push b
call conoutf ;externally, to console
pop b ;recall/save character
push b
;may be copying to the list device
lda listcp ;to printer, if so
ora a
cnz listf
pop b ;recall the character
compout:
mov a,c ;recall the character
;and compute column position
lxi h,column ;A = char, HL = .column
cpi rubout ;no column change if nulls
rz
inr m ;column = column + 1
cpi ' ' ;return if graphic
rnc
;not graphic, reset column position
dcr m ;column = column - 1
mov a,m ;return if at zero
ora a
rz
;not at zero, may be backspace or end line
mov a,c ;character back to A
cpi ctlh
jnz notbacksp
;backspace character
dcr m ;column = column - 1
ret
notbacksp:
;not a backspace character, eol?
cpi lf ;return if not
rnz
;end of line, column = 0
mvi m,0 ;column = 0
ret
ctlout:
;send C character with possible preceding up-arrow
mov a,c ;cy if not graphic (or special case)
call echoc
jnc tabout ;skip if graphic, tab, cr, lf, or ctlh
;send preceding up arrow
push psw ;up arrow
mvi c,ctl
call conout
pop psw ;becomes graphic letter
ori 40h
mov c,a ;ready to print
;(drop through to tabout)
tabout:
;expand tabs to console
mov a,c ;direct to conout if not
cpi tab
jnz conout
;tab encountered, move to next tab position
tab0:
mvi c,' ' ;another blank
call conout
lda column ;column mod 8 = 0 ?
ani 111b
jnz tab0 ;back for another if not
ret
backup:
;back-up one screen position
call pctlh
mvi c,' '
call conoutf
; (drop through to pctlh)
pctlh:
;send ctlh to console without affecting column count
mvi c,ctlh
jmp conoutf
;ret
crlfp:
;print #, cr, lf for ctlx, ctlu, ctlr functions
;then move to strtcol (starting column)
mvi c,'#'
call conout
call crlf
;column = 0, move to position strtcol
crlfp0:
lda column
lxi h,strtcol
cmp m ;stop when column reaches strtcol
rnc
mvi c,' ' ;print blank
call conout
jmp crlfp0
crlf:
;carriage return line feed sequence
mvi c,cr
call conout
mvi c,lf
jmp conout
;ret
print:
;print message until M(BC) = '$'
ldax b ;stop on $
cpi '$'
rz
;more to print
inx b ;char to C
push b
mov c,a
call tabout ;another character printed
pop b
jmp print
read: ;read to info address (max length, current length, buffer)
lda column ;save start for ctl-x, ctl-h
sta strtcol
lhld info
mov c,m
inx h
push h
mvi b,0
;B = current buffer length,
;C = maximum buffer length,
;HL= next to fill - 1
readnx:
;read next character, BC, HL active
push b ;blen, cmax, HL saved
push h
readn0:
call conin ;next char in A
ani 7fh ;mask parity bit
pop h ;reactivate counters
pop b
cpi cr ;end of line?
jz readen
cpi lf ;also end of line
jz readen
cpi ctlh ;backspace?
jnz noth
;do we have any characters to back over?
mov a,b
ora a
jz readnx
;characters remain in buffer, backup one
dcr b ;remove one character
lda column ;col > 0
sta compcol
;compcol > 0 marks repeat as length compute
jmp linelen ;uses same code as repeat
noth:
;not a backspace
cpi rubout ;rubout char?
jnz notrub
;rubout encountered, rubout if possible
mov a,b ;skip if len=0
ora a
jz readnx
;buffer has characters, resend last char
mov a,m ;A = last char
dcr b
dcx h
;blen=blen-1, next to fill - 1 decremented
jmp rdech1 ;act like this is an echo
notrub:
;not a rubout character, check end line
cpi ctle ;physical end line?
jnz note
;yes, save active counters and force eol
push b
push h
call crlf
xra a ;start position = 00
sta strtcol
jmp readn0 ;for another character
note:
;not end of line, list toggle?
cpi ctlp ;skip if not ctlp
jnz notp
;list toggle - change parity
push h ;save next to fill - 1
lxi h,listcp ;HL=.listcp flag
mvi a,1 ;True-listcp
sub m
mov m,a ;listcp = not listcp
pop h ;for another char
jmp readnx
notp:
;not a ctlp, line delete?
cpi ctlx
jnz notx
pop h ;discard start position
;loop while column > strtcol
backx:
lda strtcol
lxi h,column
cmp m ;start again
jnc read
dcr m ;column = column - 1
call backup ;one position
jmp backx
notx:
;not a control x, control u?
;not control-X, control-U?
cpi ctlu ;skip if not
jnz notu
;delete line (ctlu)
call crlfp ;physical eol
pop h ;discard starting position
jmp read ;to start all over
notu:
;not line delete, repeat line?
cpi ctlr
jnz notr
linelen:
;repeat line, or compute line len (ctlh)
;if compcol > 0
push b ;save line length
call crlfp
pop b
pop h
push h
push b
;bcur, cmax active, beginning buff at HL
rep0:
mov a,b ;count len to 00
ora a
jz rep1
inx h ;next to print
mov c,m
dcr b ;count length down
push b
push h
call ctlout ;character echoed
pop h ;recall remaining count
pop b
jmp rep0 ;for the next character
rep1:
;end of repeat, recall lengths
;original BC still remains pushed
push h ;save next to fill
lda compcol ;>0 if computing length
ora a
jz readn0 ;for another char if so
;column position computed for ctlh
lxi h,column ;diff > 0
sub m
sta compcol ;count down below
;move back compcol-column spaces
backsp:
;move back one more space
call backup ;one space
lxi h,compcol
dcr m
jnz backsp
jmp readn0 ;for next character
notr:
;not a ctlr, place into buffer
rdecho:
inx h ;character filled to mem
mov m,a
inr b ;blen = blen + 1
rdech1:
;look for a random control character
push b ;active values saved
push h
mov c,a ;ready to print
call ctlout ;may be up-arrow C
pop h ;recall char
pop b
mov a,m
cpi ctlc ;set flags for reboot test
mov a,b ;move length to A
jnz notc ;skip if not a control c
cpi 1 ;control C, must be length 1
jz reboot ;reboot if blen = 1
;length not one, so skip reboot
notc:
;not reboot, are we at end of buffer?
cmp c ;go for another if not
jc readnx
readen:
;end of read operation, store blen
pop h ;M(current len) = B
mov m,b
mvi c,cr ;return carriage
jmp conout
;ret
func1:
;return console character with echo
call conech
jmp sta_ret
;
func2 equ tabout
;write console character with tab expansion
;
func3:
;return reader character
call readerf
jmp sta_ret
;func4: equated to punchf
;write punch character
;func5: equated to listf
;write list character
;write to list device
func6:
;direct console i/o - read if 0ffh
mov a,c ;0ffh => 00h, means input mode
inr a
jz dirinp
inr a ;0feH in C for status
jz constf
;direct output function
jmp conoutf
dirinp:
call constf ;status check
ora a ;skip, return 00 if not ready
jz retmon
;character is ready, get it
call coninf ;to A
jmp sta_ret
func7:
;return io byte
lda ioloc
jmp sta_ret
func8:
;set i/o byte
lxi h,ioloc
mov m,c
ret ;jmp goback
func9:
;write line until $ encountered
xchg ;was lhld info
mov c,l ;BC=string address
mov b,h
jmp print ;out to console
func10 equ read
;read a buffered console line
func11:
;check console status
call conbrk
;(drop through to sta_ret)
sta_ret:
;store the A register to aret
sta aret
func_ret: ;
ret ;jmp goback (pop stack for non cp/m functions)
setlret1:
;set lret = 1
mvi a,1
jmp sta_ret
; data areas
compcol:db 0 ;true if computing column position
strtcol:db 0 ;starting column position after read
column: db 0 ;column position
listcp: db 0 ;listing toggle
kbchar: db 0 ;initial key char = 00
entsp: ds 2 ;entry stack pointer
ds ssize*2 ;stack size
lstack:
; end of Basic I/O System
;*****************************************************************
;*****************************************************************
; common values shared between bdosi and bdos
usrcode:db 0 ;current user number
curdsk: db 0 ;current disk number
info: ds 2 ;information address
aret: ds 2 ;address value to return
lret equ aret ;low(aret)
;*****************************************************************
;*****************************************************************
;** **
;** B a s i c D i s k O p e r a t i n g S y s t e m **
;** **
;*****************************************************************
;*****************************************************************
dvers equ 22h ;version 2.2
; module addresses
; literal constants
_true equ 0ffh ;constant true
_false equ 000h ;constant false
enddir equ 0ffffh ;end of directory
byte equ 1 ;number of bytes for "byte" type
word equ 2 ;number of bytes for "word" type
; fixed addresses in low memory
tfcb equ 005ch ;default fcb location
tbuff equ 0080h ;default buffer location
; fixed addresses referenced in bios module are
; pererr (0009), selerr (000c), roderr (000f)
; error message handlers
;per_error:
;report permanent error to user
; lxi h,pererr jmp goerr
;rod_error:
;report read/only disk error
; lxi h,roderr jmp goerr
;rof_error:
;report read/only file error
; lxi h,roferr ;jmp goerr
sel_error:
;report select error
lxi h,selerr
goerr:
;HL = .errorhandler, call subroutine
mov e,m ;address of routine in DE
inx h
mov d,m
xchg ;to subroutine
pchl
; local subroutines for bios interface
move:
;move data length of length C from source DE to
;destination given by HL
inr c ;in case it is zero
move0:
dcr c ;more to move
rz
ldax d ;one byte moved
mov m,a
inx d ;to next byte
inx h
jmp move0
selectdisk:
;select the disk drive given by curdsk, and fill
;the base addresses curtrka - alloca, then fill
;the values of the disk parameter block
lda curdsk ;current disk# to c
mov c,a
;lsb of e = 0 if not yet logged - in
call seldskf ;HL filled by call
;HL = 0000 if error, otherwise disk headers
mov a,h ;return with 0000 in HL and z flag
ora l
rz
;disk header block address in hl
mov e,m ;DE=.tran
inx h
mov d,m
inx h
shld cdrmaxa ;.cdrmax
inx h
inx h
shld curtrka ;HL=.currec
inx h
inx h
shld curreca ;HL=.buffa
inx h
inx h
;DE still contains .tran
xchg ;.tran vector
shld tranv
lxi h,buffa ;DE= source for move, HL=dest
mvi c,addlist ;addlist filled
call move
;now fill the disk parameter block
lhld dpbaddr ;DE is source
xchg
lxi h,sectpt ;HL is destination
mvi c,dpblist ;data filled
call move
;now set single/double map mode
lhld maxall ;largest allocation number
mov a,h ;00 indicates < 255
lxi h,single ;assume a=00
mvi m,_true
ora a
jz retselect
;high order of maxall not zero, use double dm
mvi m,_false
retselect:
mvi a,_true ;select disk function ok
ora a
ret
home:
;move to home position, then offset to start of dir
call homef ;move to track 00, sector 00 reference
;lxi h,offset ;mov c,m ;inx h ;mov b,m ;call settrkf
;first directory position selected
xra a ;constant zero to accumulator
lhld curtrka ;curtrk=0000
mov m,a
inx h
mov m,a
lhld curreca ;currec=0000
mov m,a
inx h
mov m,a
;curtrk, currec both set to 0000
ret
rdbuff:
;read buffer and check condition
call readf ;current drive, track, sector, dma
jmp diocomp ;check for i/o errors
wrbuff:
;write buffer and check condition
;write type (wrtype) is in register C
;wrtype = 0 => normal write operation
;wrtype = 1 => directory write operation
;wrtype = 2 => start of new block
call writef ;current drive, track, sector, dma
diocomp: ;check for disk errors
ora a
rz
lxi h,pererr
jmp goerr
seek_dir:
;seek the record containing the current dir entry
lhld dcnt ;directory counter to HL
mvi c,dskshf ;value to HL
call hlrotr
shld arecord ;ready for seek
shld drec
; jmp seek
;ret
seek:
;seek the track given by arecord (actual record)
;local equates for registers
;arech equ b ;arecord = BC
;arecl equ c
;crech equ d ;currec = DE
;crecl equ e
;ctrkh equ h ;curtrk = HL
;ctrkl equ l
;tcrech equ h ;tcurrec = HL
;tcrecl equ l
;load the registers from memory
lxi h,arecord
mov c,m ; % c = arecl
inx h
mov b,m ; % b = arech
lhld curreca
mov e,m ; % e = crecl
inx h
mov d,m ; % d = crech
lhld curtrka
mov a,m
inx h
mov h,m ; % h = ctrkh
mov l,a ; % l = ctrkl
;loop while arecord < currec
seek0:
mov a,c ; % c = arecl
sub e ; % e = crecl
mov a,b ; % b = arech
sbb d ; % d = crech
jnc seek1 ;skip if arecord >= currec
;currec = currec - sectpt
push h ; % h = ctrkh
lhld sectpt
mov a,e ; % e = crecl
sub l
mov e,a ; % e = crecl
mov a,d ; % d = crech
sbb h
mov d,a ; % d = crech
pop h ; % h = ctrkh
;curtrk = curtrk - 1
dcx h ; % h = ctrkh
jmp seek0 ;for another try
seek1:
;look while arecord >= (t:=currec + sectpt)
push h ; % h = ctrkh
lhld sectpt ;HL = currec+sectpt
dad d ; % d = crech
jc seek2 ;can be > FFFFH
mov a,c ; % c = arecl
sub l ; % l = tcrecl
mov a,b ; % b = arech
sbb h ; % h = tcrech
jc seek2 ;skip if t > arecord
;currec = t
xchg
;curtrk = curtrk + 1
pop h ; % h = ctrkh
inx h ; % h = ctrkh
jmp seek1 ;for another try
seek2: pop h ; % h = ctrkh
;arrive here with updated values in each register
push b ;to stack for later ; % b = arech
push d ; % d = crech
push h ; % h = ctrkh
;stack contains (lowest) BC=arecord, DE=currec, HL=curtrk
xchg ;HL = curtrk+offset
lhld offset
dad d
mov b,h ;track set up
mov c,l
call settrkf
;note that BC - curtrk is difference to move in bios
pop d ;recall curtrk
lhld curtrka ;curtrk updated
mov m,e
inx h
mov m,d
;now compute sector as arecord-currec
pop d ;recall currec ; % d = crech
lhld curreca
mov m,e ; % e = crecl
inx h
mov m,d ; % d = crech
pop b ;BC=arecord, DE=currec ; % b = arech
mov a,c ; % c = arecl
sub e ; % e = crecl
mov c,a ; % c = arecl
mov a,b ; % b = arech
sbb d ; % d = crech
mov b,a ; % b = arech
lhld tranv ;BC=sector#, DE=.tran
xchg
call sectran ;HL = tran(sector)
mov c,l ;BC = tran(sector)
mov b,h
jmp setsecf ;sector selected
;ret
; file control block (fcb) constants
empty equ 0e5h ;empty directory entry
lstrec equ 127 ;last record# in extent
recsiz equ 128 ;record size
fcblen equ 32 ;file control block size
dirrec equ recsiz/fcblen ;directory elts / record
dskshf equ 2 ;log2(dirrec)
dskmsk equ dirrec-1
fcbshf equ 5 ;log2(fcblen)
extnum equ 12 ;extent number field
maxext equ 31 ;largest extent number
ubytes equ 13 ;unfilled bytes field
modnum equ 14 ;data module number
maxmod equ 15 ;largest module number
fwfmsk equ 80h ;file write flag is high order modnum
namlen equ 15 ;name length
reccnt equ 15 ;record count field
dskmap equ 16 ;disk map field
lstfcb equ fcblen-1
nxtrec equ fcblen
ranrec equ nxtrec+1;random record field (2 bytes)
; reserved file indicators
rofile equ 9 ;high order of first type char
invis equ 10 ;invisible file in dir command
; equ 11 ;reserved
; utility functions for file access
dm_position:
;compute disk map position for vrecord to HL
lxi h,blkshf ;shift count to C
mov c,m
lda vrecord ;current virtual record to A
dmpos0:
ora a
rar
dcr c
jnz dmpos0
;A = shr(vrecord,blkshf) = vrecord/2**(sect/block)
mov b,a ;save it for later addition
mvi a,8 ;8-blkshf to accumulator
sub m
mov c,a ;extent shift count in register c
lda extval ;extent value ani extmsk
dmpos1:
;blkshf = 3,4,5,6,7, C=5,4,3,2,1
;shift is 4,3,2,1,0
dcr c