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
|
;-----------------------------------------------------------------------
; Disketten I/O
; Input:
; (ah)=0 Reset Diskette System
; hard reset to nec, prepare command, recal rquired
; on all drives
; (ah)=1 read the status of the system into (al)
; diskette_status from last operation is used
;
; Registers for read/write/verify/format
; (dl) drive number (0-3 allowed, vlue checked)
; (dh) head number (0-1 allowed, not value checked)
; (ch) track number (0-39, not value checked)
; (cl) sektor number (1-8, not value checked,
; not used for format)
; (al) number of sektors ( max = 8, not value checked,
; not used for format
; (es:bx) address of buffer (not required for verify)
; (ah)=2 read the desired sektors into memory
; =3 write
; =4 verify
; =5 format
; for the format operation, the buffer pointer (es,bx)
; must point to the collektion of desired address fields
; for the track. Each field is composed of 4 Bytes,
; (c,h,r,n) where c = track number, h=head number,
; r = sektor number, n = number of bytes per sektor
; (00=128, 01=256, 02=512, 03=1024). There must be one
; entry for every sektor on the track. This information
; is used to find the requested sektor during read/write
; access.
;
; Data Variable -- disk_pointer
; double word pointer to the current set of diskette parameters
; Output
; ah = status of Operation
; Status bits are defined in the equates for
; Diskette_status variable in the data segment of this
; module.
; cy = 0 successful operation (ah = 0 on return)
; cy = 1 failed operation (ah has error reason)
; for read/write/verify
; ds,bx,dx,ch,cl reserved
; al = number of sektors actually read
; ***** al may not be correkt if time out error occurs
; note: if an error is reported by the diskette code, the
; appropriate action is to reset the diskette, then retry
; the operation, on read access, no motor start delay
; is taken, so that three retries are required on reads
; to ensure that the problem is not due to motor
; start-up.
;-----------------------------------------------------------------------
data segment at 40h
org 3eh
seek_status db ?
int_flag equ 80h
motor_status db ?
motor_count db ?
motor_wait equ 37
diskette_status db ?
nec_status db 7 dup(?)
data ends
assume ds:data
ife withhd
dma equ 0 ; dma address
dma_high equ 82h ; port for high 4 bits of dma
endif
diskette_io proc near
sti
push bx
push cx
push ds
push si
push di
push bp
push dx
mov bp,sp ; set up pointer to head parm
mov si,data
mov ds,si
call j1 ; call the rest to ensure ds restored
mov bx,4 ; get the motor wait parameter
call get_parm
mov motor_count,ah ; set the timer count for the motor
mov ah,diskette_status ; get status of operation
cmp ah,1 ; set the carry flag to indicate
cmc ; success or failure
pop dx
pop bp
pop di
pop si
pop ds
pop cx
pop bx
ret
diskette_io endp
j1 proc near
mov dh,al
and motor_status,07fh
or ah,ah
jz disk_reset
dec ah
jz fdisk_status
mov diskette_status,0
cmp dl,4
jae j3
dec ah
jz fdisk_read
dec ah
jnz j2
jmp fdisk_write
j2:
dec ah
jz disk_verf
dec ah
jz disk_format
j3:
mov diskette_status,bad_cmd
ret
j1 endp
;----- reset the diskette system
disk_reset proc near
mov dx,03f2h
cli
mov al,motor_status
mov cl,4
sal al,cl
test al,20h
jnz j5
test al,40h
jnz j4
test al,80h
jz j6
inc al
j4:
inc al
j5:
inc al
j6:
or al,8
out dx,al
mov seek_status,0
mov diskette_status,0
or al,4
out dx,al
sti
call chk_stat_2
mov al,nec_status
cmp al,0c0h
jz j7
or diskette_status,bad_cntlr
ret
;----- send specific command to nec
j7:
mov ah,3
call nec_output
mov bx,1
call get_parm
mov bx,3
call get_parm
j8:
ret
disk_reset endp
;-----diskette status routine
fdisk_status proc near
mov al,diskette_status
ret
fdisk_status endp
;-----diskette read
fdisk_read proc near
mov al,046h
j9:
call dma_setup
mov ah,0e6h
jmp short rw_opn
fdisk_read endp
;----- diskette verify
disk_verf proc near
mov al,042h
jmp j9
disk_verf endp
;----- diskette format
disk_format proc near
or motor_status,80h
mov al,04ah
call dma_setup
mov ah,04dh
jmp short rw_opn
j10:
mov bx,7
call get_parm
mov bx,9
call get_parm
mov bx,15
call get_parm
mov bx,17
jmp j16
disk_format endp
;-----diskette write routine
fdisk_write proc near
or motor_status,80h
mov al,04ah
call dma_setup
mov ah,0c5h
fdisk_write endp
;-----allow write routine to fall into rw_opn
;-----------------------------------------------------------------------
; rw_opn
; this routine performs the read/write/verify operation
;-----------------------------------------------------------------------
rw_opn proc near
jnc j11
mov diskette_status,dma_boundary
mov al,0
ret
j11:
push ax
;----- turn on the motor and select the drive
push cx
mov cl,dl
mov al,1
sal al,cl
cli
mov motor_count,0ffh
test al,motor_status
jnz j14
and motor_status,0f0h
or motor_status,al
sti
mov al,10h
sal al,cl
or al,dl
or al,0ch
push dx
mov dx,03f2h
out dx,al
pop dx
;----- wait for motor if write operation
test motor_status,80h
jz j14
clc
mov ax,090fdh
int 15h
jc j14
mov bx,20
call get_parm
or ah,ah
j12:
jz j14
sub cx,cx
j13:
loop j13
dec ah
jmp j12
j14:
sti
pop cx
;----- do the seek operation
call seek
pop ax
mov bh,ah
mov dh,0
jc j17
mov si,offset j17
push si
;----- send out the parameters to the controller
call nec_output
mov ah,[bp+1]
sal ah,1
sal ah,1
and ah,4
or ah,dl
call nec_output
;----- test for format command
cmp bh,04dh
jne j15
jmp j10
j15:
mov ah,ch
call nec_output
mov ah,[bp+1]
call nec_output
mov ah,cl
call nec_output
mov bx,7
call get_parm
mov bx,9
call get_parm
mov bx,11
call get_parm
mov bx,13
j16:
call get_parm
pop si
;----- let the operation happen
call wait_int
j17:
jc j21
call results
jc j20
;----- check the results returned by the controller
cld
mov si,offset nec_status
lods nec_status
and al,0c0h
jz j22
cmp al,040h
jnz j18
;----- abnormal termination, find out wy
lods nec_status
sal al,1
mov ah,record_not_fnd
jc j19
sal al,1
sal al,1
mov ah,bad_crc
jc j19
sal al,1
mov ah,bad_dma
jc j19
sal al,1
sal al,1
mov ah,record_not_fnd
jc j19
sal al,1
mov ah,write_protect
jc j19
sal al,1
mov ah,bad_addr_mark
jc j19
;----- nec must have failed
j18:
mov ah,bad_cntlr
j19:
or diskette_status,ah
call num_trans ; how many were really transferred
j20:
ret
j21:
call results
ret
;----- operation was successfull
j22:
call num_trans
xor ah,ah
ret
rw_opn endp
;-----------------------------------------------------------------------
; nec_output
; This routine sends a byte to the nec controller after testing
; for correct direction and controller ready. This routine will
; time out if the byte is not accepted within a reasonable
; amount of time, setting the diskette status on completion.
; Input
; (ah) byte to be output
; Output
; cy=0 success
; cy=1 failure -- diskette status updated
; If a failure has occured, the return is made one level
; higher than the caller of nec_output. (!Schweinkram)
; This removes the requirement of testing after every
; call of nec_output
; (al) destroyed
;-----------------------------------------------------------------------
nec_output proc near
push dx
push cx
mov dx,03f4h
xor cx,cx
j23:
in al,dx
test al,040h
jz j25
loop j23
j24:
or diskette_status,time_out
pop cx
pop dx
pop ax ; discard the return address
stc
ret
j25:
xor cx,cx
j26:
in al,dx
test al,080h
jnz j27
loop j26
jmp j24
j27:
mov al,ah
mov dl,0f5h
out dx,al
pop cx
pop dx
ret
nec_output endp
;-----------------------------------------------------------------------
; get_parm
; This routine fetches the indext pointer from the disk_bas
; block pointed at by the data variable disk_pointer. A byte from
; that table is then moved into ah, the index of that byte being
; the parm in bx
; Input:
; bx index of byte to be fetched *2
; if the low bit of bx is on, the byte is immediately output
; to the nec controller
; Exit
; am that byte from block
;-----------------------------------------------------------------------
disk_pointer equ 1eh * 4
get_parm proc near
push ds
push si
sub ax,ax
mov ds,ax
lds si,dword ptr ds:disk_pointer
shr bx,1
mov ah,[si+bx]
pop si
pop ds
jc nec_output
ret
get_parm endp
;-----------------------------------------------------------------------
; seek
; Thi routine will move the head on the named drive to the
; named track. If the drive has not been accessed since the
; drive reset command was issued, the drive will be recalibrated.
; Input:
; (dl) = Drive to seek on
; (ch) = track t seek to
; Output:
; cy = 0 success
; cy = 1 failure -- diskette_status set accordingly
; (ax) destroyed
;-----------------------------------------------------------------------
seek proc near
mov al,1
push cx
mov cl,dl
rol al,cl
pop cx
test al,seek_status
jnz j28
or seek_status,al
mov ah,07h
call nec_output
mov ah,dl
call nec_output
call chk_stat_2
jc j32
;----- drive is in synch with controller, seek to track
j28:
mov ah,0fh
call nec_output
mov ah,dl
call nec_output
mov ah,ch
call nec_output
call chk_stat_2
;----- wait for head settle
pushf
mov bx,18
call get_parm
push cx
j29:
mov cx,550
or ah,ah
jz j31
j30:
loop j30
dec ah
jmp j29
j31:
pop cx
popf
j32:
ret
seek endp
;-----------------------------------------------------------------------
; dma_setup
; this routine sets up the dma for read/write/verify operations
; input:
; (al) = mode byte for the dma
; (es:bx) - address to read/write the data
; output:
; (ax) destroyed
;-----------------------------------------------------------------------
dma_setup proc near
push cx
cli
out dma+12,al
push ax
pop ax
out dma+11,al
mov ax,es
mov cl,4
rol ax,cl
mov ch,al
and al,0f0h
add ax,bx
jnc jj33
inc ch
jj33:
push ax
out dma+4,al
mov al,ah
out dma+4,al
mov al,ch
and al,0fh
out 081h,al
;----- determine count
mov ah,dh
sub al,al
shr ax,1
push ax
mov bx,6
call get_parm
mov cl,ah
pop ax
shl ax,cl
dec ax
push ax
out dma+5,al
mov al,ah
out dma+5,al
sti
pop cx
pop ax
add ax,cx
pop cx
mov al,2
out dma+10,al
ret
dma_setup endp
;-----------------------------------------------------------------------
; chk_stat_2
; This routine handles the interrupt received after a
; recalibrate, seek, or reset to the adapter.
; The interrupt is waited for, the interrupt sensed,
; and the result returned to the caller.
; input:
; none
; output:
; cy = 0 success
; cy = 1 failure -- error is in diskette_status
; (ax) destroyed
;-----------------------------------------------------------------------
chk_stat_2 proc near
call wait_int
jc j34
mov ah,08h
call nec_output
call results
jc j34
mov al,nec_status
and al,060h
cmp al,060h
jz j35
clc
j34:
ret
j35:
or diskette_status,bad_seek
stc
ret
chk_stat_2 endp
;-----------------------------------------------------------------------
; wait_int
; This routine waits for an interrupt to occur. A time out
; routine takes place during the wait, so that an error may be
; returned if the drive is not ready.
; input:
; none
; output:
; cy = 0 success
; cy = 1 failure -- diskette_status is set accordingly
; (ax) destroyed
;-----------------------------------------------------------------------
wait_int proc near
sti
push ax
push bx
push cx
clc
mov ax,09001h
int 15h
sti
jc j36a
;
mov bl,2
xor cx,cx
j36:
test seek_status,int_flag
jnz j37
; push cx
; push bx
; push ds
; push es
; push ax
; push dx
; push si
; push di
; push bp
; call cs:warte
; pop bp
; pop di
; pop si
; pop dx
; pop ax
; pop es
; pop ds
; pop bx
; pop cx
loop j36
dec bl
jnz j36
j36a: or diskette_status, time_out
stc
j37:
pushf
and seek_status, not int_flag
popf
pop cx
pop bx
pop ax
ret
wait_int endp
;-----------------------------------------------------------------------
; disk_int
; This routine handles the diskette interrupt
; Input
; none
; output:
; The interrupt flag is set is seek_status
;-----------------------------------------------------------------------
;**************
;org 0ef57h
;**************
disk_int proc far
sti
push ds
push ax
push si
mov si,data
mov ds,si
or seek_status, int_flag
mov al,20h
out 20h,al
mov ax,09101h
int 15h
pop si
pop ax
pop ds
iret
disk_int endp
;-----------------------------------------------------------------------
; results
; This routine will read anything that the nec controller has
; to say following an interrupt.
; input:
; none
; output:
; cy = 0 successful transfer
; cy = 1 failure -- time out in waiting for status
; nec_status area has status byte loaded into it
; (ah) destroyed
;-----------------------------------------------------------------------
results proc near
cld
mov di,offset nec_status
push cx
push dx
push bx
mov bl,7
;-----wait for request for master
j38:
xor cx,cx
mov dx,03f4h
j39:
in al,dx
test al,80h
jnz j40a
loop j39
or diskette_status, time_out
j40:
stc
pop bx
pop dx
pop cx
ret
;----- test the direction bit
j40a:
in al,dx
test al,40h
jnz j42
j41:
or diskette_status,bad_cntlr
jmp j40
;-----read in the status
j42:
inc dx
in al,dx
mov [di],al
inc di
mov cx,10
j43: loop j43
dec dx
in al,dx
test al,10h
jz j44
dec bl
jnz j38
jmp j41
;----- result operation is done
j44:
pop bx
pop dx
pop cx
ret
;-----------------------------------------------------------------------
; num_trans
; This routine calculates the number of sectors that were
; actually transferred to/from the diskette
; input
; (ch) = cylinder of operation
; (cl) = start sector of operation
; output
; (al) = number actually transferred
; no other registers modified
;-----------------------------------------------------------------------
num_trans proc near
mov al,nec_status+3
cmp al,ch
mov al,nec_status+5
jz j45
mov bx,8
call get_parm
mov al,ah
inc al
j45:
sub al,cl
ret
num_trans endp
results endp
assume ds:shard
|