Subversion Repositories Kolibri OS

Rev

Rev 2288 | Rev 3539 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2288 clevermous 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
2455 mario79 3
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;;
2288 clevermous 4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7
 
8
$Revision: 2455 $
9
 
10
 
11
;**********************************************************
12
;  Непосредственная работа с контроллером гибкого диска
13
;**********************************************************
14
; Автор исходного текста  Кулаков Владимир Геннадьевич.
15
; Адаптация и доработка Mario79
16
 
17
;give_back_application_data:  ; переслать приложению
18
;     mov edi,[TASK_BASE]
19
;     mov edi,[edi+TASKDATA.mem_start]
20
;     add edi,ecx
21
give_back_application_data_1:
22
        mov     esi, FDD_BUFF;FDD_DataBuffer  ;0x40000
23
        xor     ecx, ecx
24
        mov     cx, 128
25
        cld
26
        rep movsd
27
        ret
28
 
29
;take_data_from_application:   ; взять из приложени
30
;     mov esi,[TASK_BASE]
31
;     mov esi,[esi+TASKDATA.mem_start]
32
;     add esi,ecx
33
take_data_from_application_1:
34
        mov     edi, FDD_BUFF;FDD_DataBuffer  ;0x40000
35
        xor     ecx, ecx
36
        mov     cx, 128
37
        cld
38
        rep movsd
39
        ret
40
 
41
; Коды завершения операции с контроллером (FDC_Status)
42
FDC_Normal         equ 0 ;нормальное завершение
43
FDC_TimeOut        equ 1 ;ошибка тайм-аута
44
FDC_DiskNotFound   equ 2 ;в дисководе нет диска
45
FDC_TrackNotFound  equ 3 ;дорожка не найдена
46
FDC_SectorNotFound equ 4 ;сектор не найден
47
 
48
; Максимальные значения координат сектора (заданные
49
; значения соответствуют параметрам стандартного
50
; трехдюймового гибкого диска объемом 1,44 Мб)
51
MAX_Track   equ 79
52
MAX_Head    equ  1
53
MAX_Sector  equ 18
54
 
55
uglobal
56
; Счетчик тиков таймера
57
TickCounter dd ?
58
; Код завершения операции с контроллером НГМД
59
FDC_Status  DB ?
60
; Флаг прерывания от НГМД
61
FDD_IntFlag DB ?
62
; Момент начала последней операции с НГМД
63
FDD_Time    DD ?
64
; Номер дисковода
65
FDD_Type    db 0
66
; Координаты сектора
67
FDD_Track   DB ?
68
FDD_Head    DB ?
69
FDD_Sector  DB ?
70
 
71
; Блок результата операции
72
FDC_ST0 DB ?
73
FDC_ST1 DB ?
74
FDC_ST2 DB ?
75
FDC_C   DB ?
76
FDC_H   DB ?
77
FDC_R   DB ?
78
FDC_N   DB ?
79
; Счетчик повторения операции чтени
80
ReadRepCounter  DB ?
81
; Счетчик повторения операции рекалибровки
82
RecalRepCounter DB ?
83
endg
84
; Область памяти для хранения прочитанного сектора
85
;FDD_DataBuffer:  times 512 db 0   ;DB 512 DUP (?)
86
fdd_motor_status db 0
87
timer_fdd_motor  dd 0
88
 
89
;*************************************
90
;* ИНИЦИАЛИЗАЦИЯ РЕЖИМА ПДП ДЛЯ НГМД *
91
;*************************************
92
Init_FDC_DMA:
93
        pushad
94
        mov     al, 0
95
        out     0x0c, al; reset the flip-flop to a known state.
96
        mov     al, 6           ; mask channel 2 so we can reprogram it.
97
        out     0x0a, al
98
        mov     al, [dmamode]; 0x46 -> Read from floppy - 0x4A Write to floppy
99
        out     0x0b, al
100
        mov     al, 0
101
        out     0x0c, al; reset the flip-flop to a known state.
102
        mov     eax, 0xD000
103
        out     0x04, al; set the channel 2 starting address to 0
104
        shr     eax, 8
105
        out     0x04, al
106
        shr     eax, 8
107
        out     0x81, al
108
        mov     al, 0
109
        out     0x0c, al; reset flip-flop
