What is it?Remark in advance: this project is the ancestor of 1541LPT, No more floppies anymore!, so some text and ideas will look familiar.
PC-Flop is a project where I am going to use a PC as a hard disk drive for the C64, C128 and VIC-20 and other IEC computers using a 1541 as an interface. As a small bonus you can use the CDROM, 1.44 MB-drive and network-drives of the PC as well!
Products: software, a cable and a modified 1541-board.
The storyMarko Mäkelä, Frank Kontros, Andre Fachat and I exchange a lot of ideas and one day I suggested to build a small 6502-machine as an interface between the PC and the C64 to let GEOS think it is dealing with an real 1541 or other drive. Marko (or Andre ?) replied that I should use an old 1541-board instead, it would save me a lot of soldering.
TheoryTo understand how the 1541 transfers data to/from the floppy disk, you can read this document . The 1541 uses a 6522 (UC2) to transfer data from/to the head of the drive and to steer the stepping motor. This 6522 is as far as a programmer can go. The idea is to remove the mechanical part and the connected electronics and to connect the I/O lines of the 6522 with the printer port of a PC instead. The PC now must emulate the parts we removed: it must read the data send by the 6522 and store it, and it must send stored data to the 6522 as if it was coming from a real floppy.
This can only be done when the PC handles/emulates the "handshake" signals in the right way. I use the word "handshake" by lack of a better word.
The first thing a drive does when a command is given is to read the track where the head is above. The PC can detect this because PB2, motor on/off, becomes active (H). As you know, the original 1540 and 1541 have no "track 0"-detector. It detects the track where the head is above by reading the first header off a sector it "sees" because the header contains this information. If it doesn't read anything, then the "famous" head-bumping occurs because the floppy thinks the mis-reading could be caused by a wrong alignment of the head. My idea is anyway to let a drive think that, after powering up or "changing" the floppy, the head is above track 18.
If the drive wants to change the track, it does this by changing the outputs PB0 and PB1 like 00, 01, 10, 11, 00 etc. when increasing the tracknumber and changing the values in the opposite way when decreasing the tracknumber. The head is above a track when PB0 = 0. This means that the drive needs two steps to change the track. We will come back to this matter when discussing "Copy protections". The PC only has to detect the changes of both PB0 and PB1 and act on it as needed.
The PC must start reading and storing data the moment it detects CB2 is (L). If the byte has been stored it must signal this to the drive by negating the "Byte ready" line towards CA1 and the SO input of the processor. Normally the drive needs 26 to 32 usec to write the info away. The needed time depends on the track where it is on. After receiving the "Byte ready" signal the processor outputs a new byte to port A of the 6522. I do not know how much time this will take but with the help of the following disassembly it can be calculated:
B_F5BF LDA (BUFPNT),Y 6 B_F5C1 BVC B_F5C1 3 CLV 2 STA PortA2 4 INY 2 BNE B_F5BF 3 ----+ 20The above is a part of the procedure to write a complete datablock to the floppy disk. The numbers behind the text is the number of cycles this instruction needs to be executed. As you can see the total is 20. We have to wait at least this amount of time plus some reserve. We also can see that it takes up to 11 cycles before the new data is outputted to the port.
When reading data the opposite happens:
B_F4D4 BVC B_F4D4 CLV LDA PortA2 STA (BUFPNT),Y INY BNE B_F4D4Again the 6502 needs at least 20 cycles to read a byte.
Notice that the 6502 immediately resets the overflow flag after detecting it has been set. This is possible because the SO input is edge sensitive. For the same reason the PC can set the signal immediately after it had been negated.
Remark: From now on the handling of the "Byte ready" signal is included when I mention reading or writing a byte from/to port A. As we have no handshake from the drive to signal that it is ready to write/read the next byte, we must respect the timing mentioned above.
We'll now discuss all actions the drive can perform on a disk:
- Positioning the head
The drive moves the head by changing the values of bit 0 and 1 of port B of the 6522. Counting up moves the head inwards to a higher track, counting down to a lower track. The only thing the PC has to do is react accordingly to the behaviour of these two bits.
Formatting a disk is another matter. The drive seeks the first track using the "famous" bump-action. The reason for this is that, with exception of the 1541C, the drive does have no means to detect if the head is above the first track. The bumping is caused by the fact that the drive performs 90 steps (= 45 tracks) outwards. So on whatever track the head was positioned before, it always ends up at track 1.
The only way the PC can find out that a BUMP is going on is that at a certain moment during this action its internal trackpointer will count down to zero and we all know that track 0 does not exist. The only thing the PC can do now is keeping the pointer pointing to track 1 and to wait for the 1541 to stop counting down.
- Formatting the disk
A disk is formatted by formatting the tracks one by one. The first thing the drive does with a track is writing 10240 times a SYNC-char (= $FF) to it. Can a track contain 10240 bytes? No.
Spinning at 300 RPM it means one track is 200.000 uSec long. For track 1 this means 200.000 / 26 = 7693 bytes. For track 35 this means 200.000 / 32 = 6250 bytes.
With writing 10240 bytes the drive can be very sure that the complete track has been overwritten. (Or you must have a drive that turns at 225 RPM or slower) The next step is writing another 4000 SYNC-chars and then 4000 times $55. This last action surely overwrites some of the SYNC-chars. (Unless your drive is slower then 289 RPM) The drive now starts to count the bytes of both actions. If the result is too low (drive is too slow) an error will occur. It then starts to calculate the gap between two blocks of data (incl. the header). I studied the source but until now it is not clear to me how the gap is calculated and how big it will be for every track. I only know that the size depends on the found result mentioned above. And this number depends on the speed of the drive !!!
The only thing the PC has to do is to create an array of 7692 bytes. It simply starts writing the data into the array from the point the bytevector is pointing to (actual point is not important now). The moment the vector reaches the maximum number of bytes the track can contain (7693, 7143 6667 or 6250), it starts with byte zero again. Once the 1541 has calculated the gap, it starts writing the sectors. But where should the PC start writing the new sectors? At that point the bytevector is pointing to !!! You simply don't know what and why the drive is writing data to the floppy. The result can be that the start of sector 0 is somewhere in the middle of the array. When the drive changes track, the PC only has to change the array, NOT the bytevector!
Where should the bytevector point to after changing a track? IMHO that doesn't matter. The 1541 hasn't a "sector 0"-detector as PC-floppies do. So during the formatting process, the creations of the sector on a track starts at that point where the head is at that moment. This moment depends on how much time was needed to write the previous track, which depends on the total size of that track, which depends on the size of the gap between two sectors, which depends on the speed of the drive. And as a drive is a mechanical thing, you can bet on it that the speed differs for all drives. This simply means that the alignment of two sectors of different tracks may be the same for two floppies formatted on the same drive but probably will differ for floppies formatted on different drives.
Remark: When changing track to the inside, the bytevector can have a value greater then the maximum value for that track.
- Writing data
The only thing the PC has to do is to feed the content of the array to port A at an interval of 26 uSec. But where should it start reading? If the drive is looking for a specific sector, it simply starts reading all the headers of the sectors until the sector is found. The header of a sector also contains info about the track where it is on. So if the drive finds out that it is on the wrong track, it has to go to the right track first. Starting the drivemotor, moving the head, all these actions cost time. So there is no logic in what sector the drive will find first. So IMHO the PC can start feeding the drive with data starting from the first byte of the array. Remember: the beginning of the array is not necessarily the beginning of the track.
- Reading data
The only thing the PC has to do is to read the bytes from port A and to write them into the array at an interval of 26 uSec. Period.
Copy protectionsAt this moment I only can think of six types of copy protection that can be used on a disk:
- Writing own data to the disk
Using ML you can send your own data to port A to be written on the disk. In this way you can write patterns to a track in such a way that the Kernal won't recognize them as sectors or whatever. In this case the drive will return read error to the host. IMHO this is no problem for PC-Flop. As I already stated above: "Store what port A is giving. Don't think about it, just do it!". So whatever data is received, it will be returned in the same way.
Still one funny problem can occur. Sending data to port A you have to take care of one thing: don't use more then three zeros in a row !!! Four zeros, 0000, will be read as 0001. That is, if you're were dealing with a real 1541. With no precautions, PC-Flop will return 0000. The only way you can avoid this is scanning the data and adjusting the data after everything has been stored. The funny thing about this phenomena can only be used as a copy protection against PC-Flop as it has no use at all on whatever 1541.
- Using halftracks
The halftracks are the tracks between the normal tracks. Or technical spoken, the tracks where the head is above the moment bit 0 of port B is 1. Why doesn't the drive use these tracks as well because it could double the capacity of the drive? The reason is that when using halftracks as well, the tracks would overlap each other. Reading such a track is a guarantee for faulty data. But on the other hand, there is nothing against formatting track 1, 2.5, 3.5 and 5, and putting valid sectors and data on it. The only thing is that the unprepared 1541 most likely will produce read errors for the tracks 2, 3 and 4.
What does this mean for PC-Flop? Once you know halftracks are used, you have to reserve an array for every step of the stepping motor. At the moment I'm thinking about a scheme which automatically takes care of halftracks if needed.
- Shifting tracks
This means that the drive first reads a track to find a certain pattern and, once found, switches to another track to write a pattern there. When the software is used, it first looks for the first pattern. Once found, it switches to the other track. The pattern the software will read now should be the second pattern.
The protection lays in the fact that if you want to copy the disk, you need a copyprogram that is capable of copying a track bit for bit but also is capable of aligning the tracks in the same way as the original disk. The bit copying is needed because you don't know at what place the second pattern has been written to. If it was, for example, written over the header of a sector, a normal copy program won't be able anymore of finding this sector ie. copying it.
At this moment the only means of aligning tracks that the PC has is not changing the bytevector during the moment the drive changes track. IMHO this should be enough to handle this type of protection. Comment on this statement is welcome !!!
- A software solution: we need a program that copies the tracks bit by bit and determines the alignment. But I foresee problems programming the whole thing because one part has to run in the drive and one part in the host computer.
- a hardware solution: we connect a cable to the 6522 and read the tracks parallel to the 6522 using bigger arrays capable of storing at least a track twice. During changing the track we store the pointer as well. Once the whole floppy is read, the PC can do the analyzing. The only program needed for the 1541 is one that moves the head from track 1 to 35 (or more) while waiting a second above every track. Nothing else, even any reading!.
- Changing the clockfrequency
As already stated in this document about the 1541 , the drive places the data with an higher frequency on the outside surface of the disk then on the inside surface. Writing the data with an altered frequency causes errors when reading it with the normal frequency. Writing 101... at slow speed will be read as 11... at high speed; the 0 is not detected.
Because we don't use/need this mechanism at all, it won't trouble us.
- Using more tracks
The 1541 only uses 35 tracks but an external PRG can address up to 40 (maybe more ???). The reason why Commodore choose not to use 40 tracks is unknown to me. Anyway, there are programs that can use these extra tracks. For most of them it is not meant as a copy protection but this part of the document seemed to be the most suitable to discuss it.
The only consequence for the PC is that it has to store more data/arrays. That's all.
- Intentionally physical damage
This is a very interesting way of copy protection. The program writes data to the place that is damaged. When reading from this place, it expects anything but the written data back. But the surface of the copy disk is most likely NOT damaged at this particular spot and so the program will read the data it just has written!
But this kind of protection is very rarely used. I myself only heard of one case. The reason for this is probably that there is a lot of work involved in the preparation of the disk.
This kind of protection can be emulated by telling the program what part of the disk to treat as read-only.
RealizationThe only thing we have to do is to place two extra sockets between the 6522 and its original socket. All pins are connected to each other by means of soldering with the exception of:
- PA0..7 (pin 2..9, bidir.): used to transfer data
- CB1 (pin 18, in): not used by the drive, connect to +5V through 10K resistor for future use.
- CB2 (pin 19, out): direction of the data (H: read, L: write)
- PB0..1 (pin 10..11, out): lines to steer the stepping motor
- PB2 (pin 12, out): motor on/off
- PB4 (pin 14, in): write-protection detector
- PB5..6 (pin 15..16, out): lines to select density
- PB7 (pin 17, in): synchronisation-byte detected
- CA1 (pin 40, in): byte ready
- CA2 (pin 39, out): disable SO input of 6502
As you can see there are 8 bidirectional lines, 7 outputs and 3 inputs. PB5 and PB6 influence the density of data on the floppy and, IMHO, can be neglected for our purposes. This means we have 5 outputs to deal with. A bidirectional printer port of a PC has 8 bidirectional lines, 5 inputs and 4 outputs. As you can see this makes a nice match.
The second step is to connect a male 25 pins D-connector to the free pins of the upper socket. This connector is used to make the connection with the LPT-port of the PC and is wired like this:
6522 LPT Name Meaning pin name pin ---- ------- --- ---------- --- PA0 2 D0 2 . . . . PA7 9 D7 9 CA1 BRDY 40 Strobe 1 (O) PB7 SYNC 17 Auto feed 14 (O) PB4 WPE 14 Initialize 16 (O) PB0 Stp1 10 Select 13 (I) PB1 Stp0 11 Paper out 12 (I) PB2 Mtr 12 Acknowl. 10 (I) CB2 Mode 19 Busy 11 (I) CA2 SOE 19 Error 15 (I) CB1 18 Select out 17 (O) 3BC,378,278 = Printer data 3BD,379,279 = Printer status bit 0 = not used bit 1 = not used bit 2 = not used bit 3 = error (15) bit 4 = select (13) bit 5 = paper end (12) bit 6 = acknowledge (10) bit 7 = busy (11) 3BE,37A,27A = Printer control bit 0 = strobe (1) bit 1 = autofeed (14) bit 2 = Initialize (16) bit 3 = select out (17) bit 4 = enable IRQ7 bit 5 = data port direction bit 6 = not used bit 7 = not used Control after reset: $CCBetween the 74LS174 (= Printer control port) and the Strobe-pin (1) at the connector you'll find a 74LS05 open-collector inverter. This is the same for Autofeed (14) and "Select out" (17). For Initialize you'll find two 05-inverters. Combining this info with the fact that the byte $EC is written to the controlport results in the fact that the inputs CA1, PB4 and PB7 all read a 1. CB1 will read a 0.
The softwareUnless we expand, the rest is only a matter of software on the PC.
Testing everythingAt this moment everything is purely theoretically. To make sure that my theory is according the reality, I have to see first how a live drive uses the above mentioned signals. For this I need three extra inputs ie. a second printer port.
6522 LPT Name Meaning pin name pin ---- ------- --- ---------- --- CA1 BRDY 40 Acknowl. 10 (I) PB7 SYNC 17 Busy 11 (I) PB4 WPE 14 Paper out 12 (I)What now has to be done is writing some software that scans the bus continuously.
In case we want to expand the Kernal with extra commands, we need to expand the onboard (EP)ROM and RAM. This is described below in separate parts.
We need more ROMIf we want to use a stand-alone PC, we must be able to command it in one or another way. This means we must use the 6522 in a way that is not provided by the standard Kernal of the 1541.
This could be archived by executing a small program in one of the buffers. The disadvantage of this procedure is we first have to load this program from disk. This does mean that this program has to be available on every "floppy" on the PC otherwise we are not able to change "floppies" anymore.
The more logical step is to change the Kernal. IMHO the only thing we need to change is the command-interpreter. And I'm very sure this can be done with maintaining 100% compatibility.
Adding more commands means we need more ROM. There are 256 bytes free in the range $C000/$C0FF but I don't think that this will be enough. My idea is to replace both onboard ROMs with one 32 KB EPROM like the 27256. This gives us an extra 16 KB of EPROM to be filled with our own programs.
We need more RAMAt this moment I don't know if I need more RAM. But expanding the 1541 with 2KB of extra RAM is simple and the 1541 will still be 100% compatible.
The only thing we have to do is to add one AND gate and a 6116, 2016 or equivalent 2K*8 RAM. The last one can be piggybacked on the original one: all pins are soldered with the exception of pin 18, the chip select input. For the AND gate we need a 74LS08 that can be piggybacked upon another TTL IC with pin 14 and 7. The output of the AND gate is connected to the previously mentioned CS input. The inputs of the AND gate are connected to pin 13 and 12 of the onboard 74LS138. In this way the new RAM is mapped from $0800 to $0FFF.
Emulating more drivesAnother idea is to have the possibility to assign more then one devicenumber to the 1541. But every device needs its own 2KB RAM starting at address $0000. So we must save the contents of this RAM every time another device needs this range. To archive this we could add more RAM to the board but this would mean a major rebuild and that is a little bit out of the scope of this project. Another idea is to save the contents of the RAM on the PC. This will cost some performance but will need fewer modifications of the 1541-board. To perform the needed save- and restore-operations, we will need some extra RAM but that is already covered by the part above.
One remark: A multi-device drive cannot be two devices at the same time. So I foresee troubles with copy-programs that transfer data directly from one drive to the other.
SoftwareThe SW can be split up in two parts:
- the software for the 1541 board
- the software for the PC
The software for the PC is less trouble as I can use the core of CBM-HD for this purpose. Theoretically I only have to change the I/O- and command-interpreter-part (I hope).
SchematicsNot even started yet.
You can email me here.