How to HD install Pacland (MFM format) using WHDLoad
In this tutorial I will explain how I installed the game Pacland. The Pacland disk is not in a standard AmigaDos format, which means you must rip the data from the disk prior to actually installing the game.
As we all know disks contain tracks, data on the disk is stored on those tracks.
There are 80 (official) cylinders on the disk, each cylinder containing two tracks (upper and lower).
When we number things as 0-79, we are really talking about cylinders, but usually this numbering is called track numbering.
The system numbers tracks 0-159 and numbering starts from lower side, where is track 0, track 1 is really cylinder 0 upper side.
Data on these tracks is usually MFM-decoded. Each track contains 11 sectors of 512 bytes of data. Each sector has a header, which tells us the track number, sector number and some additional data.
The contents of a normal DOS-format track is:
... (gap) ... (track) ... (gap) ...
(gap) is normally 0-bytes decoded into MFM. 00 -> $AAAA
(track) contains 11 sectors which are:
(00) (00) (sync) (sync) (header) (fill) (headerchecksum) (datachecksum) (data)
(00) is zero byte (in MFM $AAAA)
(sync) is (A1)-bytes converted to MFM and clock pulse is dropped so that the
result is $4489, which is standard syncword. Any data never converts
into this pattern (in MFM)
(header) is the sector header.
(fill) is 16 bytes of zeros. These are intended for use by dos, but dos
doesn't use them.
(headerchecksum) is checksum of header info. Checksum is calculated using
exclusive-or and contains only databits.
(datachecksum) is the same but for data.
(data) is 512-byte data block.
The sector header consists of:
(format)(track)(sector)(length)
(format) is $FF for normal format
(track) is track number
(sector) is sector number
(length) is count of sectors before gap (end of track)
This stuff is converted into MFM before writing and is is done as follows:
(sector header) is converted as one longword
(fill) is converted as one 16-byte block
(checksums) are converted as a longword
(data) is converted as one 512-byte block
MFM conversion is done by the following principle:
Take 2 data bits and add one clock bit between them. The clock bit is a 1 if both data bits are 0, otherwise it is a 0. This scheme is used so that long runs of 0's or 1's will not occur which reduces synchronisation problems.
For example, to MFM encode the value 78:
Convert to binary: 0 1 0 0 1 1 1 0
Add clock bits: c0c1c0c0c1c1c1c0
MFM encode: 0001001001010100
Each byte converts into a word. As stretching bytes is quite hard to do on the Amiga, data is first split into two halves - odd and even.
First even bits are converted and then odd ones.
Convert to binary: 01001110
Even bits: 0 0 1 1
Odd bits: 1 0 1 0
This leads to a faster operation because extracting odd and even halves can be done by logical operations:
Even half: ((data and 0xAAAA) >> 1)
Odd half: (data and 0x5555)
And values for the clock bits are:
Clock bit: not (previous_bit or next_bit)
Now you may be wondering what the point of all this is. Non-copyable disks are stored in either MFM or GCR (Group Coded Recording) format. I have personally never seen any Amiga games which are GCR so we will not bother with that in this tutorial.
To rip the data off the disk, you must first find the sync which is where the data starts on the track. The sync is purely a marker.
Imagine a 400m running track covered with numbers, and you had to go and pick up the numbers from a particular point to get a meaningful message. The sync is equivalent to a sequence of numbers which cannot possibly be in the message itself which acts as a starting point for you. For example, walk around the track until you see a 4, then a 4, then an 8 and then a 9 in a row. Once you see this, you are at the starting point of the data so walk around the track and pick up all the numbers.
For any wannabe HD fixers out there, there are 2 CIA registers which you simply must understand and hopefully learn off by heart. Once you know how $BFD100 and $BFE001 works, you should be able to decode the majority of loaders.
When I first learnt how to disassemble a loader, I was quite surprised to learn that there is no actual track counter to say which track the heads of the disk drive are over. Loaders simply step the heads to track 0, then whenever they step in/out a track, they keep their own internal counter somewhere. You may sometimes need to patch every disk routine in a game and keep your own track counter if the game code is a mess.
Now, on with the lesson!
$BFD100 PRB
Peripheral Data Register for Data Port B
Status: Read/Write. Chip: CIA-B
Bit 0: STEP: Move drive head by one track in direction specified by the
DIR bit (set to 1, 0, and then 1 again to move head)
Bit 1: DIR: Direction to move drive head (1 = outward; 0 = inward)
Bit 2: SIDE: Select drive head (1 = bottom; 0 = top)
Bit 3: SEL0: Select DF0: (1 = not selected; 0 = selected)
Bit 4: SEL1: Select DF1: (1 = not selected; 0 = selected)
Bit 5: SEL2: Select DF2: (1 = not selected; 0 = selected)
Bit 6: SEL3: Select DF3: (1 = not selected; 0 = selected)
Bit 7: MTR: Motor on-off status (1 = motor off; 0 = motor on)
Bit 0. This bit controls the movement of the drive head for all selected drives. To move the drive head, you must toggle the value of this bit from 1 to 0, and then back to 1 again. One such operation moves the drive head the distance of one track.
Before moving the drive head, you must select a direction: either outward towards track 0, or inwards towards track 79. Bit 1 of this register determines the direction that the drive heads will move.
After moving the drive head, it's very important that you wait at least three milliseconds before performing any other disk activities. Because software timing loops are inaccurate (they depend too much on the computer's clock speed, which may vary from computer to computer), it's recommended that you use one of the CIA chip's timers to pause the required three milliseconds.
Bit 1. The value of this bit determines the direction in which the selected drives' heads will move when bit 0 of this register is changed from high (1) to low (0). To move the drives' heads out towards track 0, store a 1 here. To move the drives' heads in towards track 79, store a 0 here.
To be sure of the direction that you are moving, always set this register prior to toggling bit 0, and never attempt to move a drive head in further than track 79 or out past track 0. (You can check to see if the drive head of a selected drive is on track 0 by reading bit 4 of the CIA-A chip's PRA register, location $BFE001).
Bit 2. Amiga floppy disks are double sided. That means that the disk drives must have two drive heads-one for the top side of the disk and one for the bottom side of the disk. This bit determines which drive head will be used when it comes time to read and/or write data. To select the bottom drive head, store a 1 here. To select the top drive head, store a 0 here. As with the previous bits, the value of this bit only affects the currently selected drives.
Bits 3-6. These four bits allow you to choose which of the Amiga's floppy disk drives are selected. Only selected drives are affected by the values stored in the register's remaining bits.
The Amiga's hardware supports up to four 3Ω inch floppy disk drives. On the Amiga 500 and 1000, the internal drive is always known as drive 0 (DF0:). External drives are daisy chained together. The drive connected directly to the computer is drive 1, the drive connected to drive 1 is drive 2, and the drive connected to drive 2 is drive 3. With the Amiga 2000, 2500, and 3000, the two internal drives make up drives 0 and 1; the first external drive is drive 2 (DF2:), even if only one internal drive is present. Any drive connected to this external drive is drive 3.
To select a disk drive, set its corresponding bit equal to 0. To deselect a drive, set its corresponding bit equal to 1. Bits 3, 4, 5, and 6 correspond to drives 0, 1, 2, and 3, respectively. Any combination of drives may be selected at any one time. The other bits in this register affect all selected drives, so it's possible to perform such tasks as simultaneously moving the drive heads on more than one drive.
Bit 7. This bit turns on and off the motors of the selected drives. If you store a 1 here, the motors are turned off. If you store a 0 here, the motors are turned on. The on-off state of a motor is reflected by the drive light found on the front of the disk drive.
This bit should be set before you select a drive. If a drive is already selected and you wish to change the state of its motor, you should deselect the drive, set this bit, and then reselect the desired drive.
When turning on a drive's motor, you must wait for the motor to reach its full rotation speed before performing any other disk activities. Bit 5 of the CIA≠A chip's PRA register (see location $BFE001) is set equal 0 whenever the drive has reached full speed and is ready to receive another command.
The following machine language program uses this bit to turn on drive 0 and then turn it off again:
CIAAPRA equ $BFE001
CIABPRB equ $BFD100
or.b #$08,CIABPRB ;Ensure that DFO: is deselected
and.b #S7F,CIABPRB ;Turn on motor-select by clearing bit 7
and.b #$F7,CIABPRB ;Select DFO: to turn its motor on
Wait: btst.b #5,CIAAPRA ;Check RDY bit
bne.s Wait ;and wait for motor to reach full speed
or.b #S88,CIABPRB ;Turn off motor-select and deselect DFO:
and.b #$F7,CIABPRB ;Select DFO: to turn its motor off
or.b #$08,CIABPRB ;Deselect DFO: for safety?s sake
This program assumes, of course, that all multitasking is disabled and you have taken complete control of the computer.
$BFE001 PRA
Peripheral Data Register for Data Port A
Status: Read/Write. Chip: CIA-A
Bit 0: OVL: Memory overlay bit (Always set to 0. Don't change!)
Bit 1: LED: Power LED/cutoff filter (1 = Power LED dimmed and cutoff filter
inactive; 0 = Power LED at full brightness and cutoff filter active)
Bit 2: CHNG: Disk change (1 = no change; 0 = disk has been removed)
Bit 3: WPRO: Disk write protect (1 = unprotected; 0 = protected)
Bit 4: TK0: Disk track 0 (1 = head not on track 0; 0 = head on track 0)
Bit 5: RDY: Disk ready (1 = not ready for commands; 0 = ready for commands)
Bit 6: FIR0: Fire button on port 1, pin 6 (0 = button pressed)
Bit 7: FIR1: Fire button on port 2, pin 6 (0 = button pressed)
The PRA register serves a variety of functions. Bit 1 toggles the brightness of the Amiga's power LED. This bit also affects the on-off status of the audio cutoff filter, except on the Amiga 1000 and older 2000s that don't have composite mono video output. (On these model Amigas the cutoff filter cannot be disabled through software). Normally, the LED is at full intensity and the cutoff filter is active. Setting this bit to 1, however, dims the LED and turns off the cutoff filter.
The audio cutoff filter is a device that prevents antialiasing - high frequency noise caused by the sound digitization process. When on, the filter blocks most frequencies above 7KHz. When off, the Amiga may output frequencies as high as 15KHz. This creates brighter sounds, as well as some high-frequency distortion.
Bits 2 through 5 are connected to the Amiga's disk controller. These bits return the status of the currently active disk drive. The CIA-B's PRB register ($BFD100) allows you to select which drive is active. These bits will tell you if a disk has been removed from the active drive; if the disk in the active drive is write protected; if the drive head of the active drive is over track 0; and if the active drive's motor is on, running at full speed, and ready to receive a read or write command.
The last two bits, bits 6 and 7, allow you to read the left mouse button or the fire button on a joystick. Bit 6 reads the mouse/fire button for devices plugged into port 1, and bit 7 reads the mouse/fire button for devices plugged into port 2. Using these bits you can also output data through pin 6 on either game port: Simply set bit 6 or 7 (depending on which port you wish to output data on) in the DDRA register to 1 for output and then toggle the same bit in the PRA register. Setting the PRA bit equal to 1 outputs approximately +5 volts on that line. Setting the PRA bit equal to 0 pulls the line low to 0 volts. It is common courtesy to set the data direction registers back to their original values after using them.
By the way, MFM stands for Modified Frequency Modulation :)
More to come later when my fingers recover from all the typing...