110
        mov     al, 0xff;set count (actual size -1)
111
        out     0x5, al
112
        mov     al, 0x1;[dmasize]       ;(0x1ff = 511 / 0x23ff =9215)
113
        out     0x5, al
114
        mov     al, 2
115
        out     0xa, al
116
        popad
117
        ret
118
 
119
;***********************************
120
;* ЗАПИСАТЬ БАЙТ В ПОРТ ДАННЫХ FDC *
121
;* Параметры:                      *
122
;* AL - выводимый байт.            *
123
;***********************************
124
FDCDataOutput:
125
;        pusha
126
        push    eax ecx edx
127
        mov     AH, AL    ;запомнить байт в AH
128
; Сбросить переменную состояния контроллера
129
        mov     [FDC_Status], FDC_Normal
130
; Проверить готовность контроллера к приему данных
131
        mov     DX, 3F4h  ;(порт состояния FDC)
132
        mov     ecx, 0x10000 ;установить счетчик тайм-аута
133
@@TestRS:
134
        in      AL, DX    ;прочитать регистр RS
135
        and     AL, 0C0h  ;выделить разряды 6 и 7
136
        cmp     AL, 80h   ;проверить разряды 6 и 7
137
        je      @@OutByteToFDC
138
        loop    @@TestRS
139
; Ошибка тайм-аута
140
        mov     [FDC_Status], FDC_TimeOut
141
        jmp     @@End_5
142
; Вывести байт в порт данных
143
@@OutByteToFDC:
144
        inc     DX
145
        mov     AL, AH
146
        out     DX, AL
147
@@End_5:
148
;        popa
149
        pop     edx ecx eax
150
        ret
151
 
152
;******************************************
153
;*   ПРОЧИТАТЬ БАЙТ ИЗ ПОРТА ДАННЫХ FDC   *
154
;* Процедура не имеет входных параметров. *
155
;* Выходные данные:                       *
156
;* AL - считанный байт.                   *
157
;******************************************
158
FDCDataInput:
159
        push    ECX
160
        push    DX
161
; Сбросить переменную состояния контроллера
162
        mov     [FDC_Status], FDC_Normal
163
; Проверить готовность контроллера к передаче данных
164
        mov     DX, 3F4h  ;(порт состояния FDC)
165
        xor     CX, CX    ;установить счетчик тайм-аута
166
@@TestRS_1:
167
        in      AL, DX    ;прочитать регистр RS
168
        and     AL, 0C0h  ;выдлить разряды 6 и 7
169
        cmp     AL, 0C0h  ;проверить разряды 6 и 7
170
        je      @@GetByteFromFDC
171
        loop    @@TestRS_1
172
; Ошибка тайм-аута
173
        mov     [FDC_Status], FDC_TimeOut
174
        jmp     @@End_6
175
; Ввести байт из порта данных
176
@@GetByteFromFDC:
177
        inc     DX
178
        in      AL, DX
179
@@End_6:
180
        pop     DX
181
        pop     ECX
182
        ret
183
 
184
;*********************************************
185
;* ОБРАБОТЧИК ПРЕРЫВАНИЯ ОТ КОНТРОЛЛЕРА НГМД *
186
;*********************************************
187
FDCInterrupt:
188
; Установить флаг прерывани
189
        mov     [FDD_IntFlag], 1
190
        ret
191
 
192
 
193
;******************************************
194
;* УСТАНОВИТЬ НОВЫЙ ОБРАБОТЧИК ПРЕРЫВАНИЙ *
195
;*             НГМД                       *
196
;******************************************
197
SetUserInterrupts:
198
        mov     [fdc_irq_func], FDCInterrupt
199
        ret
200
 
201
;*******************************************
202
;* ОЖИДАНИЕ ПРЕРЫВАНИЯ ОТ КОНТРОЛЛЕРА НГМД *
203
;*******************************************
204
WaitFDCInterrupt:
205
        pusha
206
; Сбросить байт состояния операции
207
        mov     [FDC_Status], FDC_Normal
208
; Сбросить флаг прерывани
209
        mov     [FDD_IntFlag], 0
210
; Обнулить счетчик тиков
211
        mov     eax, [timer_ticks]
212
        mov     [TickCounter], eax
