summaryrefslogtreecommitdiff
path: root/system/shard-x86-at/7/src/HDISK.ASM
blob: 67044d4c6962908512eaa8ee92ce8cfe3fc8e7c2 (plain)
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
;shard  segment
;       assume cs: shard
;       assume ds: shard, es:nothing, ss:nothing

;================================================================
;       modul hdisk.asm
;       hard - disk - treiber
;
;  Status:
;       0.0     13.11.84        erste Testversion
;================================================================

TIMEOUT1        equ     20h             ; warten auf Disk-Interrupt
                                        ; (20.0000h  Tests)

;-------------------------------------------------------;
;       Fehlercodes
;       Bem: 11h ist eigentlich  k e i n  Fehler !
;-------------------------------------------------------;

;sense_fail      equ     0ffh            ; sense operation
;undef_err       equ     0bbf            ; undefined error occurred
;time_out        equ     80h             ; attachment failed to respond
;bad_seek        equ     40h             ; seek operation failed
;bad_cntlr       equ     20h             ; controller has failed
;data_corrected  equ     11h             ; ecc corrected data error
;bad_ecc         equ     10h             ; bad ecc on disk read
;bad_track       equ     0bh             ; bad track flag detected
;dma_boundary    equ     9               ; attempt to dma across 64k
;init_fail       equ     7               ; drive parameter activity failed
;bad_reset       equ     5               ; reset failed
;record_not_fnd  equ     4               ; requested sector not found
;bad_addr_mark   equ     2               ; address mark not found
;bad_cmd         equ     1               ; bad command passed to disk i/o

;-------------------------------------------------------;
;       interrrupt and status area                      ;
;-------------------------------------------------------;

dummy           segment at 0

                org 0dh *4
hdisk_int       label dword
                
                org 13h * 4
org_vector      label dword
                org 19h *4
hf_tbl_vec      label dword
dummy           ends

;-----------------------------------------------------------------------;
;       cmd_block
;
;  +0   Kommando
;  +1   Kopfnummer                              Aufrufparameter 1
;  +2   2-Bit Zylinder  & Rest Sektor           Aufrufparameter 2
;  +3   Zylinder                                Aufrufparameter 3
;  +4   Block - Count   (ist immer 1 )
;  +5   Control-Byte (Step - Option)
;-----------------------------------------------------------------------;

cmd_block       label byte
hd_error        db 7 dup(?)
disk_status     db ?

