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 12 comments and join the conversation 

FPGA Disk Controller Next Steps

After more than two years of sporadic effort, my Yellowstone FPGA-based disk controller card for Apple II is finally working. That means the fundamental disk control capabilities are there, but there’s still a great deal of work left to do. Now I’m at a crossroads, and must decide what else makes sense to add, and what I’m genuinely interested to pursue. So what’s next?

In its current state, the card can function in one of two modes. Mode one is a work-alike Apple Liron disk controller, which is compatible with intelligent disk drives like the Unidisk 3.5 and the BMOW Floppy Emu‘s Smartport hard disk emulation. The best use of Liron mode is probably adding 32 MB hard disks to an Apple II+ or IIe with a Floppy Emu.

Mode two has the functionality of the standard Disk II controller for 5.25 inch floppy drives. That’s maybe less exciting since virtually everyone already has one of these, but there are plenty of uses for a second 5.25 inch disk controller. eBay’s supply of original Disk II controllers is shrinking, and prices are climbing, so it’s helpful to have an alternative. There’s still some work remaining to finish Yellowstone’s support for 5.25 inch floppy writing (reading is finished), but I don’t anticipate any major difficulties there.

 
Electronics and Mechanics

My first task for version 2 is to address a lengthy list of board changes. Most of these won’t change the card’s behavior, but they’ll help it to work more reliably and safely, and provide for future improvements. These changes include things like adding termination resistors and bus drivers to isolate the FPGA, a bigger voltage regulator, test points for all the important signals, more capacitors in different places, improved power/ground routing, and adding a second disk connector.

Some helpful Apple II bus signals aren’t connected correctly, or aren’t connected at all, so I’ll need to fix that. A hardware solution for self-programming needs to be designed and added too. There’s lots of work to do in this category, and it could keep me busy for weeks. That’s frustrating when all I want to do is develop new features, but taking care of the card’s electronic fundamentals is important.

 
Drive Type Auto-detection

The two modes are selectable with a jumper on the card. It’s either a Liron or a Disk II controller. It would be nice to merge these somehow, and auto-detect the type of attached drives. A basic solution would auto-configure the card into one of the two modes. A more complex solution would create a hybrid mode that could support Smartport drives and 5.25 inch drives at the same time on different disk connectors.

I’m not sure how to do either of those, especially the hybrid mode, which I think would require some detailed research into how typical software boots and what assumptions it makes about the card it’s booting from. From what I’ve read, some software assumes it’s booting from a Disk II card, and jumps to specific addresses in the card’s onboard ROM to help load sectors during the early boot process. This won’t work if my card’s ROM contains some custom hybrid Liron/DiskII code. Hopefully there’s a clever solution to this, like retaining entry points for Disk II compatibility at a few key addresses in the ROM code.

 
Attaching Drives

What’s the best way to attach drives to this card? It might have a single DB-19 female connector, and support a daisy-chain of several drives, like the built-in disk connector on the Apple IIGS. Or it might have two 10×2 rectangular connectors for ribbon cables, like the connectors on the Floppy Emu and on the Disk II controller card. Or it might even have two DB-19 female connectors.

The 10×2 rectangular connector is probably the best option, simply because female DB-19 connectors are so hard to find. I have a small supply, which I use to manufacture the BMOW Daisy Chainer for Floppy Emu. But pretty soon those will all be gone, and then the DB-19F will be extinct unless somebody wants to spend $15000+ for a Chinese factory to make new ones.

A compromise solution would be to use 10×2 rectangular connectors on the card, but design an optional rectangular-to-DB19F adapter. That way a female DB-19 would only be used where it’s needed. At the moment, that’s only for connection to a Unidisk 3.5 drive or the slim 5.25 inch drives (I forget what these are called… also Unidisk?). Disk II drives and the Floppy Emu use the 10×2 rectangular connector and don’t require a female DB-19.

I mentioned daisy chaining, but I’m not sure how that would be implemented in software. From my work on Floppy Emu, I’m familiar with how daisy chaining is implemented electronically for the drives, but I don’t know how the card’s ROM code detects and keeps track of all the drives in the chain. Daisy-chaining also means moving away from the simple “Slot X Drive Y” scheme to an environment where a disk controller card can have more than two drives attached, which somehow get mapped to other virtual slots. Yes there’s documentation for this, but it’s just one more challenge added to the pile.

 
Firmware Updates

