Требуется реализация переменной irq_timer_counter, которая будет инкрементироваться +1 каждые 1/100 сек. Это нужно для включения и выключения мотора.
fdc_read и fdc_write запускают чтение или запись, но ответ не ожидается, можно выполнять программу далее. Статус готовности проверяется по наличию не нулевого значения в fdc.ready
fdc_read_sync и fdc_write_sync делают тоже самое, но ответ ожидается
Ниже приведен код.
; Чтение сектора (AX) в $1000 -> IRQ #6
fdc_read:
mov [fdc.lba], ax; Запрошенный LBA
call fdc_prepare
call fdc_dma_read
movbl, 0
call fdc_rw ; BL=0 READ
ret
; Запись сектора (AX) из $1000 -> IRQ #6
fdc_write:
mov [fdc.lba], ax
call fdc_prepare
call fdc_dma_write
movbl, 1
call fdc_rw ; BL=1 WRITE
ret
; Чтение AX сектора в $1000, ждать ответа
fdc_read_sync:
call fdc_read
@@:cmp [fdc.ready], byte0
je @b
ret
; Запись AX сектора из $1000, ждать ответа
fdc_write_sync:
call fdc_write
@@:cmp [fdc.ready], byte0
je @b
ret
§ Инициализация каналов DMA для FDC
Эта процедура программирует контроллер DMA для работы дискеты.
fdc_init:
; Установка DMA
moval, $06
out$0A, al; Маскирование DMA channel 2 и 0
; Адрес $1000
moval, $FF
out$0C, al; Сброс master flip-flop
moval, $00
out$04, al; [7:0]
moval, $10
out$04, al; [15:8]
; Размер $3FFF
moval, $FF
out$0C, al; Сброс master flip-flop
moval, $FF
out$05, al; [7:0]
moval, $3F
out$05, al; [15:8]
; Адрес $00
moval, $00
out$81, al; [23:16]
moval, $02
out$0A, al; Размаскировать DMA channel 2
; Инициализация
mov [fdc.motor], 0
mov [fdc.ready], 0
ret
§ Подготовить DMA на чтение или запись
; Подготовить диск на чтение
fdc_dma_read:
moval, $06; mask DMA channel 2 and 0 (assuming 0 is already masked)
out$0A, al
moval, $56
out$0B, al; 01010110 single transfer, address increment, autoinit, read, channel2
moval, $02
out$0A, al; unmask DMA channel 2
ret
; Подготовить диск на запись
fdc_dma_write:
moval, $06
out$0A, al
moval, $5A
out$0B, al; 01011010 single transfer, address increment, autoinit, write, channel2
moval, $02
out$0A, al
ret
§ Процедуры
; Ожидать завершения (проверочный параметр AH)
fdc_wait:
pusheax
movdx, MAIN_STATUS_REGISTER
@@:inal, dx
andal, ah
cmpal, ah
jne @b
popeax
ret
; Запись данных (al) в FIFO
fdc_write_reg:
movah, $80
call fdc_wait ; Ожидать OK
movdx, FDC_DATA_FIFO
outdx, al; Записать AL в FIFO
ret
; Чтение данных (al) из FIFO
fdc_read_reg:
movah, $c0
call fdc_wait ; Ожидать OK
movdx, FDC_DATA_FIFO
inal, dx; Прочесть AL из FIFO
ret
; Проверить IRQ-статус после SEEK, CALIBRATE, etc.
fdc_sensei:
moval, SENSE_INTERRUPT
call fdc_write_reg ; Отправка запроса
movah, 0xD0
call fdc_wait
movdx, FDC_DATA_FIFO ; Получение результата
inal, dx
mov [fdc.st0], al
movah, 0xD0
call fdc_wait
movdx, FDC_DATA_FIFO ; Номер цилиндра
inal, dx
mov [fdc.cyl], al
ret
; Конфигурирование
fdc_configure:
moval, SPECIFY
call fdc_write_reg
moval, 0
call fdc_write_reg ; steprate_headunload
call fdc_write_reg ; headload_ndma
ret
; Калибрация драйва
fdc_calibrate:
call fdc_motor_on
mov [fdc.func], FDC_STATUS_SENSEI
mov [fdc.ready], 0
moval, RECALIBRATE
call fdc_write_reg ; Команда, Drive = A:
moval, 0
call fdc_write_reg ; Команда, Drive = A:
@@:cmp [fdc.ready], 0; Ожидать ответа IRQ
je @b
ret
; Сбросить контроллер перед работой с диском
fdc_reset:
mov [fdc.func], FDC_STATUS_SENSEI
mov [fdc.ready], 0
; Отключить и включить контроллер
movdx, DIGITAL_OUTPUT_REGISTER
moval, $00
outdx, al
moval, $0C
outdx, al
@@:cmp [fdc.ready], 0; Ожидать ответа IRQ
je @b
; Конфигурирование
movdx, CONFIGURATION_CONTROL_REGISTER
moval, 0
outdx, al
call fdc_configure
call fdc_calibrate
ret
; Сбор результирующих данных: если > 0, то ошибка
fdc_get_result:
call fdc_read_reg
mov [fdc.st0], al
call fdc_read_reg
mov [fdc.st1], al
call fdc_read_reg
mov [fdc.st2], al
call fdc_read_reg
mov [fdc.cyl], al
call fdc_read_reg
mov [fdc.head_end], al
call fdc_read_reg
mov [fdc.head_start], al
call fdc_read_reg
andal, $c0
ret
; Преобразовать ax=LBA -> CHS
fdc_lba2chs:
xordx, dx
movbx, 18
divbx
incdl
mov [fdc.r_sec], dl
movdl, al
anddl, 1
mov [fdc.r_hd], dl
shrax, 1
mov [fdc.r_cyl], al
ret
; Включить мотор
fdc_motor_on:
cli
mov [fdc.motor], 1; Включение
sti
moveax, [irq_timer_counter]
mov [fdc.motor_time], eax; Запись таймера
movdx, DIGITAL_OUTPUT_REGISTER ; Регистр DOR = $1C (On)