1541LPT: No more floppies anymore!
What is it?1541LPT 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.
Incompatibility.1541LPT is not 100% 1541 compatible. Programs manipulating the second 6522, the one transferring data from/to the floppy disk, simply won't work. More explanation regarding this subject you'll find spread all over this page.
The story.Marko Mäkelä, Frank Kontros, Andre Fachat and I exchange a lot of ideas and one day I suggested building a small 6502-machine as an interface between the PC and the C64 to let it think it is dealing with a 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.
PC-Flop was my first try but failed: the LPT port was too unstable for my needs. But during the tests the idea rose to alter the Kernal of the 1541 as well and to set up my own communication protocol between the 1541 and the PC.
Theory: the basics.The idea is quite simple: replace all routines handling the transfer of data with the floppy disk by my own ones. It sounds simple and, looking back, it is. But I ran into some problems that really gave me a headache.
Commodore uses GCR encoding to write/read data on/from the floppy disk for a technical reason. But IMHO we don't need this overhead. So I skipped all GCR en/decoding and saved quite some processor time on the fly.
I changed the original Kernal at 13 places. I only will describe them briefly, for details see the sources:
- I disabled the calculation of the checksum of the ROM.
- initialization of the added I/O, checking the communication with the PC.
- Check any possible restart of the program running on the PC.
- Read the header of a sector.
- Read a sector.
- Find a sector.
- Write a sector.
- Verify a sector
- Step the head.
- Format a track.
- Disable the GCR conversion at certain places
- Different start up text (= 73,CBM.....,0,0 message)
- Implemented a routine to list all available images
- Changed some timings
- Disable multiple reads.
I first simulated this process when trying to read a sector but that produced quite a messy program on the PC. And when I found out that the writing process behaved the same but with a different range, I simply dropped the whole process and wiped out the part in the Kernal by altering three bytes.
One of the ideas was only altering the Kernal by replacing the original instructions with jumps or subroutines. My routines would be placed in the so far unused address range $8000-$BFFF. The reason for this is that in this way I would keep the Kernal as much as original as possible in case a program depended on routines found in the Kernal.
The above meant that the original address range of the Kernal had to be expanded in some way. And that was not so simple with the 1540/1541-I boards. Although the 1541C and 1541-II boards use 27128 EPROMs, even then it is not that simple to exchange it with a 27256.
So I looked for a way to move the 720 bytes of my program somewhere inside the original ROM. To make a long story short: I succeeded and the short version was born: 1541LPTS.
Remark: although I used a 1541-II to test 1541LPT, the Kernal is based on the one of the 1541-I ie, the ROMs 325302-01 and 901229-05.
Theory: the PC.The program running on the PC is just a program that runs and waits for orders coming from the 1541; no menus or whatever. Some parameters at startup would tell the program which device number and LPT port to use and what D64 image to start with.
The above remark reveals that my program is using D64 images as source. The advantage for me is that I could use all routines developed for CBM-HD. D64 images won't recognize halftracks for example and that is at the same time another reason that 1541LPT is not 100% compatible. For more details see the chapters 'Theory: future expansion' and 'Copy protections'.
I mentioned the use of parameters. But after some troubles with changing parameters I started to use an INI file. But either using parameters or a file meant that I had no easy way of 'changing the floppy'. So I decided to alter the Initialize instruction by making it possible to add a parameter. For example OPEN1,8,15,"I:WORKDISK" will cause the PC to load the image WORKDISK.D64. Only later I realized that when during a game a change of floppy is needed, the user cannot type in the OPEN command mentioned above. That's why I decided to the whole restartable: the user stops the program, edits the INI file and starts the program again. And routines in the 1541 make sure it detects that the PC program has been restarted.
I also implemented a command that enables the user to see what images are available on the PC. The syntax is quit simple: LOAD"$$",x or @$$. Only images in the same directory as 1541LPT.EXE are shown.
Theory: speed loaders.So far so good, but what about speed loaders like JiffyDOS, FC-III, EXOS V3 etc.? Theoretically it should work with all speed loaders that don't access the mechanically drive directly. And the very good news is: JiffyDOS is one of them! I adapted my own JiffyDOS ROM (1541LPTJ) and now I have a system with all JiffyDOS goodies and no more playing disk jockey :)
I tested 1541LPT also with some other speed loaders. In this case I (tried to) load the program '64 DOCTOR', 83 blocks. The number is the needed time in seconds:
1541LPT 1541LPTJ original C64 50 40 JiffyDOS 6 49 6 Power Cartridge 9 9 Final Cart.-III xxx xxx EXOS V3 xxx xxxAs you can see, no result with EXOS and FC-III. But with the remark that both speed loaders had no problem with reading a directory. So IMHO these two manipulate the second 6522 directly.
Remark: I have no real good explanation for the difference in speed between the original C64 Kernal using 1541LPT or 1541LPTJ.
I already mentioned that I made a JiffyDOS version: 1541LPTJ. I also made one that fits within 16 KB: 1541LPJS. But the problem of this one is: I cannot distribute the binaries or sources as they are, so how can I get them to you in a legal way?
Theory: future expansion.It would be great to emulate drives like the 1571 or 8250 or being able to handle DOS files directly ie. having a xxx GB hard disk drive at your disposal. Unfortunately this is not so simple. I can make the 1541 format a disk with 255 tracks and 256 sectors on each track but then what about the BAM needed for this 16 MB 'only' sized disk? The 1541 is only capable of handling the 1541 specific one-sector-BAM located at track 18, sector 0. The only idea I have at this moment is to trap all commands sent to the 1541 and send them to the PC which will handle and process them. The 1541 will be nothing more then a hardware interface between the PC and the Commodore computer.
I'm using D64 images at the moment but this means we have to deal with a certain incompatibility like not having half tracks. Using G64 images could solve this and some other problems.
Realization: the 1541.Theoretically 1541LPT should work with all known 1541 models. But for practical reasons I adapted a 1541-II. There has to be some soldering done.
The first change is removing the mechanical drive.
The second change is connecting the pins together that lead to the write-protect detector of the drive. In case of the 1541-II I used a jumper placed over pin 3 and 4 of connector CN4. Until so far this worked fine but I'm thinking about replacing it with a switch.
The third change is adding a 6522. I piggybacked mine on top of U6. I connected all pins except PAx, PBx, CAx, CBx and CS2 (pin 23). I connected CS2 with a wire to Q5, pin 6 of U2, a 74LS42. In this way the 6522 shows up in the memory map at address $1400.
Then a 25 pin male D-connector is connected to the 6522: .......
- PA0 (pin 2) <-> Data 0 (pin 2)
- PA1 (pin 3) <-> Data 1 (pin 3)
- PA2 (pin 4) <-> Data 2 (pin 4)
- PA3 (pin 5) <-> Data 3 (pin 5)
- PA4 (pin 6) <-> Data 4 (pin 6)
- PA5 (pin 7) <-> Data 5 (pin 7)
- PA6 (pin 8) <-> Data 6 (pin 8)
- PA7 (pin 9) <-> Data 7 (pin 9)
- PB0 (pin 10) <- Strobe (pin 1)
- PB1 (pin 11) <- Auto feed (pin 14)
- PB2 (pin 12) -> Error (pin 15)
- PB3 (pin 13) <- Initialize (pin 16)
- PB4 (pin 14) <- Select in (pin 17)
- PB5 (pin 15) -> Acknowledge (pin 10)
- PB6 (pin 16) -> Busy (pin 11)
- PB7 (pin 17) -> Paper end (pin 12)
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 = auto feed (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: $CCAs you can see, the CAx and CBx pins are not used. Future expansion?
Realization: the PC.The software is written in Turbo Pascal 7.0 (but should run under 5.0 as well IMHO) and was tested on an 80486 80 MHz running DOS 6.22 NL. Later I switched for practical reasons to a faster machine with both Windows 98SE and XP installed. Running in Windows 98SE's real DOS mode is no problem but it does not run in a DOS box, not even when using Windows 98SE. For one or another reason Windows messes up the LPT signals during a transfer. This was my first project that I tried to test in a Windows DOS box and it took me two days to find out :(
Realization: testing.As said before, the Pascal part is using the same unit I use for CBM-HD and that software is running stable for the last two years.
I tested the whole by saving and loading some own made files but the main test is performed by utilities like 'CHANGE DISK' and 'PERFORMANCE TEST' found on 1541 Demo disk. What struck me most in a positive way was that 1541LPT even passed the mechanical test performed by 'PERFORMANCE TEST'!
The softwareThis ZIP file contains everything, ROMs, DOS executable and sources except the ones of the JiffyDOS version. The reason for this is obvious, I think.
But there is solution for the owners of a 1541-II. The 1541LPTJ version needs a 32 KB EPROM or equivalent. Unfortunately there is a connection at both sides between pin 28 and 27 of U4, the socket for the ROM. This means we are restricted to 27128 EPROMs and we need to place a 27256.
I solved the problem by desoldering pin 27 and by placing another socket on top of the original one. But before placing it, I soldered a line to pin 27 and lead that one through the hole of the removed pin. The free end of the wire was soldered to pin 24, A14, of U3, the 6502.
Unfortunately this solution only covers the 1541-II. I only have one (not tested) idea for placing a 27256 in an original 1541: use a 24 -> 28 pins converter socket, connect all address lines and connect /CS and /OE to an inverter which on its turn is connected to Address line A15.
The places in the source that have been changed, are marked with '&&&xx' where xx is a number. Find these markings in 1541LPT.LST and the remarks let you see what actually has been changed. 37 bytes have to be changed, 13 more if you want another start up text, and that is a number that can be done by hand. So now you have to read out the original ROM, make the needed changes, add the first 16 KB of 1541LPT.BIN and burn the result into a 27256.
Copy protectionsAt this moment I only can think of six types of copy protection that can be used on a disk:
- Writing/reading data directly to the disk
Some speed loaders and programs manipulate U8, the 6522 transferring the data to/from the disk, directly in ML. Sorry, won't work with 1541LPT.
- 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 the head itself is too big, so 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 an unprepared 1541 most likely will produce read errors for the tracks 2, 3 and 4.
Using G64 images would enable us to use half tracks by I won't support it.
- 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. The software will first looks for the first pattern. Once found, it switches to the other track and will try to read the second pattern. This means that the tracks have to be aligned in some way. D64 certainly cannot, G64 can AFAIK.
- Changing the clock frequency
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 ends up with reading an 11... at high speed; the 0 is not detected.
1541LPT doesn't use/need this mechanism at all, so IMHO it won't trouble us.
- Using more tracks
The 1541 only uses 35 tracks but an external PRG can address up to 40 (maybe even more). The reason why Commodore chose not to use 40 tracks is unknown to me. Anyway, there are programs that use these extra tracks. For most of them it is not meant as a copy protection but it seemed best to mention it here as well.
The only consequence for the PC is that it has to store more data/arrays. D64 can AFAIK
- 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. Unfortunately not possible with D64 and I don't know about G64.
You can email me here.