-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathDISKIO.280
1227 lines (1091 loc) · 35.4 KB
/
DISKIO.280
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
title 'AutoFormat Disk I/O Module of CP/M-3 BIOS'
.xlist
maclib Z280EQU
maclib CPU280
maclib OPTIONS
.list
.z280
; 950214 Tilmann Reh
; 170308 Wayne Warthen
; 10-July-2017 Tony Nicholson
; Comments translated from German to English (using Google
; Translate with some appropriate language adjustments resulting
; from an examination of the instruction sequences). Also
; corrected the syntax to be compatible with Hector Peraza's
; ZSM4 Z80/Z180/Z280 assembler
LogTry equ 3 ; 1..255, Number of attempts at AutoFormat-Read
RdTry equ 3 ; 1..255, Number of attempts at Disk-Read
WrTry equ 3 ; 1..255, Number of attempts at Disk-Write
VerTry equ 1 ; 0..255, Number of attempts at Disk-Verify
AllTry equ 3 ; 1..255, Total number of attempts Disk-Write/Verify
; These variables should later be adjusted in the Bootloader-Setup.
; When VerTry=0, there is no conditional assembly.
dseg ; Disk-I/O Routines are wholly in Bank 0
;***********************************************************************
;** Disk-I/O Control Routines for the BDOS **
;***********************************************************************
; Initialisation of the Floppy driver. Non-existing drives are removed
; from the Drive Table. All 4 drives are handled by this one routine.
; No messages are output in order to reduce verbosity.
if not loader
DskIni: iopage BoardP ; for accessing the NVRAM
ld bc,400h+s$Drv0 ; Point to the drive entries in NVRAM
ld hl,DTbl ; Start with the Drive Table (for A:)
DskIn1: in a,(c)
and 7
jr nz,DskIn2 ; Drive Typ <> 0 : drive available
ldw (hl),0 ; Typ = 0 : remove drive table entry
DskIn2: inc hl
inc hl ; next table entry
inc c ; next drive
djnz DskIn1 ; check each of the 4 drives
ret
endif
; Select floppy drive for all further accesses. Here are all global
; pointers and variables that are set in such a way to facilitate easy
; R/W access. On 'Initial Select' and AutoFormat detection is performed.
; The drive to select is passed in the C register (0..3) and the cold
; select hint flag is in E.
if not loader
MskTbl: defb 1,2,4,8 ; Bit masks for Floppy Login Vector
endif
DskSel: ld a,c ; Drive (0..3) to A
ld (PDrive),a ; Save drive to PDrive: for FDC
iopage BoardP ; for NVRAM access
if loader
add a,s$Drv0
ld c,a ; Drive type address (NVRAM) in C
else
push ResIOP ; after returning to Bus-I/O-Page
exts a ; PDrive to HL
add a,s$Drv0
ld c,a ; Drive Type Address (NVRAM) in C
ld a,(hl++MskTbl) ; Get the bit mask from table
ld (CurMsk),a ; save to current mask
endif
in a,(c) ; Get drive type from Setup-RAM
ld (DrvTyp),a ; and save as the current drive type
and 7 ; lower 3 bits: Typ-Code ( <> 0 )
multu a,3 ; 3 bytes per Specify command
lda hl,(hl+Steps-6) ; Point to 'Specify' (Types 2..7)
ld b,3
call FdcCo1 ; Issue SPECIFY command (FDC Times)
push ix ; save IX (used by ZPM3)
call SetLen ; Set Sector length of FDC and DMA
pop ix
if not loader ; Loader: only one call, always AutoFormat
bit 0,e
jr z,AutoFm ; First select? (Flag E=0)
ld a,(CurMsk)
ld hl,ResMsk
and (hl)
call z,DskHom ; if FDC Reset: perform drive recalibrate
ld hl,(CurDPH) ; Return with DPH in HL
ret
; Disk change (detect drive AutoFormat)
AutoTim:call MotOff ; Time-Out/Cancel AutoFormat: Motor off
ld hl,0
ret ; End with HL=0 (Illegal Drive)
endif
AutoFm:
if not loader
ld (DFunc),'L' ; Prepare the 'LOGIN' error message
endif
call DskHom ; Motor on, seek to track 0
ldw (Retry),ChkRtry ; Initialise retry count
ChkRtry:call ChkDen ; Density test
call c,TimErr ; Time-Out: Error/Retry
if loader
ld hl,0
ret c ; Time-Out: Abort
else
jr c,AutoTim ; after Time-Out: Abort (Illegal Drive)
endif
jp nz,SelDsX ; Error doing ID-Read: no AutoFormat
if not loader
ld (DFunc),'P' ; Change error message for 'Params'
endif
ld a,(Dense)
or 6 ; FDC 'READ DATA'
ld (CList),a
xor a
ld (PTrack),a ; Track 0
if not loader
ld (DBnk),a ; Auto Format buffer in Bank 0
endif
inc a
ld (Psect),a ; Read Track 0 Sector 1 to page 0
ld (EOT),a
ld a,(Result+4) ; Examine head number from ID Field
ld (Head),a
ld a,(Result+6) ; N from ID Field (Sector length)
ld (FdcN),a
ldw (DMA),Buffer ; new log. Set transfer address
ldw (RdLen),128 ; Generally only 128 byte read
ldw (Retry),RdParm ; Address for retry attempts
RdParm: ld bc,900h+LogTry ; Number of attempts in C, FDC command 9 Bytes
ParmLp: push bc
ld de,RdDmaPB
call DskIO ; Sector read
pop bc
call c,TimErr ; at Time-Out: ask what to do
jp c,DskErr ; Error aborted: Exit with error message
call ErChkP
jr z,ActDPB ; no error: Examine sector
ld a,(Result+1)
bit 2,a ; Sector 1 found?
jp nz,SelDsX ; no: cannot do AutoFormat...
dec c
jr nz,ParmLp ; retry in case of error
jp SelDsX ; failed - select disk with previous format
; Check if the AutoFormat sector contains a valid disk parameter block
ActDPB::push ix ; Save IX (because it is used by ZPM3)
push ActDPX ; Return address for all following 'RET'
ld ix,Buffer
ld a,21h ; First comparison byte
cp (ix) ; Address 00h right?
ret nz ; not 21h : no valid Parameter block
cp (ix+20h) ; Address 20h
ret nz
cp (ix+40h) ; Address 40h
ret nz
cp (ix+60h) ; Address 60h
ret nz
ld a,(ix+1)
cp 0AEh ; check first ID-Byte
ret nz
ld a,(ix+2)
cp 0BFh ; check second ID-Byte
ret nz
pop hl ; discard RET-Address from Stack
; Update Disk Parameter Blocks
ld hl,(CurDPH) ; point to current DPH
ldw hl,(hl++12)
ex de,hl ; Pointer to DPB in DE
ld ixh,d
ld ixl,e ; ... and in IX
ld hl,Buffer+3
ld bc,17 ; DPB 17 bytes long
ldir ; Copy DPB from Buffer
set 7,(ix+12) ; Permanent Mounted Drive
ld de,(CurDPH)
dec de
ld hl,Buffer+31
ld bc,12 ; 12 Bytes
lddr ; Copy track translation values before DPH
ld hl,(CurDPH) ; DPH
ldw de,(hl) ; TRANS in DE
ld ixh,d
ld ixl,e ; ... and in IX
ld hl,Buffer+64
ld bc,64 ; TRANS table upto to 64 Byte long (max.)
ldir ; load from parameter block (except S.1/33)
ld a,(Buffer+62)
ld (ix),a ; Sector 1
ld a,(Buffer+63)
ld (ix+32),a ; Sector 33
ActDPX: pop ix ; Restore IX (because it used by ZPM3...)
; SELDSK output (AutoFormat only, Cold logon of drive).
; Motor off, restore Density and FDC/DMA Parameters based
; on the current DPB, check permissible track format.
; After cold logging the drive DCHG resets and seek to track 1.
SelDsX:
if not loader
ld a,1
call Seek ; Seek to track 1 (reset DCHG)
call MotOff ; Drive Motor off again
endif
push ix ; save for ZPM3
call SetLen ; Restore FDC and DMA parameters
ld a,(DrvTyp) ; Type of current selected drive
ld b,a ; save it in B
bit 3,b
jr nz,SelDx1 ; If 80-Track drive: all OK
ld a,(ix-11) ; (IX=CURDPH from SETLEN)
cp 45
jr nc,SelDxE ; 40-Track drive, from 45 tracks error
SelDx1: bit 4,b
jr nz,SelDx2 ; If double-sided drive: all OK
ld a,(ix-2)
and 3
jr nz,SelDxE ; Single sided drive: Overflow impossible
SelDx2:
if not loader
ld hl,LogMsk ; if everything is OK
ld a,(CurMsk)
or (hl)
ld (hl),a ; Mark the drive as logged in
endif
ld hl,(CurDPH) ; and return with DPH in HL
pop ix
ret
SelDxE: ld hl,0
pop ix
ret ; 'Illegal Drive' : invalid configuration
; Sector Read. Read errors are repeated several times before an error
; is reported (defined by RdTry).
DskRd:
if not loader
ld a,(CurMsk)
and (LogMsk) ; Drive still logged in?
ld a,-1
ret z ; no: Return with A=FF (Media Change)
push ResIOP ; save Bus-Page for later
endif
call DskPos ; Motor on, position head
DskRd1::
if not loader
ld (DFunc),'R' ; in case of error: message 'READ'
endif
ldw (Retry),RdRtry ; Repeat up to RdRtry attempts
RdRtry: ld a,(Dense)
or 6 ; FDC-Command 'READ DATA'
ld (CList),a
ld bc,900h+RdTry ; RdTry tries, 9 Byte command
DskRd2: push bc
ld de,RdDmaPB
call DskIO ; Sector read
pop bc
call c,TimErr ; Time-Out: ask
jp c,DskErr ; User cancelled: that's it...
call ErrChk ; Error?
jr z,RWExit ; RET if no error (with A=0)
dec c
jr nz,DskRd2 ; try again
if not loader
ld a,(Quiet)
or a
ld a,1
ret nz ; if Quiet active: return without an error msg
endif
call DatErr ; Read error: ask
jp c,DskErr ; Error Return
RWExit: ld hl,(CurDPH)
dec hl
dec hl
bit 3,(hl)
call nz,Invert ; with inverse recording, invert the buffer
if not loader
MotOff::ld hl,MotFlg
res 0,(hl) ; Motor off after a delay (Rest via Interrupt)
endif
xor a
ret ; RET with A=0 (No errors)
; Sector write. Attempt to write WrTry times, then compare VerTry times.
; If there's a problem then retry AllTry times. If there's still an error
; then print an error message.
; HD Bug WorkAround by Stefan Nitschke: At the first appearance of a
; FDC Overrun set a Flag and try again (see DSKIO for explanation).
if not loader
DskWr: ld a,(CurMsk)
and (LogMsk) ; Drive still logged in?
ld a,-1
ret z ; no: Return with A=FF (Media Change)
push ResIOP ; later again Bus-Page
ld hl,(CurDPH)
dec hl
dec hl
bit 3,(hl)
call nz,Invert ; with inverse recording, invert the buffer
call DskPos ; Motor on, position the head
DskWr1::ldw (Retry),WrRtry ; Write retry entry point
WrRtry: ld e,AllTry ; Number of attempts for all
Wr1: ld (DFunc),'W' ; Prepare the error message
ld a,(Dense)
or 5 ; FDC-Command 'WRITE DATA'
ld (CList),a
ld bc,900h+WrTry ; WrTry write attempts, 9 byte command
Wr2: push bc
push de
ld de,WrDmaPB
call DskIO ; Write (or retry)
pop de
pop bc
call c,TimErr ; Time-Out: ask
jr c,DskErr ; Abort
call ErrChk ; Error?
jr z,Verify ; if no error -> verify (Scan)
call ChkBug ; if error: maybe HD-Bug?
jr c,WrRtry ; yes: try write again (WorkAround active)
ld a,(Result+1) ; FDC-Status 1
and 2 ; NOT WRITABLE from FDC (WRPROT from FDD)
ret nz ; RET with A=2 if Write-Protected
Wr3: dec c
jr nz,Wr2 ; try again
call DatErr ; ask...
jr c,DskErr ; --> User cancelled
jr RWExit ; --> User Ignore
Verify: ld a,VerTry ; Number of verify attempts
or a
jp z,RWExit ; no Verify: continue with RWExit
ld c,a ; Set count to C
ld (DFunc),'V' ; Identifier for error message
ld a,(Dense)
or 11h ; FDC-Command 'SCAN EQUAL'
ld (CList),a
Ver1: push bc
push de
ld de,WrDmaPB
call DskIO ; write DMA to controller
pop de
pop bc
call c,TimErr ; Time-Out (possibly retry at DSKWR1)
jr c,DskErr ; ...User Cancelled
call ErrChk ; Error?
jp z,RWExit ; no errors: RET with A=0
dec c
jr nz,Ver1 ; Scan-Error: try again
dec e
jr nz,Wr1 ; all unsuccessful: try again from the beginning
call DatErr ; ask...
jp nc,RWExit ; ...User Ignored
endif
; Output an error message with the operation type and command/result list.
; Then with A=1 (Data Error) and HL=0 (Illegal Drive) return to the BDOS.
DskErr:
if not loader
call MotOff ; Motor off
ld a,(@ErMde) ; ERROR-MODE from SCB
inc a
jr z,ErrEx ; if ErMde=FF no message, only RET with A=1
endif ; WBW 2017-02-28: Enable error reporting in loader
ld a,(Drive)
add a,'A'
ld (DrvCod),a ; Insert Drive letter into message
ld hl,DrvMsg
call PMsg ; Output error message
ld hl,(Track)
call PDec ; Output track number
ld hl,SecMsg
call PMsg ; Output Sector Header
ld a,(PDrive)
bit 2,a ; Head-Bit (phys. head)
ld c,'B'
call nz,ConOut ; leading B at page 1
ld hl,(PSect)
ld h,0
call PDec ; Output sector number
ld hl,CmdMsg
call PMsg ; 'Command:'
ld hl,CList
ld b,9
call HexLst ; Output 9 Byte FDC command bytes
ld hl,ResMsg
call PMsg ; 'Result:'
ld hl,Result
ld b,7
call HexLst ; Output 7 Byte FDC Result codes in hex
;endif ; WBW 2017-02-28: Enable error reporting in loader
ErrEx: ld a,1 ; RET with A=1 due to errors
ld hl,0 ; if AutoFormat fails... (DskSel)
ret
;***********************************************************************
;** Command Control of the Floppy Disk Controller **
;***********************************************************************
; FDC Control: Command transfer numberof bytes in B.
; I/O-Page must already be set to BOARDP. Changes ABHL.
FdcCom::
if loader
ld hl,CList
else
ld hl,(CmdAdr) ; Point to command list
endif
FdcCo1::in a,(FdcSta) ; (Entry with pointer in HL)
rla
jr nc,FdcCo1 ; wait until FDC-RQM (Request for Master)
rla
jr c,FdcErr ; with incorrect data direction: DIO-Error
ld a,(hl)
out (FdcDat),a ; Output command/data bytes to FDC
inc hl ; pointer to next byte
djnz FdcCo1 ; output all command bytes
ret
; DIO-Error (Data Direction Error in FDC) : Stop the system
;*** Possibly correct errors and continue working?
; (Is error correctable at all?)
FdcErr: ld hl,DioMsg
call PMsg ; Output "DIO-Error"
di
halt ; for safety's sake do not continue working
; After FDC errors during writing/formatting:
; set FDC-Overrun internal Flag HDBug (then try again).
; This activates the WorkAround for the DMA-Bug in DskIO.
; Output with CY if HD-Bug is freshly recognised, otherwise with NZ/NC.
if not loader
ChkBug::ld a,(Result+1) ; FDC-Status register 1
xor 10h ; Status (40) 10 (FDC Overrun) ?
ret nz ; no OR: not due to DMA-Bug (NC)
ld a,(HDBug) ; previous Bug-Status
or a
ret nz ; HDBug already known: End with NC
sub 1 ; A=FF, CY=1
ld (HDBug),a ; the first time: set Flag
ret
endif
; DMA init for Sector-Transfer, continue with INTCOM.
; DE must point to DMA Parameter block!
; HD-Bug-WorkAround by Stefan Nitschke: From the first HD bug every time
; DMASET the (undocumented!) I/O Addresses FFxxE8 to FFxxEB with 0000
; described. (No one knows why that fixes the bug!)
DskIO:: push bc ; Save command length (B)
if not loader
call ClcDMA ; phys. DMA-Address from log. to calculate
ld (RdDMA),hl
ld (RdDMA+2),a
ld (WrDMA),hl ; Address
ld (WrDMA+2),a ; Bank
endif
ex de,hl ; Pointer for DMA Parameter in HL
call DmaSet ; Initialise and start DMA 0
if not loader
ld a,(HDBug)
or a ; HD Write Error?
jr z,DskIO1 ; if not, continue normally
ld bc,04E8h ; 4 Addresses from FFxxE8 (IOPage still DMAP)
ld hl,0 ; to write: Word 0
BugLp: outw (c),hl ; Describe non-existent I/O Addresses
inc c ; next address
djnz BugLp ; until all 4 addresses are processed
endif
DskIO1: pop bc ; (Command length in B)
; Output command to FDC with wait (limited) to its interrupt. IOPage
; is set to BoardP. On exit Boardp is still set.
; Time-Out is 1 second (Home max. 240ms, I/O max. 400ms).
IntCom::iopage BoardP
xor a
ld (FdcRdy),a ; Reset FDC Ready Flag
call FdcCom ; Output FDC Command
IntCo1::ld hl,Cnt10
ldw (hl),100 ; Counter to 1 second (100 * 10ms)
inc hl
IntCo2: ld a,(FdcRdy)
or a
ret nz ; FDC-INT : RET with CY=0
bit 7,(hl) ; Count expired?
jr z,IntCo2 ; No, continue
iopage DMAP
ld hl,0
ld c,tdr0
outw (c),hl ; Stop DMA 0 (Disable)
iopage BoardP
ld a,88h
out (FdcLdOR),a ; FDC: Programmed Reset
in a,(FdcLdCR)
ld a,8Ch
out (FdcLdOR),a
in a,(FdcSta) ; Then again for "Special Mode" progr.
if not loader
xor a ; after FDC Reset all "PCN" to 0,
ld (ResMsk),a ; ... that's why all 4 drives "log out"
endif
scf ; Time-Out: RET with CY=1
ret
; DMA Parameter blocks for Floppy-I/O (global labels for FORM).
RdDmaPB:defb dal0 ; DMA 0
if loader
defw Buffer
defb 81h ; Loader: Target fixed Buffer on page 81xxxxh
else
RdDMA: defs 3 ; Used for destination
endif
defb FdcDack,0,BoardP ; Src FDCDACK
RdLen:: defs 2 ; Used for length of buffer
defw 1110000010000000b ; descriptor: DMA 0 burst enable, Read
if not loader
WrDmaPB::defb dal0 ; DMA 0
defb FdcDack,0,BoardP ; Dest FDCDACK
WrDMA: defs 3 ; Used for source
WrLen:: defs 2 ; Used for length
defw 1000000010001100b ; descriptor: DMA 0 burst enable, Write
endif
;***********************************************************************
;** Subroutines for Disk-I/O **
;***********************************************************************
; Before first R/W (Initial Select) seek drive to track 0 and recalibrate
; Motor is switched on and left running (HOME).
; Called only from DskSel (Initial Select) and TimErr (Time-Out FDC-Reset).
DskHom:
if not loader
call MotOnW ; Motor on, wait for Drive Ready
else ; WBW 2017-02-28
iopage BoardP ; WBW 2017-02-28
endif
call SetStp ; Set clock for step rate
ld (CList),7 ; FDC-Command 'RECALIBRATE'
ld b,2
call IntCom ; command output
ld a,(Result)
and 11010000b ; check AT/IC and EC Flags
ld b,2
call nz,IntCom ; do it again if 'error' (Track>76)
if loader
xor a
ld (CurTrk),a
else
ld a,(CurMsk)
ld hl,ResMsk
or (hl)
ld (hl),a ; set corresponding bit in ResMsk: FDC "OnTrack"
ld hl,(Drive) ; log. Drive (0..3)
ld h,0
ld (hl++CurTks),0 ; current phys. track position for Drive: 0
endif
jp SetClk ; go and set FDC clock rate again for I/O
; Invert DMA buffer (for inverse recording).
; Uses the area allocated for this in the 8k-Block 0000..1FFF
Invert:
if loader
ld de,(DMA)
else
iopage MmuP
ld a,10h
out (pdr),a ; Point the MMU PDR Pointer to 'System 0'
in a,(pdr) ; wg. chip failure
call ClcDMA ; calculate phys. DMA-Address (--> AHL)
ex de,hl ; Address in ADE
ld h,a
ld a,d ; phys. Page in HA
and 0F0h ; for PDR only use upper 12 bits
or 0Ah ; Valid & Cacheable
ld l,a ; valid PDR value in HL
ld c,bmp
outw (c),hl ; output
lda hl,(hl+10h) ; next PDR value
outw (c),hl ; output
ld a,d
and 0Fh
ld d,a ; Address within page in DE (0..FFF)
endif
ld hl,(RdLen) ; Buffer length
InvLp: ld a,(de)
cpl ; Invert the byte in the buffer
ld (de),a
inc de ; bump pointer
dec hl ; decrement length
ld a,h
or l
jr nz,InvLp ; and repeat for the entire buffer
if not loader
ld a,10h
out (pdr),a ; MMU PDR Pointer to 'System 0'
ld b,2 ; (C still contains BMP)
ld hl,SysMMU
otirw ; Restore MMU System-PDR's 0 and 1
endif
ret
; Position the head of the drive on track and side. Different
; overflow methods are considered.
; First, overflow and edit sector numbers:
DskPos::push ix ; for ZPM3
if not loader
call MotOnW ; Motor an, possibly wait
else ; WBW 2017-02-28
iopage BoardP ; WBW 2017-02-28
endif
ld a,(Track)
ld c,a ; log. Track in C
ld ix,(CurDPH) ; Point to DPH for Format Parameters
ld a,(ix-8) ; Track translation method (0=none)
or a
jp nz,TTrans ; Translation active: execute
ld a,(ix-2)
and 3
ld b,a ; Overflow Bits in B, Z-Flag on 'None'
ld a,(Sector) ; Sector (from TRANS table) in A
jr z,DskPoX ; no overflow: Use Track/Sector directly
djnz DskPo1
rlca ; Sector overflow:
rrca ; Bit 7 copied to CY
res 7,a ; only 7 Bit Sector number
jr DskPoX
DskPo1: djnz DskPo2
ex a,c
cp (ix-11) ; Track overflow: Compare with track number
ccf
jr nc,DskPo1a ; Track smalled then count: Side 0
sub (ix-11) ; otherwise deduct the number
scf ; --> Page 1
DskPo1a:ex a,c
jr DskPoX
DskPo2: srl c ; Half track overflow: Track/2, Head --> CY
DskPoX: ld (PSect),a ; Save phys. sector number
ld (EOT),a ; EOT due to missing terminal count
lda hl,(ix--10) ; Pointer to head number
ld a,(PDrive)
res 2,a ; if Page 0 : reset HEAD Bit
jr nc,DskPoY ; Page 0 : PDRIVE unchanged
set 2,a ; Page 1 : set HEAD Bit for FDC
inc hl ; Point to head number for Side 1
DskPoY: ld (PDrive),a
ld a,(hl)
ld (Head),a ; Store the head number in ID-Field
ld a,c ; phys. Track number
cp (ix-11)
jr nc,Step2 ; Track number too big: do not start!
; Double-Stepping for <45 tracks on a 80 track drive
ld a,(ix-11) ; Track number
cp 45
ld a,c ; Track number in A
jr nc,Step1 ; at over 45 tracks stepping 1:1
ld a,(DrvTyp)
bit 3,a ; 40 or 80 Track drive?
ld a,c ; Track number in A
jr z,Step1 ; under 45 tracks on 40 LW also 1:1
add a,a ; otherwise double-stepping (for 48 TPI)
Step1: call Seek ; Seek to track
ld a,c ; Track number in A
Step2: ld (PTrack),a ; save it R/W routine
pop ix
ret
; Track translation process:
TTrans: ld b,a ; Method in B
djnz TTran2
ld a,(ix-11) ; Method 1:
dec a
cp c
jr nc,TTranX ; Track smaller max --> ok, front
add a,(ix-11) ; 2*max -1 (i.e. 79 or 159)
sub c
ld c,a
scf ; --> Page 1
jr TTranX
TTran2: djnz TTran3 ; Method 2:
ld a,c
sub (ix-11) ; Track - tracks per side
ccf
jr nc,TTran2a ; Track of small number of tracks: Side 0
ld c,a ; otherwise track correct, Side 1
TTran2a:push af ; save CY
ld b,(ix-11)
srl b ; half track number to B
ld a,c
add a,b ; first tracks from max/2
cp (ix-11)
jr c,TTran2b ; still below max: ok
sub (ix-11) ; 0..max/2-1
neg a ; 0..-max/2+1
add a,b ; max/2..1
dec a ; max/2-1..0
TTran2b:ld c,a ; Track from A to C
pop af ; Head back in CY
jr TTranX
TTran3: djnz TTran4
ld a,c ; Method 3:
dec a ; Swap tracks 1 and 2 (now: 0 and 1)
cp 2
jr nc,TTran3a ; do not swap if another track
xor 1
inc a
ld c,a ; switched track 2 and 1 in C
TTran3a:srl c ; Track/2, Head in CY
TTranX: ld a,(Sector)
jp DskPoX ; continue with Sector in A (Head in CY)
TTran4: srl c ; Method 4: Actually half-track overflow
jr nc,TTranX ; Side 0: ok
ld a,(Sector)
add a,(ix-12) ; Side 1: Continue counting sectors
scf
jp DskPoX
; Seek drive to physical track (in A), global for Format-Manager.
Seek:: ld (PTrack),a ; Save track in FDC command
if loader
ld hl,CurTrk
else
ld hl,(Drive) ; log. Drive (0..3)
ld h,0
lda hl,(hl++CurTks) ; Pointer to phys. track for this drive
endif
cp (hl)
jr z,SetClk ; Already on this track, seek not necessary
ld (hl),a ; otherwise save the current track
push bc
iopage BoardP ; (if coming from FORM)
call SetStp ; set step-rate for FDC clock
ld (CList),0Fh ; FDC 'SEEK'
ld b,3
call IntCom ; FDC-edition
pop bc ; Fall-thru: FDC clock rate again for I/O
; Set FDC clock rates according to drive type and current format.
; SetHD or SetLD sets FDC clock direcly for High or Normal Density.
; SetStp sets the clock rate to the value required for the proper step rate.
; Board-Page required!
SetClk::ld hl,(CurDPH)
dec hl
dec hl
bit 7,(hl) ; High-Density-Format ?
jr z,setld ; no: set normal clock rate
SetHD:: out (Drv_0),a ; FDC-DRV on LOW : 'High Density'
xor a
out (FdcLdCR),a ; CR := 0 --> 500 kb/s
ld (LDFlag),a ; reset Low-Density-Flag
ret
SetLD:: out (Drv_1),a ; FDC-DRV on HIGH : 'Low Density'
ld a,1
ld (LDFlag),a ; set Low-Density-Flag
ld a,(DrvTyp)
and 3 ; lower 2 bits specify clock rate
cp 3
adc a,-1 ; 0123 becomes 0122 for Control Register
out (FdcLdCR),a ; set CR accordingly
ret
SetStp: ld a,(DrvTyp) ; Type Bit 3 : 40/80 Track Drive
cpl ; Bit 3 now 0 = 80T, 1 = 40T
and 8 ; isolate Bit
rrca
rrca ; Value 2 at 40T, 0 at 80T
out (FdcLdCR),a ; --> 500 KHz for 80T, 250 KHz for 40T
ret
; Set DMA and FDC Parameters according to DPB. Subsequently IX = CURDPH.
; Global entry point SETLN1 for Format-Manager (reading of arbitary sectors)
SetLen: ld ix,(CurDPH)
ld a,(ix-2) ; Bit-Flags
and 40h
ld (Dense),a ; Set Density-Flag
ldw hl,(ix+12) ; Pointer to DPB
ld a,(hl+15) ; PSH (Physical Sector Shift)
ld (FdcN),a ; enter N in CLIST
SetLn1::add a,a
exts a ; 2*N to HL (range 0..10)
ldw hl,(hl+LenTab) ; Get sector length from table
ld (RdLen),hl
if not loader
ld (WrLen),hl ; use
endif
ret
LenTab: defw 128,256,512,1024,2048,4096
; MOTONW turns on the drive Motor and waits 1 Second if the motor was off.
; WBW 2017-02-28: MotOnW routine is now enabled for loader build. In this
; case it just sets the iopage which is assumed by code using this routine.
; For loader, the rest of the routine is not relevant.
if not loader
MotOnW::iopage BoardP ; select IO Page for Motor-Port
out (Mot_On),a ; Motor ON
ld hl,MotFlg
ld a,3
ex a,(hl) ; Motor-Flag set, old flag in A
or a
ret nz ; Motor already on: do not wait
ld hl,Cnt10
ld (hl),100 ; Counter to 1 sec. (100 * 10 ms)
M_OnW1: bit 7,(hl) ; busy wait
jr z,M_OnW1
ret
endif
; CHKDEN checks disk density (HD, MFM, FM, AutoFormat only).
; RET with Z means readable Indexfeld, otherwise NZ (in case of error).
; (Global for Format-Manager.)
ChkDen::ld a,(DrvTyp) ; current drive type
rra
jr nc,ChkD1 ; no HD-Drive: start with MFM
call SetHD ; Use HD settings
ld a,40h ; HD is always MFM
call CheckD ; Try reading disk
ret z ; OK : RET (Z,NC)
ret c ; Time-Out : NZ,C
ChkD1: call SetLD ; Try LD using MFM/FM
ld a,40h
call CheckD ; test MFM
ret z ; success: RET (Z,NC)
ret c ; Time-Out : NZ,C
xor a ; now try FM (and RET with Z or NZ)
CheckD: ld (Dense),a ; save new density flag
ChkD2:: or 0Ah ; FDC 'READ ID'
ld (CList),a
ld b,2
call IntCom ; to FDC, then ERRCHK
ret c ; RET with CY=1 if Time-Out
; Check FDC status values for errors (basically after Result Phase).
; Return with Z (ok) or NZ (Error), only AF used.
; Since individual sectors can only be processed via the corresponding EOT,
; this check is used on all R/W 'Abnormal Termination' operations.
ErrChk::ld a,(Result) ; FDC Status 0
and 10010000b ; Normal and Abnormal Termination are ok!
ret nz ; Invalid Command or Equipment Check (Home)
ld a,(Result+1) ; FDC Status 1
and 00110111b ; DE,OR,ND,NW,MA are errors (ignore EN)
ret nz
ld a,(Result+2) ; FDC Status 2
and 01110111b ; CM,DD,WC,SN,BC,MD are errors (SH is ok)
ret
; For Parameter reading engine test (ignore OverRun).
ErChkP::ld a,(Result) ; FDC Status 0
and 10010000b ; Normal and Abnormal Termination are ok!
ret nz ; Invalid Command or Equipment Check (Home)
ld a,(Result+1) ; FDC Status 1
and 00100111b ; DE,ND,NW,MA are errors (ignore EN and OR)
ret nz
ld a,(Result+2) ; FDC Status 2
and 01110111b ; CM,DD,WC,SN,BC,MD are errors (SH is ok)
ret
; Error handling. For Disk I/O Errors (read and write errors) the
; choice of Repeat, Abort or Ignore are offered. To repeat, the destination
; address of RETRY must be set correctly! Otherwise return to the
; calling program with CY=1 (Abort with Error) or CY=0 (Ignore).
DatErr: ld a,(Drive)
add a,'A'
ld (ErrDrv),a ; Insert drive name in message
ld hl,CrcMsg ; Error message with CRC errors
ld a,(Result+1)
bit 5,a ; Is it a CRC error (ID or Data)?
jr nz,DskEr1 ; yes: more specific message
ld hl,DskMsg ; no: general message
DskEr1: call PMsg ; Output error text
ld hl,ErrMsg
call PMsg ; Remainder of error message and prompt
DskEr2: call ConIn ; Wait for input character
if not loader
cp 3
jr z,DskEr4 ; ^C: Cancel, also send ^C to Host
endif
and 0DFh ; --> CAPS
cp IgnoreChar
ret z ; Ignore: RET with NC
cp AbortChar
scf
ret z ; Abort: RET with C
cp RetryChar
jr nz,DskEr2 ; nothing else allowed except 'Retry'
DskEr3: pop hl ; (Return address)
defb 0C3h ; Op-code for JP
Retry:: defw 0 ; Patch address, global for FORM
if not loader
DskEr4: ld (BrkFlg),0FFh ; in CHARIO: return ^C to Host
scf ; CY=1 : (Abort)
ret
endif
; Disk Time Out: Drive Not Ready.
; Here there are only two choices - Abort or Retry.
; Return either CY=1 or not at all (RETRY instead).
TimErr::ld a,(Drive)
add a,'A'
ld (TimDrv),a ; Insert drive name in timeout message
ld hl,TimMsg
call PMsg ; Output message and prompt
TimLp: call ConIn
if not loader
cp 3
jr z,DskEr4 ; ^C: Abort, with ^C an Host
endif
and 0DFh ; --> CAPS
cp 'A'
scf
ret z ; Abort: RET with C
cp RetryChar
jr nz,TimLp ; only permit 'Retry' response
; perform Drive reset
call DskHom ; Seek to Track 0
call DskPos ; Reposition head (due to PCN in FDC)
jr DskEr3 ; Try again
; Output (HL) in Hexadecimal, Number of Bytes in B.
; WBW 2017-02-28: Enable error reporting for loader build.
;if not loader ; WBW 2017-02-28 (comment out)
HexLst::ld c,' '
call CO ; leading space
ld a,(hl)
call HexByt ; Output Byte at (HL) in Hex
inc hl
djnz HexLst ; next byte
ret
;endif ; WBW 2017-02-28 (comment out)
; Text (Error messages):
if deutsch
CrcMsg: defz cr,lf,'CRC'
DskMsg: defz cr,lf,'Disk'
ErrMsg: defm '-Fehler auf '
ErrDrv: defz 'A: Abbruch/Ignorieren/Wiederholen? '
TimMsg: defm cr,lf,'Laufwerk '
TimDrv: defz 'A: nicht bereit. Abbruch/Wiederholen? '
;if not loader ; WBW 2017-02-28 (comment out)
DrvMsg: defm cr,lf,bel,'BIOS '
DFunc: defm 'L-Fehler auf '