All the interesting parts of the Yellowstone card are implemented in an FPGA, and I expect the FPGA design will be updated over time to fix bugs and add new features. Ideally there should be a way to update the FPGA for a Yellowstone card that’s in the field, without requiring the Lattice design IDE and JTAG programming hardware.

I haven’t confirmed this, but I think there’s a way to export the FPGA firmware from the Lattice IDE as a JTAG player file – basically a sequential list of JTAG commands. Then a stand-alone third-party hardware/software solution should be able to update the FPGA. In this case, that solution could be the Apple II itself. I need to design a way to bit-bang the JTAG signals from the Apple II, possibly using the game port, or even just using the address and data bus. It may be very slow, but it should work. Unfortunately the FPGA can’t help with this, since it will be in the midst of being reprogrammed, and so I’ll probably need to include some additional hardware on the card to support this self-programming.

One drawback of a self-programming approach is that the entire FPGA player file must be small enough to fit entirely in the Apple II’s RAM. It can’t be loaded piecemeal from the disk, because the disk controller will be non-functional while it’s being reprogrammed. This problem could be circumvented by using a second disk controller, but that doesn’t seem very elegant.

 
Support for 3.5 Inch Drives

The biggest unknown is potential support for unintelligent (dumb) 3.5 inch floppy drives, like the Apple 3.5 Drive A9M0106. From a completionist point of view, this would be great, because it would bring Yellowstone support for all three major types of Apple II disk drives. But there are some good reasons to omit it. In brief, it would be very complex and not very useful.

What is useful? While it would be nice to have, I believe there isn’t a strong need for a dumb 3.5 inch floppy controller card like this. If the main audience for the Yellowstone card is the Apple II+ and IIe, there just isn’t very much II+/IIe software on 3.5 inch disks. And even where software is on 3.5 inch disks, it could already be supported using the Yellowstone card in Liron mode with the Floppy Emu in Unidisk 3.5 emulation mode. The only case where dumb 3.5 drive support would be needed is connecting a real Apple 3.5 Drive A9M0106 to a II+ or IIe.

I would add 3.5 support anyway if it were easy, but it’s not. The Disk II card is basically a proto-IWM, and fairly easy to replicate in an FPGA. The Liron card is a full IWM with some extra bits of address decoding and a larger ROM. But the Apple 3.5 Disk Controller is crazy complex with its own onboard 6502 CPU, 32K of onboard RAM, a SWIM, and gobs of programmable logic. I don’t want to attempt replicating something as difficult as that, and I don’t even have an Apple 3.5 Disk Controller to examine. So… no.

A slightly more plausible path would be to follow the example of the Universal Disk Controller (UDC) that was marketed by Laser, VTech, and CPS. The fundamental problem of 3.5 inch disk support on an Apple II+ or IIe is that a 1 MHz 6502 isn’t fast enough to keep up with the bit rate of a 3.5 inch disk. The Apple 3.5 Disk Controller solves this problem by essentially putting an entire second computer on the disk controller. The UDC takes a different approach, using the regular Apple II CPU, but halting it at key times with the RDY signal instead of expecting the code to do busy wait loops. The elimination of busy waiting saves just enough CPU cycles that the 1 MHz CPU can handle the faster bit rate – or so I understand.

The UDC is interesting in that it’s a hybrid 3.5 / 5.25 inch drive controller. But duplicating the UDC would be no simple task. There are two versions, one with a hairy mass of 7400-series logic and the other with a single ASIC. Here’s an image of the “long” version with the 7400-series logic:

I don’t have examples of either type, so my efforts would be limited to examining photos and reverse-engineering the card’s ROM. I spent some time examining the ROM code, and it’s very complex. It appears to be an 8-way bank-switched ROM, with 2-way bank-switched onboard RAM, and it makes extensive use of self-modifying code. Here be dragons.

Help! If anybody has a UDC card they’d be willing to lend or sell, please let me know!

So for the time being at least, Yellowstone will offer Liron support (intelligent Smartport / hard disk) and 5.25 inch floppy drive support. Dumb 3.5 inch floppy drive support might come later as a version 2.0 type of feature.

 
Next Steps

That’s the state of everything as of today. There’s still a tremendous amount of work to do, but I’m happy to be making forward progress again. Do you have any suggestions or advice on where to go next, or how to address some of the challenges I’ve mentioned here? I’d love to hear it – please leave your feedback in the comments.

Read 18 comments and join the conversation 

BMOW Inventory Restock

The BMOW Wombat ADB-USB input converter and the Internal/External Drive Switcher for Apple IIc are now back in stock at the BMOW Store. Head there to get yours now.

