Оглавление
- Чтение и запись
- Инициализация каналов DMA для FDC
- Подготовить DMA на чтение или запись
- Процедуры
- Вспомогательные процедуры чтения и записи в DMA
- Обработчик прерываний (IRQ #6)
- Переменные для FDC
- Константы
§ Чтение и запись
Главные процедуры для чтения и записи на диск.Требуется реализация переменной
irq_timer_counter
, которая будет инкрементироваться +1 каждые 1/100 сек. Это нужно для включения и выключения мотора.-
fdc_read
иfdc_write
запускают чтение или запись, но ответ не ожидается, можно выполнять программу далее. Статус готовности проверяется по наличию не нулевого значения в fdc.ready -
fdc_read_sync
иfdc_write_sync
делают тоже самое, но ответ ожидается
1; Чтение сектора (AX) в $1000 -> IRQ #6 2fdc_read: 3 4 mov [fdc.lba], ax ; Запрошенный LBA 5 call fdc_prepare 6 call fdc_dma_read 7 mov bl, 0 8 call fdc_rw ; BL=0 READ 9 ret 10 11; Запись сектора (AX) из $1000 -> IRQ #6 12fdc_write: 13 14 mov [fdc.lba], ax 15 call fdc_prepare 16 call fdc_dma_write 17 mov bl, 1 18 call fdc_rw ; BL=1 WRITE 19 ret 20 21; Чтение AX сектора в $1000, ждать ответа 22fdc_read_sync: 23 24 call fdc_read 25@@: cmp [fdc.ready], byte 0 26 je @b 27 ret 28 29; Запись AX сектора из $1000, ждать ответа 30fdc_write_sync: 31 32 call fdc_write 33@@: cmp [fdc.ready], byte 0 34 je @b 35 ret
§ Инициализация каналов DMA для FDC
Эта процедура программирует контроллер DMA для работы дискеты.1fdc_init: 2 3 ; Установка DMA 4 mov al, $06 5 out $0A, al ; Маскирование DMA channel 2 и 0 6 7 ; Адрес $1000 8 mov al, $FF 9 out $0C, al ; Сброс master flip-flop 10 mov al, $00 11 out $04, al ; [7:0] 12 mov al, $10 13 out $04, al ; [15:8] 14 15 ; Размер $3FFF 16 mov al, $FF 17 out $0C, al ; Сброс master flip-flop 18 mov al, $FF 19 out $05, al ; [7:0] 20 mov al, $3F 21 out $05, al ; [15:8] 22 23 ; Адрес $00 24 mov al, $00 25 out $81, al ; [23:16] 26 mov al, $02 27 out $0A, al ; Размаскировать DMA channel 2 28 29 ; Инициализация 30 mov [fdc.motor], 0 31 mov [fdc.ready], 0 32 ret 33
§ Подготовить DMA на чтение или запись
1; Подготовить диск на чтение 2fdc_dma_read: 3 4 mov al, $06 ; mask DMA channel 2 and 0 (assuming 0 is already masked) 5 out $0A, al 6 mov al, $56 7 out $0B, al ; 01010110 single transfer, address increment, autoinit, read, channel2 8 mov al, $02 9 out $0A, al ; unmask DMA channel 2 10 ret 11 12; Подготовить диск на запись 13fdc_dma_write: 14 15 mov al, $06 16 out $0A, al 17 mov al, $5A 18 out $0B, al ; 01011010 single transfer, address increment, autoinit, write, channel2 19 mov al, $02 20 out $0A, al 21 ret 22
§ Процедуры
1; Ожидать завершения (проверочный параметр AH) 2fdc_wait: 3 4 push eax 5 mov dx, MAIN_STATUS_REGISTER 6@@: in al, dx 7 and al, ah 8 cmp al, ah 9 jne @b 10 pop eax 11 ret 12 13; Запись данных (al) в FIFO 14fdc_write_reg: 15 16 mov ah, $80 17 call fdc_wait ; Ожидать OK 18 mov dx, FDC_DATA_FIFO 19 out dx, al ; Записать AL в FIFO 20 ret 21 22; Чтение данных (al) из FIFO 23fdc_read_reg: 24 25 mov ah, $c0 26 call fdc_wait ; Ожидать OK 27 mov dx, FDC_DATA_FIFO 28 in al, dx ; Прочесть AL из FIFO 29 ret 30 31; Проверить IRQ-статус после SEEK, CALIBRATE, etc. 32fdc_sensei: 33 34 mov al, SENSE_INTERRUPT 35 call fdc_write_reg ; Отправка запроса 36 mov ah, 0xD0 37 call fdc_wait 38 mov dx, FDC_DATA_FIFO ; Получение результата 39 in al, dx 40 mov [fdc.st0], al 41 mov ah, 0xD0 42 call fdc_wait 43 mov dx, FDC_DATA_FIFO ; Номер цилиндра 44 in al, dx 45 mov [fdc.cyl], al 46 ret 47 48; Конфигурирование 49fdc_configure: 50 51 mov al, SPECIFY 52 call fdc_write_reg 53 mov al, 0 54 call fdc_write_reg ; steprate_headunload 55 call fdc_write_reg ; headload_ndma 56 ret 57 58; Калибрация драйва 59fdc_calibrate: 60 61 call fdc_motor_on 62 mov [fdc.func], FDC_STATUS_SENSEI 63 mov [fdc.ready], 0 64 mov al, RECALIBRATE 65 call fdc_write_reg ; Команда, Drive = A: 66 mov al, 0 67 call fdc_write_reg ; Команда, Drive = A: 68@@: cmp [fdc.ready], 0 ; Ожидать ответа IRQ 69 je @b 70 ret 71 72; Сбросить контроллер перед работой с диском 73fdc_reset: 74 75 mov [fdc.func], FDC_STATUS_SENSEI 76 mov [fdc.ready], 0 77 78 ; Отключить и включить контроллер 79 mov dx, DIGITAL_OUTPUT_REGISTER 80 mov al, $00 81 out dx, al 82 mov al, $0C 83 out dx, al 84@@: cmp [fdc.ready], 0 ; Ожидать ответа IRQ 85 je @b 86 87 ; Конфигурирование 88 mov dx, CONFIGURATION_CONTROL_REGISTER 89 mov al, 0 90 out dx, al 91 call fdc_configure 92 call fdc_calibrate 93 ret 94 95; Сбор результирующих данных: если > 0, то ошибка 96fdc_get_result: 97 98 call fdc_read_reg 99 mov [fdc.st0], al 100 call fdc_read_reg 101 mov [fdc.st1], al 102 call fdc_read_reg 103 mov [fdc.st2], al 104 call fdc_read_reg 105 mov [fdc.cyl], al 106 call fdc_read_reg 107 mov [fdc.head_end], al 108 call fdc_read_reg 109 mov [fdc.head_start], al 110 call fdc_read_reg 111 and al, $c0 112 ret 113 114; Преобразовать ax=LBA -> CHS 115fdc_lba2chs: 116 117 xor dx, dx 118 mov bx, 18 119 div bx 120 inc dl 121 mov [fdc.r_sec], dl 122 mov dl, al 123 and dl, 1 124 mov [fdc.r_hd], dl 125 shr ax, 1 126 mov [fdc.r_cyl], al 127 ret 128 129; Включить мотор 130fdc_motor_on: 131 132 cli 133 mov [fdc.motor], 1 ; Включение 134 sti 135 mov eax, [irq_timer_counter] 136 mov [fdc.motor_time], eax ; Запись таймера 137 mov dx, DIGITAL_OUTPUT_REGISTER ; Регистр DOR = $1C (On) 138 mov al, 0x1C 139 out dx, al 140 ret 141 142; Выключить мотор 143fdc_motor_off: 144 145 cli 146 mov [fdc.motor], 0 147 sti 148 xor eax, eax 149 mov dx, DIGITAL_OUTPUT_REGISTER ; Отключить 150 out dx, al 151 ret
§ Вспомогательные процедуры чтения и записи в DMA
Процедура записи и чтения на диск.1; bl = 0 READ; 1 WRITE 2; ax = lba 3; (byte write, byte head, byte cyl, byte sector) 4 5fdc_rw: 6 7 mov [fdc.ready], 0 8 mov [fdc.func], FDC_STATUS_RW 9 mov ax, $4546 10 and bl, bl 11 je @f 12 mov al, ah 13@@: call fdc_write_reg ; 0 MFM_bit = 0x40 | (W=0x45 | R=0x46) 14 mov al, [fdc.r_hd] 15 shl al, 2 16 call fdc_write_reg ; 1 17 18 mov al, [fdc.r_cyl] 19 call fdc_write_reg 20 mov al, [fdc.r_hd] 21 call fdc_write_reg 22 mov al, [fdc.r_sec] 23 call fdc_write_reg 24 mov al, 2 25 call fdc_write_reg ; 5 Размер сектора (2 ~> 512 bytes) 26 mov al, 18 27 call fdc_write_reg ; 6 Последний сектор в цилиндре 28 mov al, $1B 29 call fdc_write_reg ; 7 Длина GAP3 30 mov al, $FF 31 call fdc_write_reg ; 8 Длина данных, игнорируется 32 ret 33 34; Поиск дорожки => IRQ #6 35fdc_seek: 36 37 mov [fdc.ready], 0 38 mov [fdc.func], FDC_STATUS_SEEK 39 mov al, SEEK 40 call fdc_write_reg ; Команда 41 mov al, [fdc.r_hd] 42 shl al, 2 43 call fdc_write_reg ; head<<2 44 mov al, [fdc.r_cyl] 45 call fdc_write_reg ; Цилиндр 46 ret 47 48; Подготовить диск для чтения/записи (AX = LBA) 49fdc_prepare: 50 51 call fdc_lba2chs ; Вычислить LBA 52 mov [fdc.error], 0 ; Отметить, что ошибок пока нет 53 mov eax, [irq_timer_counter] 54 mov [fdc.motor_time], eax 55 cmp [fdc.motor], 0 ; Включить мотор, если нужно 56 jne @f 57 call fdc_reset 58@@: call fdc_seek 59@@: cmp [fdc.ready], 0 ; Ожидать ответа IRQ 60 je @b 61 ret
§ Обработчик прерываний (IRQ #6)
1fdc_irq: 2 3 pushad 4 cmp [fdc.func], byte FDC_STATUS_RW 5 je .rw 6 call fdc_sensei ; Выполнить считывание рез-та 7 jmp .exit 8.rw: call fdc_get_result ; Забрать результат при R/W 9 and al, al 10 jne .exit 11 mov [fdc.error], byte 1 ; Ошибка чтения при al > 0 12.exit: mov [fdc.ready], byte 1 ; Завершено 13 mov al, $20 ; EOI 14 out $20, al 15 popad 16 iretd 17 18; Вычисление таймаута и выключение FDC из прерывания IRQ #0 19; ---------------------------------------------------------------------- 20 21fdc_timeout: 22 23 cmp [fdc.motor], 0 ; Мотор включен? 24 je @f 25 mov eax, [irq_timer_counter] ; Если > 5с крутится, выключить 26 sub eax, [fdc.motor_time] 27 cmp eax, 500 28 jb @f 29 call fdc_motor_off 30@@: ret
§ Переменные для FDC
Контроллер флоппи-диска1fdc: ; 2 3 ; результат 4 .st0 db 0 ; Статусный регистр 0 5 .st1 db 0 6 .st2 db 0 7 .cyl db 0 8 .head_end db 0 9 .head_start db 0 10 11 ; функционирование 12 .motor db 0 ; Включен ли мотор 13 .motor_time dd 0 ; Время включения мотора 14 .func db 0 ; Функция запроса на IRQ 15 .ready db 0 ; IRQ обработан 16 .error db 0 ; Ошибка исполнения 17 18 ; запрос 19 .lba dw 0 20 .r_hd db 0 ; * головка 21 .r_cyl db 0 ; * цилиндр 22 .r_sec db 0 ; * сектор
§ Константы
1 2; Floppy Disk Controller 3; ---------------------------------------------------------------------- 4 5; Порты 6STATUS_REGISTER_A equ 0x3F0 ; read-only 7STATUS_REGISTER_B equ 0x3F1 ; read-only 8DIGITAL_OUTPUT_REGISTER equ 0x3F2 9TAPE_DRIVE_REGISTER equ 0x3F3 10MAIN_STATUS_REGISTER equ 0x3F4 ; read-only 11DATARATE_SELECT_REGISTER equ 0x3F4 ; write-only 12FDC_DATA_FIFO equ 0x3F5 13DIGITAL_INPUT_REGISTER equ 0x3F7 ; read-only 14CONFIGURATION_CONTROL_REGISTER equ 0x3F7 ; write-only 15 16; Команды 17READ_TRACK equ 2 ; generates IRQ6 18SPECIFY equ 3 ; * set drive parameters 19SENSE_DRIVE_STATUS equ 4 20WRITE_DATA equ 5 ; * write to the disk 21READ_DATA equ 6 ; * read from the disk 22RECALIBRATE equ 7 ; * seek to cylinder 0 23SENSE_INTERRUPT equ 8 ; * ack IRQ6, get status of last command 24WRITE_DELETED_DATA equ 9 25READ_ID equ 10 ; generates IRQ6 26READ_DELETED_DATA equ 12 27FORMAT_TRACK equ 13 28DUMPREG equ 14 29SEEK equ 15 ; * seek both heads to cylinder X 30VERSION equ 16 ; * used during initialization, once 31SCAN_EQUAL equ 17 32PERPENDICULAR_MODE equ 18 ; * used during initialization, once, maybe 33CONFIGURE equ 19 ; * set controller parameters 34LOCK equ 20 ; * protect controller params from a reset 35VERIFY equ 22 36SCAN_LOW_OR_EQUAL equ 25 37SCAN_HIGH_OR_EQUAL equ 29 38 39; Статусы 40FDC_STATUS_NONE equ 0x0 41FDC_STATUS_SEEK equ 0x1 42FDC_STATUS_RW equ 0x2 43FDC_STATUS_SENSEI equ 0x3