;-------------------------------------------------------;
;       hardware specific values                        ;
;                                                       ;
; - Controller i/o port                                 ;
;   > when ready from:                                  ;
;       hf_port+0 - read data (from controller to cpu   ;
;       hf_port+1 - read controller hardware status     ;
;               (controller to cpu)                     ;
;       hf_port+2 - read configuration switches         ;
;       hf_port+3 - not used                            ;
;  < when written to:                                   ;
;       hf_port+0 - write data (from cpu to controller) ;
;       hf_port+1 - controller reset                    ;
;       hf_port+2 - generate controller select pulse    ;
;       hf_port+3 - write pattern to dma and interrupt  ;
;                   mask register                       ;
;-------------------------------------------------------;

hf_port         equ     320h            ; disk port
r1_busy         equ     00001000b       ; disk port 1 busy bit
r1_bus          equ     00000100b       ;       command/data bit
r1_iomode       equ     00000010b       ;       mode bit
r1_req          equ     00000001b       ;       request bit

dma_read        equ     01000111b       ; channel 3 (47h)
dma_write       equ     01001011b       ; channel 3 (4bh)
dma             equ     0               ; dma address
dma_high        equ     82h             ; port for high 4 bits of dma

tst_rdy_cmd     equ     0               ; cntrl ready (00h)
recal_cmd       equ     00000001b       ;       recal (01h)
sense_cmd       equ     00000011b       ;       sense (03h)
fmtdrv_cmd      equ     00000100b       ;       drive (04h)
chk_trk_cmd     equ     00000101b       ;       t chk (05h)
fmttrk_cmd      equ     00000110b       ;       track (06h)
fmtbad_cmd      equ     00000111b       ;       bad   (07h)
read_cmd        equ     00001000b       ;       read  (08h)
write_cmd       equ     00001010b       ;       write (0ah)
seek_cmd        equ     00001011b       ;       seek  (0bh)
init_drv_cmd    equ     00001100b       ;       init  (0ch)
rd_ecc_cmd      equ     00001101b       ;       burst (00h)
rd_buff_cmd     equ     00001110b       ;       buffr (0eh)
wr_buff_cmd     equ     00001111b       ;       buffr (0fh)
ram_diag_cmd    equ     11100000b       ;       ram   (e0h)
chk_drv_cmd     equ     11100011b       ;       drv   (e3h)
cntrl_diag_cmd  equ     11100100b       ;       cntlr (e4h)
rd_long_cmd     equ     11100101b       ;       rlong (e5h)
wr_long_cmd     equ     11100110b       ;       wlong (e6h)

int_ctl_port    equ     20h             ; 8259 control port
eoi             equ     20h             ; end of interrupt command

        page

;===============================================================;
;       MAIN - Routine
; Input:
;       ah      -       0 write disk
;               -       1 read disk
;       (es:bx) -       Datenadresse
;       cmd_block
; Output:
;       disk_status     0 - alles OK
;===============================================================;

hard_dsk        proc
;       mov     ax,0                    ; interrupt initiieren
;       mov     es,ax
;       mov     word ptr es:[hdisk_int+2],cs
;       mov     word ptr es:[hdisk_int],offset hd_int

        sti                             ; enable interrupts
        mov     disk_status,0           ; noch alles ok !
        mov     cmd_block+5,5           ; 70 ysec steprate
        cmp     ah,0                    ; ah = 0  --> write disk
        jz      a4                      ; ah <> 0 --> read disk
        call    disk_read
        jmp     short   dsbl
a4:     call    disk_write

;-------------------------------------------------------;
;       dsbl
;       make shure that all housekeeping is done
;       before exit
;-------------------------------------------------------;

dsbl:
        mov     dx,hf_port+3
        sub     al,al
        out     dx,al                   ; reset int/dma mask
        mov     al,7
        out     dma+10,al               ; set dma - mode to disable
        cli                             ; disable interrupts
        in      al,21h
        or      al,20h
        out     21h,al                  ; disable interrupt 5
        sti                             ; enable interrupts
        ret

hard_dsk        endp

;========================================================
;       disk read routine
; Input:
;       (es:bx) -       Datenadresse
;       cmd_block
;========================================================

disk_read       proc    near
        mov     al,dma_read             ; mode byte for dma read
        mov     cmd_block+0,read_cmd
        jmp     do_io
disk_read       endp

;========================================================
;       disk write routine
; Input:
;       (es:bx) -       Datenadresse
;       cmd_block
;========================================================

disk_write      proc    near
        mov     al,dma_write            ; mode byte for dma write
        mov     cmd_block+0, write_cmd
        jmp     do_io
disk_write      endp
        page
;========================================================
;       do_io
;       gemeinsame Routine fuer alle Kommandos
; Input:
;       (es:bx) -       Datenadresse
;       al      -       mode (dma_read/dma_write)
;       cmd_block
;========================================================

do_io   proc near

        mov     cmd_block+4,1           ; Blockzahl immer 1

;-------------------------------------------------------;
;       DMA_SETUP
;       diese Routine dressiert den DMA
;-------------------------------------------------------;

        cli                             ; keine Interrupts mehr
        out     dma+12,al               ; first/last ff setzen
        push    ax                      ; warten ?
        pop     ax
        out     dma+11,al               ; mode setzen

;-----phys. Adresse zum DMA ausgeben:

        mov     ax,es
        mov     cl,4
        rol     ax,cl                   ; h - nibble von es nach al
        mov     ch,al
        and     al,0f0h
        add     ax,bx
        jnc     j33
        inc     ch                      ; Uebertrag notieren
j33:    out     dma+6,al                ; a0 - a7 ausgeben
        push    ax                      ; fuer Ueberlauftest merken
        mov     al,ah
        out     dma+6,al                ; a8 - a15 ausgeben
        mov     al,ch
        and     al,0fh
        out     dma_high,al             ; a16 - a19 ausgeben

;-----Blocklaenge zum DMA ausgeben:

        mov     ax,511                  ; Blocklaenge
        out     dma+7,al                ; Blocklaenge ausgeben
        mov     al,ah
        out     dma+7,al
        sti                             ; Interrupts scharfmachen
        pop     ax
        add     ax,511                  ; 64k Overflow testen
        jnc     gx                      ; wenn kein Overflow
        mov     disk_status, dma_boundary
        ret

gx:     call command
        jc      error_chk               ; wenn was schiefgelaufen ist

        mov     al,3                    ; controller dma/interrupt register mask
        out     dma+10,al               ; initialize the disk channel
g3:
        in      al,21h
        and     al,0dfh
        out     21h,al

;-------------------------------------------------------;
;       wait_int
;       this routine waits for the fixed disk
;       controller to signal, that an interrupt
;       has occured
;-------------------------------------------------------;

        sti                             ; muss das nochmal sein ???
        push    es
        push    si

;----- set timeout values
        sub     bh,bh
        mov     bl,TIMEOUT1             ; timout Zaehler setzen (high word)
        sub     cx,cx

;----- wait for interrupt
w1:
        push    ds
        push    bx
        push    cx
        call    cs:warte                   ; nicht dumm rumloopen, sondern
        pop     cx                      ;    arbeiten !!
        pop     bx
        pop     ds

        mov     dx,hf_port+1
        in      al,dx
        and     al,20h
        cmp     al,20h
        jz      w2
        loop    w1
        dec     bx
        jnz     w1
        mov     disk_status,time_out

w2:     mov     dx, hf_port
        in      al,dx
        and     al,2
        or      disk_status,al          ; Fehler merken
        mov     dx,hf_port+3
        xor     al,al
        out     dx,al
        pop     si
        pop     es

;-----------------------------------------------;
;       error_chk                               ;
;-----------------------------------------------;

error_chk:
        ret                             ; zunaechst keine Fehler- Auswertung
        mov     al,disk_status
        or      al,al
        jnz     g21
        ret

;-----perform sense status

g21:    mov     ax, shard
        mov     es,ax
        sub     ax,ax
        mov     di,ax
        mov     cmd_block+0, sense_cmd
        sub     al,al
        call    command
        jc      sense_abort
        mov     cx,4
g22:
        call    hd_wait_req
        jc      g24
        mov     dx,hf_port
        in      al,dx
        mov     hd_error[di],al
        inc     di
        mov     dx,hf_port+1
        loop    g22
        call    hd_wait_req
        jc      g24
        mov     dx,hf_port
        in      al,dx
        test    al,2
        jz      stat_err
sense_abort:
        mov     disk_status, sense_fail
g24:
        stc
        ret
do_io   endp

;========================================================
;       command
;       erklaert dem controller, was zu tun ist
;   input
;       cmd_block
;========================================================

command proc    near

        mov     dx,hf_port+2
        out     dx,al                   ; controller select pulse ausgeben
        mov     dx,hf_port+3
        mov     al,3            ; controller dma/interrupt register mask
        out     dx,al                   ; DMA und Interrupt-Maske setzen

; eigentlich ist es nicht normal, wenn der Controller an dieser
; Stelle beschaeftigt ist, aber wer weiss ...

        sub     cx,cx                   ; timeout - Zaehler setzen
        mov     dx,hf_port+1
wait_busy:
        in      al,dx                   ; status lesen
        and     al,0fh
        cmp     al,r1_busy or r1_bus or r1_req
        je      weiter_gehts            ; weiter, wenn controller frei
        loop    wait_busy               ; warten...
        mov     disk_status, time_out   ; is nix
        stc
        ret

weiter_gehts:
        cld                             ; clear direction flag
        mov     cx,6                    ; Blocklaenge fuer move
        mov     si, offset cmd_block

cm3:    mov     dx,hf_port              ; Command-Block ausgeben
        lodsb                           ; 
        out     dx,al
        loop    cm3

        inc     dx                      ; weiter nach hf_port+1
        in      al,dx                   ; status lesen
        test    al,r1_req
        jz      cm7                     ; wenn alles ok
        mov     disk_status, bad_cntlr  ; war nix
        stc
cm7:
        ret
command endp


;================================================================
;       hd_int
;================================================================

hd_int  proc    near
        push    ax
        mov     al,eoi                  ; end of interrupt
        out     int_ctl_port,al
        mov     al,7                    ; set dma mode to disable
        out     dma+10,al
        in      al,21h
        or      al,20h
        out     21h,al
        pop     ax
        iret
hd_int  endp


t_0     dw      type_0
t_1     dw      type_1
t_2     dw      type_2
t_3     dw      type_3


stat_err:
        mov     bl,es:hd_error          ; get error byte
        mov     al,bl
        and     al,0fh
        and     bl,00110000b
        sub     bh,bh
        mov     cl,3
        shr     bx,cl
        jmp     word ptr cs:[bx + offset t_0]

type0_table     label byte
        db      0, bad_cntlr, bad_seek, bad_cntlr, time_out, 0, bad_cntlr
        db      0, bad_seek
type0_len       equ     $-type0_table

type1_table     label   byte
        db      bad_ecc, bad_ecc, bad_addr_mark, 0, record_not_fnd
        db      bad_seek, 0, 0, data_corrected, bad_track
type1_len       equ     $-type1_table

type2_table     label byte
        db      bad_cmd, bad_addr_mark
type2_len       equ     $-type2_table

type3_table     label   byte
        db      bad_cntlr, bad_cntlr, bad_ecc
type3_len       equ     $-type3_table

type_0:
                ret
type_1:
                ret
type_2:
                ret
type_3:
                ret

;================================================================
;       hd_wait_req
;================================================================

hd_wait_req     proc near
        push    cx
        sub     cx,cx                   ; timeout - Zaehler setzen
        mov     dx,hf_port + 1
l1:
        in      al,dx
        test    al,r1_req
        jnz     l2                      ; wenn ok
        loop    l1
        mov     disk_status, time_out
        stc
l2:
        pop     cx
        ret
hd_wait_req     endp


;       end