213
; Ожидать установки флага прерывания НГМД
214
@@TestRS_2:
215
        cmp     [FDD_IntFlag], 0
216
        jnz     @@End_7           ;прерывание произошло
217
        call    change_task
218
        mov     eax, [timer_ticks]
219
        sub     eax, [TickCounter]
220
        cmp     eax, 50 ;25   ;5 ;ожидать 5 тиков
221
        jb      @@TestRS_2
222
;        jl      @@TestRS_2
223
; Ошибка тайм-аута
224
        mov     [FDC_Status], FDC_TimeOut
225
;        mov   [flp_status],0
226
@@End_7:
227
        popa
228
        ret
229
 
230
;*********************************
231
;* ВКЛЮЧИТЬ МОТОР ДИСКОВОДА "A:" *
232
;*********************************
233
FDDMotorON:
234
        pusha
235
;        cmp     [fdd_motor_status],1
236
;        je      fdd_motor_on
237
        mov     al, [flp_number]
238
        cmp     [fdd_motor_status], al
239
        je      fdd_motor_on
240
; Произвести сброс контроллера НГМД
241
        mov     DX, 3F2h;порт управления двигателями
242
        mov     AL, 0
243
        out     DX, AL
244
; Выбрать и включить мотор дисковода
245
        cmp     [flp_number], 1
246
        jne     FDDMotorON_B
247
;        call    FDDMotorOFF_B
248
        mov     AL, 1Ch   ; Floppy A
249
        jmp     FDDMotorON_1
250
FDDMotorON_B:
251
;        call    FDDMotorOFF_A
252
        mov     AL, 2Dh   ; Floppy B
253
FDDMotorON_1:
254
        out     DX, AL
255
; Обнулить счетчик тиков
256
        mov     eax, [timer_ticks]
257
        mov     [TickCounter], eax
258
; Ожидать 0,5 с
259
@@dT:
260
        call    change_task
261
        mov     eax, [timer_ticks]
262
        sub     eax, [TickCounter]
263
        cmp     eax, 50 ;10
264
        jb      @@dT
265
        cmp     [flp_number], 1
266
        jne     fdd_motor_on_B
267
        mov     [fdd_motor_status], 1
268
        jmp     fdd_motor_on
269
fdd_motor_on_B:
270
        mov     [fdd_motor_status], 2
271
fdd_motor_on:
272
        call    save_timer_fdd_motor
273
        popa
274
        ret
275
 
276
;*****************************************
277
;*  СОХРАНЕНИЕ УКАЗАТЕЛЯ ВРЕМЕНИ         *
278
;*****************************************
279
save_timer_fdd_motor:
280
        mov     eax, [timer_ticks]
281
        mov     [timer_fdd_motor], eax
282
        ret
283
 
284
;*****************************************
285
;*  ПРОВЕРКА ЗАДЕРЖКИ ВЫКЛЮЧЕНИЯ МОТОРА  *
286
;*****************************************
287
align 4
288
check_fdd_motor_status:
289
        cmp     [fdd_motor_status], 0
290
        je      end_check_fdd_motor_status_1
291
        mov     eax, [timer_ticks]
292
        sub     eax, [timer_fdd_motor]
293
        cmp     eax, 500
294
        jb      end_check_fdd_motor_status
295
        call    FDDMotorOFF
296
        mov     [fdd_motor_status], 0
297
end_check_fdd_motor_status_1:
298
        mov     [flp_status], 0
299
end_check_fdd_motor_status:
300
        ret
301
 
302
;**********************************
303
;* ВЫКЛЮЧИТЬ МОТОР ДИСКОВОДА      *
304
;**********************************
305
FDDMotorOFF:
306
        push    AX
307
        push    DX
308
        cmp     [flp_number], 1
309
        jne     FDDMotorOFF_1
310
        call    FDDMotorOFF_A
311
        jmp     FDDMotorOFF_2
312
FDDMotorOFF_1:
313
        call    FDDMotorOFF_B
314
FDDMotorOFF_2:
315
        pop     DX
316
        pop     AX
317
        ; сброс флагов кеширования в связи с устареванием информации
318
        mov     [root_read], 0
319
        mov     [flp_fat], 0
320
        ret
321
 