Wombat what? The Wombat is a bidirectional ADB-to-USB and USB-to-ADB converter for keyboards and mice, and was developed by Steve Chamberlin here at Big Mess o’ Wires. Connect modern USB keyboards and mice to a classic ADB-based Macintosh, Apple IIgs, or NeXT machine. Or connect legacy ADB input hardware to a USB-based computer running Windows, OSX, or Linux. No special software or drivers are needed – just plug it in and go. For more details, please see the product description page.

The Internal/External Drive Switcher for Apple IIc is a convenience option for Floppy Emu owners with a IIc, and makes life easier when when emulating a 5.25 inch floppy disk drive for that computer. It provides a simple way to select whether the internal floppy drive or external Floppy Emu will appear as 5.25 inch Drive 1, which is the only bootable drive on the IIc. More details are here.

Read 3 comments and join the conversation 

Yellowstone Back From the Dead

Remember the Yellowstone disk controller card that I designed back in 2018? It was an FPGA-based clone of the Apple II Liron controller, with aspirations to eventually become a universal reconfigurable disk controller. And it worked nicely when it was the only card installed in the computer, but things went haywire when too many other expansion cards were also present. I eventually gave up and abandoned the project, but now I think I’ve fixed it.

The symptoms were documented in a series of blog posts here, here, here, and here. The more expansion cards present along with Yellowstone, the more likely I was to see errors such as unexplained resets and lockups and drops into the Apple II system monitor. Investigation with an oscilloscope showed lots of nasty looking signals, huge over and undershoot on the data bus, and strange transients on the power supply during card I/O.

There were plenty of theories to explain the problem, and I received over 100 comments from helpful readers. Some theories put forward were: poor grounding, insufficient bulk capacitance, a too weak 3.3V regulator, impedance mismatch, bus fighting, failure to meet the minimum input high voltage, a too strong or too weak drive from the bus driver IC, wrong FPGA slew rate, bad scope probes, bad power supply in the Apple II, a race condition in the logic, and more. My own best guess was a combination of grounding and impedance problems. I spent many weeks chasing various theories without much success. I hacked the card and replaced its bus driver with one from a different logic family. I even started to wonder whether the whole problem lay with the computer rather than the card. By March 2018 I gave up in frustration.

 
Two and a Half Years Later

This past week I’ve been investigating ideas for an Apple II video card, and a reader pointed me to this tech note about Apple IIgs expansion card design. The point was to learn which signals were provided to the different slots, but my eye caught a different paragraph titled “Avoiding Bus Fights”. As the text described,

“To avoid potential (or actual) bus fights, it is helpful to avoid driving read data from an expansion card onto the bus immediately after PH0 rises. … If a card drives data onto the expansion slot data bus immediately after PH0 rises, there may be a bus fight between the expansion card trying to drive the bus, and the Apple IIGS (or Apple IIe) bus buffers, which may not have turned around yet. … Developers can avoid bus fights by simply using 74LS or 74HCT series parts and relying upon typical delay stackups to delay driving the data bus for approximately 30 nanoseconds. A more solid technique is using the first rising edge of the 7M clock, after PH0 rises.”

My card responds when the Apple II asserts the I/O SELECT signal for its slot, which happens at the same time as PH0 rising. What this paragraph says is that the card should intentionally wait at least 30 ns before responding, because the motherboard’s 74LS245 bus driver is still driving the data bus even after PH0 and the assertion of I/O SELECT!

At first glance this seems ridiculous. Why would the Apple II assert I/O SELECT for a card before it’s safe for the card to output data? But if you assume the card is built with 1978 vintage ICs that can’t respond very quickly anyway, it wouldn’t have been a problem. The trouble only appears when you use an FPGA and modern logic families like 74LVC with propagation delays of just a few nanoseconds. It becomes necessary to add an artificial output delay to avoid bus fighting.

Several readers had suggested more or less exactly this, including Fluffysheap who described it perfectly in the comments here. But I must have been too frustrated or too tired back then, and I never fully followed through on checking this theory.

Bus fighting almost perfectly explains the horrible signals I observed on the scope. For a few tens of nanoseconds at the beginning of my card’s data output, it was fighting with the motherboard’s bus driver, creating eight short circuits on the 8-bit bus. This caused a surge of current, resulting in horrible power supply transients and wild swings on the bus. From my scope observations this period seemed to last about 70-80 ns, rather than the 30 ns mentioned in the tech note. But the tech note described the Apple IIgs, not the Apple IIe that I used for my tests. Maybe the Apple IIe bus driver is slower to shut off.

