VGA adapter internals.


The important feature is to have a 25 MHz pixel clock to make LCD monitors relatively happy.So we need to rescan the video at a rate not related to the Apple bus clock. One solution is to scan a line at the Apple rate into a FIFO and display it at a different rate while capturing the next line into a second  FIFO. Sinse we have a lot of RAM on board another approach that I actually use is to just shadow every byte written into the Apple's video RAM and scan it at whatever rate we like. Then again we have 256K of RAM. Why limit ourself to the video buffer? We shadow every byte written by the 6502 unless we have a better use for the RAM. What for? For example to be able to  make snapshots of the memory to the MMC card. Of course we can emulate a big RAM card if we want and we have a lot more memory for that.

MMC/SD interface


The second part of the default configuration is a storage device using the MMC/SD flash memory card. At the very basic level there is an SPI controller that can be directly driven by the Apple's CPU.  A byte written to a card's i/o address starts an 8 bit SPI transfer. Then read back the result. This is good for non-standard commands but too much trouble for a basic block read. So there is a state machine that uses a 24 bit block address and requires a single start command to read a 512 byte block into internal memory on the CB card. The block size on an MMC card happens to be the same as the ProDOS block, so a ProDOS driver would need to write 2 bytes of the address ( the high bits will always be zeros) and start the transaction. The  memory buffer is mapped into the $C800-$C9FF space that becomes visible on the Apple's bus after accessing $CFFF to turn of any competition and reading from the $CXyy space belonging to CB's slot. This way a block of data can be read extremely fast. The problem is that only the first 32MB can be addressed directly. But wait - don't we have another register that holds the high order bits? Sure, but somebody needs to set them up. I'm sure somebody will write a front end application for the 6502 to do that. So far my default configuration uses a different approach.

Soft Z80


I hate to waste resources so seeing only a tiny fraction of the FPGA used was somewhat painful. So I added a little functionality in the form of a soft CPU - a free implementation of a z80 core - TV80. It's happy to run at 50 MHz. Currently it is mostly used to initialize the MMC/SD card (instead of a 6502 program doing it) and allow the user to select an image to use. That is a NIB image. After one is selected the combination of hardware and code emulates a floppy. Just like the PseudoDisk.
One problem is that the programs runs on the soft CPU that has no direct input devices. At least none present in every Carte Blanche. My interim solution is watching the $C000 address on the bus and react to some keyboard codes. For example if no disk is found after reset Apple will sit in a loop waiting for keyboard input to the BASIC interpreter. Z80 looks for left and right arrows and the ENTER key. Apple doesn't mind these codes - it just opens another line with a "]" prompt. So if we press the right arrow twice and then hit ENTER the third NIB image from the FAT formated MMC/SD card will be selected. While this happens the VGA shows the directory of the SD card with the current choice highlighted. After the ENTER key is hit the screen changes to a copy of the Apple screen. So is CB is in slot 5, you can type PR#5 and boot the virtual floppy.
This is far from perfect. I'm open to ideas on how to improve it. Keep in mind that we have a block of memory visible in the $CXyy and $C800-$CFFF space that is preset at boot and can be rewritten from the z80 side. For example if a file with a certain name is found on the flash card it can be read into this space.

3 modes of "disk" operation



I have added a third and probably most useful mode to the "disk" on SD card emulation - a file under FAT16 emulating a ProDOS volume. So here is the summary of all the modes.

1. No FAT is detected on the flash card. A raw ProDOS volume is assumed. The soft z80 is not controlling the MMC/SD interface any more and a 6502 can access the interface directly.

2. A FAT is detected and an image that does NOT have a .NIB extension is selected. This is almost like the previous raw mode but the offset of the file is added to whatever the 6502 is setting. So if there is a file that is an image of a ProDOS volume on the card it will be used.

3. A file that has a .NIB extension is selected. Apple will see a DOS 3.3 ROM in the Cx00 space and z80 will monitor the "track" selected by the 6502. The whole track is read into a buffer and each byte  in sequence will appear at the $C0XC address. Read only.

Last but not least the 6502 can use the SPI interface directly to send arbitrary commands to the MMC/SD card. For example to read a huge file as a stream.
Debug additions
While waiting for the production Carte Blanche to be ready I have added some debugging capabilities to the board. I have borrowed parts of a z80 monitor machine language code and added that with some modifications to my code. A soft UART is used to communicate with it. A $18 USB/serial cable (at 3.3V levels) is used to connect to a PC.  Only a few commands are implemented: dumping memory and reading and writing the i/o regsters, but this is quite useful. Apart from being able to debug the z80 program itself, the top 32K is mappped to the low 32K of Apple's memory. So you can examine say the zero page while Apple is running.

terminal

The most useful new feature is a hardware breakpoint. The idea is very simple: a pair of registers writable by the z80 contains an address in Apple memory space. When a byte is fetched (by 6502) from this address, INH signal disables the memory and a $00 (BRK) is fed to the bus resulting in a break into the monitor even if the address is in the ROM area. Even if Apple writes over this address. For example set the break at $0801 and boot a floppy. This will cause a break after reading the first sector.  Yet another new feature is the trace buffer. Another pair of registers holds a trigger address. All the bus transactions are written into a circular buffer. After the tigger address is hit you can watch 511 things that happened before it did. For example this is extremely useful if you need to understand what code writes over some memory. My current implementation is rudimentary but there is plenty of unused logic to play with if needed.