Friday, April 11, 2014

The internal drive now works (for reading)

I am continuing to work on the floppy controller.

I have been tantalisingly close to being able to access the SD card via the internal 1581 DOS for a while, but there always seems to be one more step to cover.

The latest progress has been getting the floppy controller to read sectors from the correct location in the disk images on the SD card.

I had worked out a while back that physical track numbers start at 0, and had taken that into account.

I assumed that sectors also started at zero, since there was no contradictory guidance in the C65 specifications.   However, directory headers were not being loaded correctly, indicating that something was amiss.  I suspected the SWAP line that swaps halves of the sector buffer around, but couldn't find the point when the directory header sector was actually being loaded.

I added extra debug features to the serial monitor so that I could get the CPU to halt when writing to the floppy controller command register, but even that failed to reveal the reading of a sector 0. At this point I began to suspect that sectors might be numbered from 1, not zero.

Looking through the C65 ROM disassembly I managed to find the routine that prepares to load a sector from disk.  After scratching my head over it for a while, I was able to confirm that sectors do in fact start from 1, not zero, and made the change to the FPGA.

This is the routine:

9A34  BD B4 1F   LDA $1FB4,X ; Read logical track number (1 - 80)
9A37  3A         DEC         ; Decrement by one to obtain
                             ;   physical track number (0 to 79)
9A38  8D 84 D0   STA $D084   ; Store physical track number in
                             ;   FDC register
9A3B  BD B5 1F   LDA $1FB5,X ; Read logical sector number 
                             ; (0 - 39)
9A3E  C9 14      CMP #$14    ; Set carry flag if sector number is >=20
9A40  A9 00      LDA #$00
9A42  2A         ROL A       ; Set A to 1 if sector number >=20,
                             ;   or 0 if sector number <20
9A43  8D 86 D0   STA $D086   ; Store physical side number in FDC
                             ;   register
9A46  F0 02      BEQ $9A4A   ; Take branch if sector is one
                             ;   side 0 (A will be $00)
9A48  A9 14      LDA #$14    ; Load A with 20, which will be
                             ;   subtracted from logical sector
                             ;   number
9A4A  42         NEG         ; Calculate 2's complement of A,
                             ;   so will be either 0 (front
                             ;   sector) or -20 (rear sector)
9A4B  18         CLC         ; With C flag, A will be either $00
                             ;   if sector is on front side, or
                             ;   ($00-20) if on back side
9A4C  7D B5 1F   ADC $1FB5,X ; Now add logical sector number.
                             ;   Result will be 0 for sector 0,
                             ;   through to 19 for sector 39.
9A4F  4A         LSR A       ; Shift sector number right one bit
                             ;   since physical sectors are
                             ;   512 bytes, not 256.  Sector
                             ;   number will now be 0 through 9
9A50  1A         INC         ; Add one to sector number, since
                             ;   physical sectors apparently
                             ;   start at 1, not 0. Result will
                             ;   be between 1 and 10.
9A51  8D 85 D0   STA $D085   ; Store sector number into FDC
                             ;   register

Armed with this knowledge, I fixed the sector location calculation (and a few other bugs along the way).

The result is that the DOS now works for loading directories and programs.

First, here is the kickstart startup process where -- if you are quick -- you can see it mounting the .D81 file:

Now a couple of screenshots showing part of the (rather long) directory listing of the C64 emulator test suite that lives on the disk I mounted.  Even holding CONTROL down, the list flies by very quickly because of the speed that this machine is running.

Finally, in this video you can see me run most of the CPU tests from the C64 emulator test suite in about a minute -- the C65GS is already a very fast C64. The video wasn't appearing in the preview here for me, but hopefully it will appear when I publish this post.


  1. Do you have a list of the offset points and load addresses of the modules in the C65 kernel? I've collected some of the information from the C65 System Specification manual from CBM and from the drivers/c65.c file from MESS, but I am not sure it is correct.

    Also, what are you using as a disassembler? I updated the da64 binary from the cc64 project to support 65ce02 ops and long branches, but when I compare my output to the code snips you've posted, they don't match. I must be doing something wrong.

    1. Hello,
      The 4502 uses different opcode numbers compared with the 65CE02 for the same instructions. Only the original 6502 opcodes can be assumed to be common. As for the ROM entry points, clone the git repository for the c65gs, put a 910111.bin file there and one of the make targets will produce an annotated dissasembly of the ROM. You will also find dis4510.c which I wrote specially for this, and c65-rom-annotations.txt which has the annotations that get applied to the ROM. I have also just started annotating the october 1991 ROM, but not got very far. It is quite different to the earlier one.