One thing that bus fighting doesn’t seem to explain is why adding more peripheral cards would make the problem worse. It appears my card was engaging in a bus fight with the motherboard’s own bus driver, and the other cards were just innocent bystanders. The only affect of their presence would be to increase the bus capacitance. I may still be missing something here.

 
Testing It

Armed with this newfound knowledge, I went to edit the Yellowstone FPGA source to insert an intentional delay before enabling the card’s bus driver for output. Lo and behold, code for creating a delay was already there, but commented out. It was written by me. I can’t remember if I ever tested it back in 2018. Maybe I had the idea but never tried it, or maybe I tried it but something went wrong. Either way, I gave thanks to 2018-Steve and just reapplied the already-existing code.

At first there was some comedy, because I tried several different changes that appeared to have no effect. After half an hour, I realized I was rebuilding the FPGA configuration file after each change, but then programming the old configuration file from 2018. Oops.

What can I say, it works. I loaded up my Apple IIe with a sampler of six different expansion cards in different combinations, connected to a variety of Floppy Emus and real drives, including a Smartport-aware Unidisk 3.5 drive. Everything worked as expected, and there were no unexplained resets or other weird behavior.

I looked at the data bus and the power supplies on the scope, and everything appeared cleaner than before. The power supplies looked OK. There was still some overshoot on the databus when the card first started driving, but much less than before. Maybe this can be improved further by adding some small inline resistors on the next version of the card. I adjusted the output delay to about 120 ns, which is probably much longer than necessary, but it still leaves more than ample time for 2020-era logic chips to do their jobs.

 
One More Issue

Things look good with Yellowstone on the Apple IIe, but the IIgs is another story. I have to switch the IIgs to normal speed instead of fast, but then the card should work. A real Liron disk controller card works fine in a IIgs, as long as the system speed is changed, so there’s no fundamental incompatibility. Unfortunately the Yellowstone card just plain doesn’t work on the IIgs. At first I thought that was a result of my new output delay, but removing the delay didn’t help. Then I dug through all my notes from 2018 and concluded that the card never worked on the IIgs under any circumstances. So this isn’t a new problem – it’s an old problem I just hadn’t noticed because it was overshadowed by the bus fighting.

The sort-of-good news is that this failure of Yellowstone on the IIgs seems repeatable and debuggable. Instead of weird spurious resets and lockups like I was seeing two years ago, it looks like it’s just a communication error with the drive. The Yellowstone card firmware appears to be running OK, and I get reasonable error messages like “NO DEVICE CONNECTED”. With a Unidisk 3.5 drive attached, there’s no drive activity. With a Floppy Emu attached and configured for Smartport emulation, it reports a checksum error.

I suspect there’s another timing problem here, but this one relates to writes to the card instead of reads. Perhaps I’m not latching the data from the bus at the right time, and due to minor differences between the bus timing on the IIe and IIgs, it still works OK on the IIe but occasionally writes the wrong values to the IWM chip on the IIgs, or fails to write anything. That would cause garbled communication with the drive.

I’m calling a stop for the moment, feeling pleased with this new progress, and optimistic that I’ll eventually find an explanation for the IIgs behavior.

Read 4 comments and join the conversation 

Apple II Video Card Thoughts

Recently I’ve been toying with the idea of building an Apple II video card. Like many of you, I’ve grown tired of searching for the dwindling supply of monitors with a native composite video input, and frustrated with available solutions for composite-to-VGA and composite-to-HDMI conversion. This card would fit in an expansion slot of an Apple II, II+, IIe, or IIgs, and provide a high quality VGA output image suitable for use with a modern computer monitor. I welcome your thoughts on this idea.

 
Why Do This?

Another Apple II video solution? Aren’t there enough options already? It’s true there have been many different Apple II VGA solutions over the years, and a smaller number of HDMI solutions. Unfortunately almost all of them have been retired, or have very limited availability. I’m also interested in this project as a personal technology challenge. It could combine some of my past experience with Yellowstone (Apple II peripheral cards) and Plus Too and BMOW1 (VGA video generation).

 
How Would It Work?