322
FDDMotorOFF_A:
323
        mov     DX, 3F2h;порт управления двигателями
324
        mov     AL, 0Ch ; Floppy A
325
        out     DX, AL
326
        ret
327
 
328
FDDMotorOFF_B:
329
        mov     DX, 3F2h;порт управления двигателями
330
        mov     AL, 5h ; Floppy B
331
        out     DX, AL
332
        ret
333
 
334
;*******************************
335
;* РЕКАЛИБРОВКА ДИСКОВОДА "A:" *
336
;*******************************
337
RecalibrateFDD:
338
        pusha
339
        call    save_timer_fdd_motor
340
; Подать команду "Рекалибровка"
341
        mov     AL, 07h
342
        call    FDCDataOutput
343
        mov     AL, 00h
344
        call    FDCDataOutput
345
; Ожидать завершения операции
346
        call    WaitFDCInterrupt
347
;        cmp    [FDC_Status],0
348
;        je    no_fdc_status_error
349
;        mov   [flp_status],0
350
;no_fdc_status_error:
351
        call    save_timer_fdd_motor
352
        popa
353
        ret
354
 
355
;*****************************************************
356
;*                    ПОИСК ДОРОЖКИ                  *
357
;* Параметры передаются через глобальные переменные: *
358
;* FDD_Track - номер дорожки (0-79);                 *
359
;* FDD_Head - номер головки (0-1).                   *
360
;* Результат операции заносится в FDC_Status.        *
361
;*****************************************************
362
SeekTrack:
363
        pusha
364
        call    save_timer_fdd_motor
365
; Подать команду "Поиск"
366
        mov     AL, 0Fh
367
        call    FDCDataOutput
368
        ; Передать байт номера головки/накопител
369
        mov     AL, [FDD_Head]
370
        shl     AL, 2
371
        call    FDCDataOutput
372
        ; Передать байт номера дорожки
373
        mov     AL, [FDD_Track]
374
        call    FDCDataOutput
375
; Ожидать завершения операции
376
        call    WaitFDCInterrupt
377
        cmp     [FDC_Status], FDC_Normal
378
        jne     @@Exit
379
; Сохранить результат поиска
380
        mov     AL, 08h
381
        call    FDCDataOutput
382
        call    FDCDataInput
383
        mov     [FDC_ST0], AL
384
        call    FDCDataInput
385
        mov     [FDC_C], AL
386
; Проверить результат поиска
387
        ; Поиск завершен?
388
        test    [FDC_ST0], 100000b
389
        je      @@Err
390
        ; Заданный трек найден?
391
        mov     AL, [FDC_C]
392
        cmp     AL, [FDD_Track]
393
        jne     @@Err
394
        ; Номер головки совпадает с заданным?
395
        mov     AL, [FDC_ST0]
396
        and     AL, 100b
397
        shr     AL, 2
398
        cmp     AL, [FDD_Head]
399
        jne     @@Err
400
        ; Операция завершена успешно
401
        mov     [FDC_Status], FDC_Normal
402
        jmp     @@Exit
403
@@Err:  ; Трек не найден
404
        mov     [FDC_Status], FDC_TrackNotFound
405
;        mov   [flp_status],0
406
@@Exit:
407
        call    save_timer_fdd_motor
408
        popa
409
        ret
410
 
411
;*******************************************************
412
;*               ЧТЕНИЕ СЕКТОРА ДАННЫХ                 *
413
;* Параметры передаются через глобальные переменные:   *
414
;* FDD_Track - номер дорожки (0-79);                   *
415
;* FDD_Head - номер головки (0-1);                     *
416
;* FDD_Sector - номер сектора (1-18).                  *
417
;* Результат операции заносится в FDC_Status.          *
418
;* В случае успешного выполнения операции чтения       *
419
;* содержимое сектора будет занесено в FDD_DataBuffer. *
420
;*******************************************************
421
ReadSector:
422
        pushad
423
        call    save_timer_fdd_motor
424
; Установить скорость передачи 500 Кбайт/с
425
        mov     AX, 0
426
        mov     DX, 03F7h
427
        out     DX, AL
428
; Инициализировать канал прямого доступа к памяти
429
        mov     [dmamode], 0x46
430
        call    Init_FDC_DMA
