BMOW title
Floppy Emu banner

Unlocking the Secrets of the UDC Disk Controller

I concluded my last post about my Yellowstone disk controller for Apple II by saying I would probably support intelligent Smartport drives and 5.25 inch drives, but not 3.5 inch drives. But since then I’ve been busy investigating the possibility of a multi-purpose disk controller that could support all three drive types, by studying the Universal Disk Controller (UDC) that was marketed by Laser, VTech, and CPS. I’ve made some good progress, but big mysteries still remain.

There were two physical versions of the UDC: the original “long” version and the later “short” version. There were also at least four different firmware versions, and probably many more. The UDC’s capabilities may have changed substantially between versions. I have ROM dumps for firmware versions $21, $23, $30, and $40. Initially I thought these hex values for version number should be converted to decimal for interpretation, so for example $21 meant human-readable version 3.3. But it now seems more likely we’re intended to just put a decimal point between the two hex nibbles, and so I have firmware versions 2.1, 2.3, 3.0, and 4.0. The 2.x versions are from long UDCs and the 3.0 and 4.0 are from short UDCs.

 
ROM Spelunking

Unfortunately I don’t have any UDC cards! All of my investigation is based on analysis of these ROM dumps and contemporary documentation.

Making sense of the ROM is a slow and tedious task. It’s quite possibly the most time invested for the least reward of anything I’ve ever attempted. Running the ROM dump through a 6502 disassembler produces thousands of lines of output like this:

CF9B   AD CF CA   LDA $CACF
CF9E   C5 41      CMP $41
CFA0   F0 37      BEQ $CFD9
CFA2   90 42      BCC $CFE6
CFA4   E5 41      SBC $41
CFA6   8D DD CB   STA $CBDD
CFA9   A9 0B      LDA #$0B
CFAB   20 F8 C9   JSR $C9F8
CFAE   A9 0E      LDA #$0E
CFB0   20 F8 C9   JSR $C9F8
CFB3   BD 8D C0   LDA $C08D,X
CFB6   BD 81 C0   LDA $C081,X
CFB9   BD 8E C0   LDA $C08E,X
CFBC   10 F5      BPL $CFB3
CFBE   CE DD CB   DEC $CBDD
CFC1   D0 EB      BNE $CFAE
CFC3   AD C6 CA   LDA $CAC6
CFC6   29 20      AND #$20
CFC8   D0 0A      BNE $CFD4
CFCA   A9 01      LDA #$01
CFCC   20 02 CA   JSR $CA02
CFCF   BD 8E C0   LDA $C08E,X
CFD2   30 FB      BMI $CFCF
CFD4   A0 00      LDY #$00
CFD6   88         DEY
CFD7   D0 FD      BNE $CFD6
CFD9   A5 41      LDA $41
CFDB   8D CF CA   STA $CACF
CFDE   AC D4 CB   LDY $CBD4
CFE1   99 D2 CB   STA $CBD2,Y
CFE4   18         CLC
CFE5   60         RTS
CFE6   A5 41      LDA $41
CFE8   38         SEC
CFE9   ED CF CA   SBC $CACF
CFEC   8D DD CB   STA $CBDD
CFEF   A9 0F      LDA #$0F
CFF1   D0 B8      BNE $CFAB

It looks indecipherable. But I can replace a few known memory addresses with symbols, such as all the references to addresses in the $C08x range, which are IWM latch addresses on the Apple II. I can examine the subroutines that are called from JSR instructions, infer what some of the simplest ones are doing, and replace their addresses with symbolic names. The referenced memory locations like $41 and $CACF are clearly state variables of some kind. I can look for all the places where those locations are used or modified, and begin to guess what they’re used for, and give them symbolic names too.

Eventually some parts of the code will become more readable. This helps me to make better inferences about other code that references the newly-readable parts. This process repeats in a sort of recursive fashion, until after many many hours and thousands of lines of opaque code analysis, the code above is transformed into something like this:

; ROMFUNC 81 - Seek
; seek to track for 3.5 drive
L4CF9B   LDA CUR_TRK          ; current track 
         CMP WANT_TRK         ; desired track 
         BEQ L4CFD9
         BCC L4CFE6
         SBC WANT_TRK         ; subtract to get the number of tracks to step
L4CFA6   STA $CBDD            ; init the step counter
         LDA #$0B             ; write drive register 0100: step direction towards track 0
