system/shard-x86-at/7/src/FDISK.ASM

Raw file
Back to index

  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