431
; Подать команду "Чтение данных"
432
        mov     AL, 0E6h ;чтение в мультитрековом режиме
433
        call    FDCDataOutput
434
        mov     AL, [FDD_Head]
435
        shl     AL, 2
436
        call    FDCDataOutput
437
        mov     AL, [FDD_Track]
438
        call    FDCDataOutput
439
        mov     AL, [FDD_Head]
440
        call    FDCDataOutput
441
        mov     AL, [FDD_Sector]
442
        call    FDCDataOutput
443
        mov     AL, 2   ;код размера сектора (512 байт)
444
        call    FDCDataOutput
445
        mov     AL, 18 ;+1; 3Fh  ;число секторов на дорожке
446
        call    FDCDataOutput
447
        mov     AL, 1Bh ;значение GPL
448
        call    FDCDataOutput
449
        mov     AL, 0FFh;значение DTL
450
        call    FDCDataOutput
451
; Ожидаем прерывание по завершении операции
452
        call    WaitFDCInterrupt
453
        cmp     [FDC_Status], FDC_Normal
454
        jne     @@Exit_1
455
; Считываем статус завершения операции
456
        call    GetStatusInfo
457
        test    [FDC_ST0], 11011000b
458
        jnz     @@Err_1
459
        mov     [FDC_Status], FDC_Normal
460
        jmp     @@Exit_1
461
@@Err_1:
462
        mov     [FDC_Status], FDC_SectorNotFound
463
;        mov   [flp_status],0
464
@@Exit_1:
465
        call    save_timer_fdd_motor
466
        popad
467
        ret
468
 
469
;*******************************************************
470
;*   ЧТЕНИЕ СЕКТОРА (С ПОВТОРЕНИЕМ ОПЕРАЦИИ ПРИ СБОЕ)  *
471
;* Параметры передаются через глобальные переменные:   *
472
;* FDD_Track - номер дорожки (0-79);                   *
473
;* FDD_Head - номер головки (0-1);                     *
474
;* FDD_Sector - номер сектора (1-18).                  *
475
;* Результат операции заносится в FDC_Status.          *
476
;* В случае успешного выполнения операции чтения       *
477
;* содержимое сектора будет занесено в FDD_DataBuffer. *
478
;*******************************************************
479
ReadSectWithRetr:
480
        pusha
481
; Обнулить счетчик повторения операции рекалибровки
482
        mov     [RecalRepCounter], 0
483
@@TryAgain:
484
; Обнулить счетчик повторения операции чтени
485
        mov     [ReadRepCounter], 0
486
@@ReadSector_1:
487
        call    ReadSector
488
        cmp     [FDC_Status], 0
489
        je      @@Exit_2
490
        cmp     [FDC_Status], 1
491
        je      @@Err_3
492
        ; Троекратное повторение чтени
493
        inc     [ReadRepCounter]
494
        cmp     [ReadRepCounter], 3
495
        jb      @@ReadSector_1
496
        ; Троекратное повторение рекалибровки
497
        call    RecalibrateFDD
498
        call    SeekTrack
499
        inc     [RecalRepCounter]
500
        cmp     [RecalRepCounter], 3
501
        jb      @@TryAgain
502
;        mov   [flp_status],0
503
@@Exit_2:
504
        popa
505
        ret
506
@@Err_3:
507
        mov     [flp_status], 0
508
        popa
509
        ret
510
 
511
;*******************************************************
512
;*               ЗАПИСЬ СЕКТОРА ДАННЫХ                 *
513
;* Параметры передаются через глобальные переменные:   *
514
;* FDD_Track - номер дорожки (0-79);                   *
515
;* FDD_Head - номер головки (0-1);                     *
516
;* FDD_Sector - номер сектора (1-18).                  *
517
;* Результат операции заносится в FDC_Status.          *
518
;* В случае успешного выполнения операции записи       *
519
;* содержимое FDD_DataBuffer будет занесено в сектор.  *
520
;*******************************************************
521
WriteSector:
522
        pushad
523
        call    save_timer_fdd_motor
524
; Установить скорость передачи 500 Кбайт/с
525
        mov     AX, 0
526
        mov     DX, 03F7h
527
        out     DX, AL