I see three possible paths for a high-quality Apple II VGA video solution. One is to convert the signals from the computer’s external monitor port. But monitor ports are only present on the Apple IIc and IIgs, and so that wouldn’t meet my goals. The second approach is to tap into a few key video-related signals directly from the motherboard, before they’re combined to make the composite video output. This is a viable approach, and others have been successful using this method. The downside is that it requires a snarl of jumper wires and clips attached to various points on the motherboard, and the details vary from one motherboard revision to the next.

I’m considering a third approach: design a peripheral card that listens to bus traffic, watches for any writes to video memory, and shadows the video memory data internally. Then the card will generate a VGA video output using the shadowed video memory as its framebuffer. It’s simple in concept, but maybe not so simple in the details. The first two approaches require only a comparatively dumb device to do scan conversion and color conversion. In contrast, the bus snooping approach will require the video card to be a smart device that’s able to emulate all the Apple II’s video generation circuitry – its weird memory layouts and mixed video modes and character ROM and page flipping and everything else. But it promises a simple and easy solution when it comes time to use the card. Just plug it in and go.

To be specific, for basic support of text and LORES/HIRES graphics, the card will need to shadow writes to these memory addresses:

$0400-$07FF TEXT/LORES page 1
$0800-$0BFF TEXT/LORES page 2
$2000-$3FFF HIRES page 1
$4000-$5FFF HIRES page 2

and these soft switches:

$C050/$C051 graphics / text
$C052/$C053 mix / no mix
$C054/$C055 page 1 / page 2
$C056/$C057 lores / hires

 
Can It Work?

For basic 40 column text mode, I hesitate to say this will be easy, but I don’t anticipate it being difficult. LORES and HIRES graphics may be more challenging, because the memory layouts are increasingly strange, and because determining what color to draw will depend on careful study of NTSC color artifact behavior. But I’m relatively optimistic I could get this all working well enough for it to be useful.

After finishing the basics, there will remain several more difficult challenges. First among these is sync. If the vertical blank of the VGA image isn’t synchronized with the vertical blank of the Apple II’s composite video, then tearing or flickering may be visible in the image. Carefully-timed program loops that attempt to change video memory only during blank periods won’t work as intended. Fortunately motherboard revisions 1 and later provide the SYNC signal to peripheral cards in slot 7, which can be used to synchronize the VGA and composite video outputs. For installation in a different slot or on a revision 0 motherboard, a wire can be connected to the motherboard for the SYNC signal, or the card can run unsynchronized.

What about European PAL models of the Apple II? I think Eurapple machines should work OK, since the card’s function is based on bus snooping rather than the actual video data. The VGA output will be the same, since fortunately there are no NTSC/PAL distinctions to worry about for VGA video. I’m less sure about Eurocolor machines. I believe these already have slot 7 occupied with an Apple video card – can anyone confirm? If so, my video card will have to go in a different slot, where the SYNC signal won’t be available. That’s probably no great loss, since software designed to sync with a 50 Hz composite PAL display can’t be synchronized with 60 Hz VGA anyway.

Can double-hires graphics and 80 column text be handled too? I think so, but I haven’t looked at these modes in much detail yet. From what I’ve seen, they both involve bank switching RAM between the main and AUX banks. Supporting these modes would mean shadowing some additional areas of memory, and a few more soft switches that control bank switching, as well as more software complexity. But they should be doable.

Non-standard character ROMs are another question. The video card will need to duplicate the contents of the character ROM in order to generate text. The most obvious solution is to simply assume the character ROM is a standard one, and include a copy of the standard character ROM on the card. But in some models of Apple II, it’s possible to replace the normal character ROM with a ROM containing an international character set in place of the inverse characters. These seem to have been common for Apple II computers sold in several countries. My card won’t know about the custom character ROM, and won’t render those characters correctly. I don’t see any easy answer for this issue. Possibly the card could use DMA to read the character ROM, but that would be a major increase in complexity.

Finally there’s the question of the Apple IIgs. Will the card even work in a IIgs? Maybe not, if writes to video memory on the IIgs are handled specially, and the address and data never appear on the peripheral card bus. That will be easy enough to test. Another question to consider is super hires graphics on the IIgs. I don’t know anything about how this works. I can’t think of any fundamental reason it couldn’t be handled in the same way as the other graphics modes, but it might be very complex.

 
Hardware Choices

What kind of hardware would be appropriate for a video card like this? It needs at least 18K of RAM to shadow the memory regions for text, LORES, and HIRES graphics. If 80 column text and double-HIRES are also supported, then the RAM requirement grows to something like 54K. The hardware must also be fast enough to snoop 6502 bus traffic and to shadow memory writes that may appear as often as every 2 microseconds. And it must also be capable of generating a VGA output signal with consistent timing and a pixel clock about 25 MHz.