L4CFAB   JSR WRREG35
L4CFAE   LDA #$0E             ; write drive register 0001: perform step 
         JSR WRREG35
L4CFB3   LDA SENSE_ON,X
         LDA PH0_ON,X         ; redundant? PH0 was already on
         LDA WRITE_OFF,X      ; check if step is completed
         BPL L4CFB3           ; keep waiting if the step isn't yet completed
         DEC $CBDD            ; decrement the step counter
         BNE L4CFAE           ; loop back if there are more steps yet to be done
         LDA CUR_DRV_FLGS
         AND #$20             ; mask bit 5 of the drive flags (changed speed zones)
         BNE L4CFD4           ; skip ahead if flag is 1
         LDA #$01             ; read drive register 1110: READY flag
         JSR RDREG35	
L4CFCF   LDA WRITE_OFF,X
         BMI L4CFCF           ; keep waiting if the drive is not ready
L4CFD4   LDY #$00             ; busy loop delay
L4CFD6   DEY                  ; 256
         BNE L4CFD6           ; times
L4CFD9   LDA WANT_TRK
         STA CUR_TRK          ; update the current track number
         LDY DRV_NUM          ; maybe drive number?
         STA CUR_TRK_TAB,Y    ; set the current track number in the drive table
         CLC                  ; carry value 0 means OK/success
         RTS
L4CFE6   LDA WANT_TRK
         SEC
         SBC CUR_TRK          ; reverse subtract to get the number of tracks to step
         STA $CBDD            ; init the step counter
         LDA #$0F             ; write drive register 0000: set step direction towards track 79
         BNE L4CFAB

 
Intelligent Smartport Drive Support – The Phantom Feature

Firmware versions 2.1 and 2.3 from the long UDC are nearly identical. They contain support for intelligent Smartport drives, like Floppy Emu’s Smartport hard disk emulation mode, or the Unidisk 3.5 drive. I’ve looked at the Smartport support code in detail, and it seems correct and complete. And yet… there are many sources on the web saying the UDC doesn’t support intelligent Smartport drives, and connecting one will damage the drive or the card. Hmm.

The 2.x firmware versions don’t seem to have support for daisy-chained drives. That’s a big disappointment, since I would definitely like Yellowstone to support daisy-chaining if possible.

There are many things in this firmware that look “not quite right”. I see unnecessarily convoluted code, limitations, questionable assumptions, and possible bugs. It could be that I just don’t understand the code fully enough, but it really looks like it was written by somebody who didn’t totally understand what they were doing, or was in a rush, or was just not a very good programmer.

As best as I can tell, the long UDC corresponds to this version of the instruction manual, which says it supports up to two drives on two separate connectors. It’s sort of vague about intelligent Smartport or Unidisk 3.5 support.

Being somewhat disappointed in the 2.x firmware and its lack of daisy-chaining support, I began to analyze firmware 4.0. But after only a few hours I realized something terrible: it has no support for intelligent Smartport drives! And neither does firmware 3.0. The Smartport support that was there in firmware 2.x is gone.

Why, WHY would they remove previously-existing support for Smartport drives? It doesn’t make sense.

The short UDC appears to correspond to this version of the instruction manual, which says it supports daisy-chaining and up to four drives. Again, it’s sort of vague about intelligent Smartport support.

According to sources I’ve read, later models of the Laser 128 computer contain an integrated UDC as a floppy drive controller, and these computers do support intelligent Smartport drives. This Australian web page has some helpful info if you search for “UDC”, about halfway down the page. There’s also the Laser 128 manual, where the chapter on disk I/O has a detailed discussion about the different types of drives and specifically lists Unidisk 3.5 as one of the supported drive types for the Laser 128. Which UDC version is that?

 
Still Searching for Answers

So that’s where I am. I’d like to make a disk controller card that handles all three Apple II drive types, and daisy-chaining, similar to the Apple IIGS. UDC firmware 2.x seems to support Smartport drives (although there’s some question about this), but doesn’t support daisy-chaining, and overall looks a bit rough. UDC firmware 3.0 and 4.0 supports daisy-chaining, but support for Smartport drives was removed. And the Laser 128 contains an integrated UDC that reportedly supports Smartport drives, but its daisy-chaining capabilities are uncertain. Clear as mud. Where do I go next?