528
; Инициализировать канал прямого доступа к памяти
529
        mov     [dmamode], 0x4A
530
        call    Init_FDC_DMA
531
; Подать команду "Запись данных"
532
        mov     AL, 0xC5 ;0x45  ;запись в мультитрековом режиме
533
        call    FDCDataOutput
534
        mov     AL, [FDD_Head]
535
        shl     AL, 2
536
        call    FDCDataOutput
537
        mov     AL, [FDD_Track]
538
        call    FDCDataOutput
539
        mov     AL, [FDD_Head]
540
        call    FDCDataOutput
541
        mov     AL, [FDD_Sector]
542
        call    FDCDataOutput
543
        mov     AL, 2   ;код размера сектора (512 байт)
544
        call    FDCDataOutput
545
        mov     AL, 18; 3Fh  ;число секторов на дорожке
546
        call    FDCDataOutput
547
        mov     AL, 1Bh ;значение GPL
548
        call    FDCDataOutput
549
        mov     AL, 0FFh;значение DTL
550
        call    FDCDataOutput
551
; Ожидаем прерывание по завершении операции
552
        call    WaitFDCInterrupt
553
        cmp     [FDC_Status], FDC_Normal
554
        jne     @@Exit_3
555
; Считываем статус завершения операции
556
        call    GetStatusInfo
557
        test    [FDC_ST0], 11000000b ;11011000b
558
        jnz     @@Err_2
559
        mov     [FDC_Status], FDC_Normal
560
        jmp     @@Exit_3
561
@@Err_2:
562
        mov     [FDC_Status], FDC_SectorNotFound
563
@@Exit_3:
564
        call    save_timer_fdd_motor
565
        popad
566
        ret
567
 
568
;*******************************************************
569
;*   ЗАПИСЬ СЕКТОРА (С ПОВТОРЕНИЕМ ОПЕРАЦИИ ПРИ СБОЕ)  *
570
;* Параметры передаются через глобальные переменные:   *
571
;* FDD_Track - номер дорожки (0-79);                   *
572
;* FDD_Head - номер головки (0-1);                     *
573
;* FDD_Sector - номер сектора (1-18).                  *
574
;* Результат операции заносится в FDC_Status.          *
575
;* В случае успешного выполнения операции записи       *
576
;* содержимое FDD_DataBuffer будет занесено в сектор.  *
577
;*******************************************************
578
WriteSectWithRetr:
579
        pusha
580
; Обнулить счетчик повторения операции рекалибровки
581
        mov     [RecalRepCounter], 0
582
@@TryAgain_1:
583
; Обнулить счетчик повторения операции чтени
584
        mov     [ReadRepCounter], 0
585
@@WriteSector_1:
586
        call    WriteSector
587
        cmp     [FDC_Status], 0
588
        je      @@Exit_4
589
        cmp     [FDC_Status], 1
590
        je      @@Err_4
591
        ; Троекратное повторение чтени
592
        inc     [ReadRepCounter]
593
        cmp     [ReadRepCounter], 3
594
        jb      @@WriteSector_1
595
        ; Троекратное повторение рекалибровки
596
        call    RecalibrateFDD
597
        call    SeekTrack
598
        inc     [RecalRepCounter]
599
        cmp     [RecalRepCounter], 3
600
        jb      @@TryAgain_1
601
@@Exit_4:
602
        popa
603
        ret
604
@@Err_4:
605
        mov     [flp_status], 0
606
        popa
607
        ret
608
 
609
;*********************************************
610
;* ПОЛУЧИТЬ ИНФОРМАЦИЮ О РЕЗУЛЬТАТЕ ОПЕРАЦИИ *
611
;*********************************************
612
GetStatusInfo:
613
        push    AX
614
        call    FDCDataInput
615
        mov     [FDC_ST0], AL
616
        call    FDCDataInput
617
        mov     [FDC_ST1], AL
618
        call    FDCDataInput
619
        mov     [FDC_ST2], AL
620
        call    FDCDataInput
621
        mov     [FDC_C], AL
622
        call    FDCDataInput
623
        mov     [FDC_H], AL
624
        call    FDCDataInput
625
        mov     [FDC_R], AL
626
        call    FDCDataInput
627
        mov     [FDC_N], AL
628
        pop     AX
629
        ret
630