Using the Viejo 20 disk controller

Back to assignment page

Introduction

The Viejo 20 uses one or two Antiquon 5802 disk controllers to interface with its floppy disk drive(s). Each disk controller is accessible in memory at the following addresses:

AddressDescription
0xC010Primary controller: Sector Select Register 1
0xC011Primary controller: Sector Select Register 2
0xC012Primary Controller: Drive Status Register
0xC013Primary Controller: Main Status Register
0xC014Primary Controller: Command Data
0xC015Primary Controller: Data
0xC016Primary Controller: Interrupt Control Register
0xC017Primary Controller: Scratchpad Register
0xC018Secondary controller: Sector Select Register 1
0xC019Secondary controller: Sector Select Register 2
0xC01ASecondary Controller: Drive Status Register
0xC01BSecondary Controller: Main Status Register
0xC01CSecondary Controller: Command Data
0xC01DSecondary Controller: Data
0xC01ESecondary Controller: Interrupt Control Register
0xC01FSecondary Controller: Scratchpad Register

The primary disk controller is connected to line IR2 of the interrupt controller, and the secondary controller is connected to line IR3. Sectors of 512 bytes are used, so each 5¼" 360-KB floppy disk has the following geometry:

Sides2
Tracks per side40
Sectors per track9

Sector addresses are given as SIDE:TRACK:SECTOR in this documentation, where sides are numbered from 0 to 1, tracks are numbered from 0 to 39, and sectors are numbered from 0 to 8.

Programming the Viejo 20 disk controllers

Reading a sector

To read a sector from a disk, the drive motor must first be turned on by setting bit 0 of the Drive Status Register. If the motor was not already on, the program should wait for up to a second to allow the drive to spin up.

The head, track, and sector indices must be written to the Sector Select Registers, and the Read Sector command issued by sending the command number (0x10) to the Command Data port. If interrupts have been enabled, the program may wait for an interrupt to signal the completion of the command. Otherwise, the program must poll the Main Status Register until the Busy bit becomes 0.

Once the command has completed, the program should check the Main Status Register bits to ensure that no error occurred; if all error bits are 0, 512 bytes of data may be read sequentially from the Data port.

The drive motor may be turned off once the command has completed, or left on for a short period of time to prevent spin-up delays on future commands.

Writing a sector

To write a sector to disk, the drive motor must first be turned on by setting bit 0 of the Drive Status Register. If the motor was not already on, the program should wait for up to a second to allow the drive to spin up.

The head, track, and sector indices must be written to the Sector Select Registers, and the Write Sector command issued by sending the command number (0x20) to the Command Data port. 512 bytes of sector data must then be written sequentially to the Data port. If interrupts have been enabled, the program may wait for an interrupt to signal the completion of the command. Otherwise, the program must poll the Main Status Register until the Busy bit becomes 0.

Once the command has completed, the program should check the Main Status Register bits to ensure that no error occurred; if all error bits are 0, the command was successful.

Register detail

Sector Select Registers

Sector Select Register 1 is used to select the track of the next disk operation, and may be set to any value from 0 to 39. Sector Select Register 2 is used to select the head and sector of the next disk operation, and contains the following fields:

Bit(s)Description
0–6Sector index (0 to 8)
7Head (0 or 1)

Drive Status Register

This register is used to check and control the state of the disk drive. It contains the following bits:

BitsR/WDescription
0R/W1=Drive motor on
1R1=Disk present
2R1=Disk is write-protected
3R1=Read/write head is on track 0
4R1=Read/write head is at beginning of track
5R1=Head is moving outwards; 0=Head is moving inwards
6R1=Head is moving
7R1=Drive is attached
Note: You don’t need to emulate this precisely. Bits 4–6 can just stay at 0, since you’re emulating a really fast drive anyway. Bit 7 should stay at 1.

Main Status Register

This register is used to check the state of the controller. It contains the following read-only bits:

BitDescription
01=Busy (currently executing command)
11=Seek error in last command: Track not found
21=Seek error in last command: Sector not found
31=Seek error in last command: Hardware error
41=Data error in last command
5,6Reserved
71=Drive error in last command (see Drive Status Register)

This register is set to value 0x01 when a command begins executing, and the individual bits are filled in once the command completes.

Note: Bits 1 or 2 should be set only if an invalid track or sector number was given. If they sought past the end of a file, you need to pretend that the data there is all 0. A hardware error can’t really be generated, but a drive error could be generated if no “disk” is present, or if it’s read-only.

Command Data Port

Commands are started by issuing a byte to this port. Valid command bytes are:

Command numberDescription
0x00Recalibrate drive. (Seeks to track 0.)
0x10Read sector.
0x20Write sector.
0x30Seek to sector.
0x40Format track.

All other command numbers are reserved.

Note: Make sure you generate an error on write/format commands if the “disk” is read-only. (You should probably have opened it as read-only, too, but the program needs to know if a write failed.)

Data Port

Sector data can be read or written sequentially from this port. At the completion of a read command, contents of the disk read buffer can be read sequentially through this port, and before a write command, contents of the write buffer can be written sequentially through this port.

Interrupt Control Register

This register controls interrupt generation, and allows acknowledgement of interrupts. It contains the following bits:

BitDescription
01=Interrupt active (R/W)
11=Enable interrupts at command completion
21=Enable interrupts at medium change

If an interrupt has been generated and is in service, bit 0 will read as 1; clearing this bit acknowledges the interrupt. Setting bit 1 causes an interrupt to be generated at successful or unsuccessful completion of any command, and setting bit 2 causes interrupts to be generated whenever a disk is removed or inserted.

Note: Unless you’re supporting emulation of disk-changing, you probably don’t need to worry about bit 2. Just keep its value.