Maybe firmware 3.0 and 4.0 do contain support for Smartport drives, but it’s so cleverly obfuscated that I missed it? That seems very unlikely. Maybe I could take the code for Smartport drives from firmware 2.3 and somehow add it to firmware 4.0 to create a version that does everything? That sounds extremely difficult – even after my marathon code analysis, I don’t understand the details well enough to attempt something like that. Maybe I need a ROM dump from a Laser 128? Or maybe I should forget about the UDC altogether, and take up a new hobby? 🙂

Read 10 comments and join the conversation 

10 Comments so far

  1. Joshua Bell December 24th, 2020 12:08 pm

    Data point, from a recent experiment: my Laser 128EX (ROM 4.2) could access an Apple 3.5 drive but not a Floppy Emu in SmartPort mode chained after it.

  2. Joshua Bell December 24th, 2020 12:09 pm

    (It can access the Floppy Emu in SmartPort mode if directly connected, of course.)

  3. Roy December 24th, 2020 4:35 pm

    Wow, it’s been a long time since I looked at 6502 assembler. I spent a LOT of time doing that way back when, and really enjoyed it.

    I remember trying to reverse-engineer code like you’re doing, and I don’t envy you a bit! (No computer-nerd pun intended)

    I agree that it’s entirely possible that the device driver code was hacked together by someone who didn’t really know what they were doing, and were just desperately trying to get it to work.

    Good luck…

  4. David Brown December 25th, 2020 12:58 pm

    Sounds like maybe the original 2.x code was written with a goal of support for the SmartPort, but the original programmer got replaced before it was released. So someone got the task of “making it work” at the last minute and never officially supported SmartPort because they were too busy getting the rest working. Then the new card came along and with a new firmware base, it was just left out of the new version, possibly due to time/budget constraints. Anyhow, I’ve seen similar things happen before…

  5. Steve December 26th, 2020 9:29 am

    Yeah, I would probably conclude that SmartPort was a UDC feature that never quite worked, and was just removed from later firmware, except that the Laser 128EX with its integrated UDC *does* support Smartport drives, as @Joshua attests, though apparently not with daisy-chaining.

    How do you determine the Laser 128EX ROM version? I’m not sure if that’s the same as the UDC ROM version at $C615 (assuming the card is in slot 6). If those version numbers are related, then maybe SmartPort support was re-added between ROM 4.0 and 4.2?

  6. Steve December 26th, 2020 12:33 pm

    I downloaded ROM dumps for Laser 128 ROM versions 4.2, 4.5, 6.0, and 6.1, and poked around until I located a section that looked similar to any UDC ROM. Then I poked through that section looking for code that simultaneously sets the disk I/O signals PH1 and PH3 to 1, which is how SmartPort drives are enabled. I found code for the SmartPort enable sequence in Laser 128 ROM versions 4.2 and 4.5, but not in 6.0 or 6.1.

    It’s possible the SmartPort code was simply redesigned as of Laser 128 ROM version 6.0, so the code sequence I’m looking for is different now, but I doubt it. I didn’t find any explicit reference to PH3 anywhere in the 6.0 or 6.1 ROMs.

    As best as I can tell, VTech/Laser intentionally dropped SmartPort support from the UDC somewhere between ROM version 2.3 and 3.0, and dropped it from the Laser 128 somewhere between ROM version 4.5 and 6.0.

  7. Merlin December 27th, 2020 5:39 pm

    They may have originally supported the SmartPort, but then had issues with their implementation (complaints from the field). They may have then re-looked at the code to support the SmartPort, and realized they either didn\’t know enough about it to REALLY support it, or just decided it just wasn\’t worth the hassle. Just guesses.

  8. Tom Greene December 31st, 2020 4:46 pm

    my Laser 128EX/2 with ROM v6.1 definitely does support Smartport mode. I have used the Floppy Emu to run Total Replay on it.

  9. Steve December 31st, 2020 5:26 pm

    Really, wow! Then I am stumped to explain it. Do you recall what number slot the Smartport devices are mapped to?

  10. Chris M. January 7th, 2021 10:08 am

    If Laser/VTech followed Apple’s design, they likely put the Smartport firmware in Slot 5. Someone with a Laser 128 should be able to dump that part of the ROM by poking around in BASIC. One would need to know the bank switching commands if the boot ROM code is larger than 2K and capture the $C800 space multiple times.

Leave a reply. For customer support issues, use the Contact page instead of comments.