What about something like a Raspberry Pi? Yeah… it might work, but it’s not at all the kind of solution I would choose. Those who’ve read my blog for a while know that while I’ve used the Raspberry Pi in a few projects, it’s not my favorite tool. I strongly prefer solutions that keep as close to the hardware as possible, where I can control every bit and every microsecond. That’s where the fun is.

Could it be done with a fast 32 bit microcontroller, something like an STM32? 54K of RAM would be no problem, and a 100 MHz microcontroller could probably handle an interrupt every 2 microseconds just fine. That would be enough to snoop the 6502 bus and shadow the writes to RAM. I’m less confident that a microcontroller could directly generate the required VGA output signal. If the caches could be disabled, it might be possible to write carefully-timed software loops to output the VGA signal. But the interrupts for RAM shadowing would probably screw that up, and make a hash out of the VGA signal timing.

A small FPGA is probably the solution here. 54K is rather a lot of built-in RAM for an FPGA, so the FPGA would need to be paired with an external RAM of some type – most likely SRAM or a serial RAM. Or the FPGA could be paired with a microcontroller, providing both RAM and some extra processing horsepower.

Read 45 comments and join the conversation 

How Many Bits in a Track? Revisiting Basic Assumptions

Yesterday’s post contained lots of details about Apple II copy-protection and the minutiae of 5.25 inch floppy disk data recording. It mentions that bits are recorded on the disk at a rate of 4 µs per bit. This is well-known, and 4 µs/bit appears all over the web in every discussion of Apple II disks. This number underpins everything the Floppy Emu does involving disk emulation, and has been part of its design since the beginning. But as I learned today, it’s wrong.

Sure, the rate is close to 4 µs per bit, close enough that disk emulation still works fine. But it’s not exactly right. The exact number is 4 clock cycles of the Apple II’s 6502 CPU per bit. With a CPU speed of 1.023 MHz, that works out to 3.91 µs per bit. That’s only a two percent difference compared with 4 µs, but it explains some of the behavior I was seeing while examining copy-protected Apple II games.

With the disk spinning at 300 RPM, it’s making one rotation every 200 milliseconds. 4 µs per bit would result in 50000 bits per track, assuming a disk is written using normal hardware with a correctly calibrated disk drive. 50000 is also the number of bits per track given in the well-known book Beneath Apple DOS. But it’s wrong. At 3.91 µs per bit, standard hardware will write 51150 bits per track.

Not content to trust any references at this point, I measured the number directly using a logic analyzer and a real Apple IIe and Apple IIgs. When writing to the disk, both systems used a rate of about 3.92 µs per bit. Here’s a screen capture from a test run with the Apple IIe, showing the time for 10 consecutive bits at 39.252 µs. There was some jitter of about 50 nanoseconds in the measurements, and measuring longer spans of bits revealed an average bit rate of about 3.9205 µs. That’s a tiny difference versus 3.91 µs. Can I say it’s close enough, and let it go? Of course not.

The Apple II’s CPU clock is actually precisely 4/14ths the speed of the NTSC standard color-burst frequency of 3.579545 MHz. (This number can be derived as 30 frames/sec times 525 lines/frame times 455/2 cycles/line divided by a correction factor of 1.001.) 3.579545 MHz times 4 divided by 14 is 1.02272714 MHz. Rounded to three decimal places that gives the advertised CPU speed of 1.023 MHz. But using the exact CPU frequency, four clock cycles should be 3.91111 µs. I can’t explain the remaining discrepancy of roughly 0.01 µs compared with my measurements, but I’ll chalk it up to measurement error.

But wait! In the comments to the answer to this Stack Exchange question, it’s mentioned that every 65th clock cycle of the Apple II is 1/7th longer than the others, because of weird reasons. That means the effective CPU speed is slower than I calculated by a factor of 1/(65*7). In light of this, I calculate a new average CPU speed of precisely 1.020479520466562 MHz, and a time for four clock cycles of about 3.9197 µs. That’s a difference of only 0.0008 µs from my measurement – less than one nanosecond. Ah ha! So everything makes sense, and my measurements were correct.

The difference between 4 µs per bit and 3.92 may seem like a minor detail, but for a floppy disk emulator developer, it’s like suddenly discovering that the value of pi is not 3.14159 but 3.2. My mind is blown.

Read 1 comment and join the conversation 

« Newer PostsOlder Posts »