原文:可编程软盘控制器
这篇文章是想介绍一下使用一些寄存器对NEC uPD765和Intel 82072/7软盘控制器(FDCs)进行编程,文章分为下面4个部分:
1. Overview
2. Configuration of an FDC on a PC
3. FDC Registers
4. Command Set
Overview
PC机常常使用NEC uPD765软盘控制器,AT机还包含了Intel 82072A控制器,而PS/2机使用的是Intel 82077A控制器(PC、AT是IBM早期机种类型,PS/2是IBM新的机种)。uPD765和ROM代码组成了一个微型的控制器,它可以处理大部分的工作。这篇文章里描述的FDCs和所有的PC机都是兼容的。
这篇文章描述了控制器寄存器的使用和命令识别。
许多延时被使用在了控制器上,它们的原因有很多种。包括了开启驱动马达,移动磁头到一个新的位置等待放好。
当驱动马达启动后,会请求寻道,但是它需要等待直到驱动器准备好接受命令。中断可以通知你驱动器已经准备好接受命令了。
在单任务环境下,你的驱动会一直等待中断的相应。而在多任务或者多线程的环境下,你的驱动可以在等待的中断的时候让其他任务执行。
当执行读或写操作时,数据可以一次从一个合适的端口读或写一个字节,或者使用DMA的channel 2一次操作一个扇区或磁道。将来会将DMA控制器的编程的文章加入到此站点中。
Configuration of an FDC on a PC
在PC机上会有一个标准配置,在XT机有3个端口可以用于控制和数据寄存器,AT机有4个,而PS/2机有6个。
端口基地址是要看控制器配置的是primary address or secondary address,它们控制着不同的端口地址。另外,软盘控制器都是使用DMA channel 2来进行读写操作的传输,通过硬件中断IR6来请求服务,中断类型码默认为0x0e。
注意,控制器可以有不同配置在响应默认的中断时。(?)
FDC Registers
下面的章节将详细说明列表下面的寄存器使用。第一组寄存器是每个PC system都会有的,接下来的是AT机和PS/2机特有的。
- Common Registers:
1. Digital Output Register DOR
2. Main Status Register
3. Data Register
- AT Specific Registers:
1. Digital Input Register DIR
2. Configuration Control Register
- PS/2 Specific Registers:
1. Status Register A
2. Status Register B
3. Data Rate Select Register
Digital Output Register DOR
MOTD,MOTC,MOTB,MOTA:motor control for floppy drive D,C,B,A.
1= start motor, 0 = stop motor
DMA:DMA and IRQ channel.
1= enabled, 0= disabled
REST:controller reset.
1 = controller enabled, 0 = execute controller reset
DR1,DR0:drive select.
00 =drive 0(A), 01 = drive 1(B), 10 = drive 2(C), 11 = drive 3(D)
这个寄存器是只写的,控制驱动器马达,还有驱动器和DMA/IRQ mode的选择和复位控制器。
如果REST位置位,那么控制器就可以接受和执行命令。如果它被复位,那么控制器就会忽略所有的命令,然后把内部寄存器复位除了DOR。
注意,尽管设定位被同时接受,但驱动器是无法选择的除非它的马达已经开启了。
还有注意,驱动器C和D在所有的系统里面都没有得到支持。
Example:
为了启动驱动器A的马达和选择它,准备操作,你需要按照下面的方法:
MOTA =1 (start motor for drive A)
DMA =1 (assuming you want to use DMA and interrupts)
REST =1 (controller enabled, otherwise no other commands will be executed)
DR1,DR0= 00 (select drive A)
All other bits are set to 0
因此16 +8 +4 +0 = 28,或者01ch,它被发送给端口3f2h (驱动器A通常在primary controller)。
用汇编语言,可以这样写:
mov al,01ch
mov dx,03f2h
out dx,al
Example:
为了复位控制器,需要发送0给端口3f2h。它会关掉所有的马达,不选择任何驱动器(因为驱动器A的马达关掉了,因此它也不能被选择),禁止了DMA/IRQ,然后在复位控制器。
代码如下:
mov al,0
mov dx,03f2h
out dx,al
Main Status Register
MRQ:main request.
1 = data register ready, 0 = data register not ready
DIO:data input/output.
1 = controller -> CPU, 0 = CPU -> controller
NDMA:non-DMA mode.
1= controller not in DMA mode, 0 = controller in DMA mode
BUSY:instruction (device busy).
1= active, 0 = not active
ACTD,ACTC,ACTB,ACTA:drive D,C,B,A in positioning mode.
1 = active, 0 = not active
这个寄存器是只读的,包含了控制器的状态的信息。你可以在任何时候读它。
注意,这个寄存器和状态寄存器ST0~ST3不同(后面会介绍),它们的数据是在命令执行完后的结果。这些寄存器是通过data registers获取的。
Bit 7(MRQ)位指示控制器是否已经准备好通过data register接收发送数据或执行命令。
DIO位表示控制器是从CPU接收数据还是写数据到CPU。
如果控制器启动了DMA channel 2来传输数据或从内存获取数据,那么这个NDMA位不能设置。如果它被设置了,那么数据就会通过读写命令与data register进行传输。如果是这样,控制器就会每次发送一个硬件中断来告诉要么接收一个字节要么提供一个字节。
Bit 4(BUSY)位表示控制器是否忙。如果它置位了,那么表示控制器当前正在执行命令。
Bit 0-3表示驱动器当前正在按照位置顺序进行读写或者正在重定位。
注意,控制器准备读写的延迟时间为175us,比老的控制器要长一些。
Example:
为了测试控制器是否准备好接收命令和数据,需要测试MRQ位和DIO位。它需要包含读端口值,然后mask一些bits,最后做比较(为了测试相应bits)。
用汇编语言,可以这样写:
mrqloop:
mov dx,03f4h
in al,dx
and al,0c0h
cmp al,080h
jne mrqloop
这段代码会一直循环直到控制器已经准备好接收数据。注意,如果希望控制器发送数据给CPU,那么这段代码不行。如果你需要检查两种情况,那么你应该增加另外一个分支的代码(通常,你从之前的命令可以知道控制器是应该发送或接收数据,因此只需要检查一个条件即可)。