Saturday, February 9, 2019

CF7 Compact Flash Hacking...

One of the devices I have for my TI is a cheap little compact flash adapter called either the CF7 or the NanoPeb... it changed names at some point. It didn't come with much for documentation but now that I actually need to get big files into my TI, I decided to see if I could figure it out.

I had a dump of the BIOS already, so I loaded that into my emulator and it didn't take long to map out the startup register accesses. From there it was a quick verification to map that to the CF spec, and I had the data I was interested in.

For anyone curious, the read registers map at >5Exx and the write registers map at >5Fxx (when CRU base >1100 is turned on, of course).

The CF7 deliberately uses 16-bit access but only 8-bits of the bus, but I found turning on 8-bit mode in the CF card worked just fine, so the entire card data is accessible by the hardware, at least. I need to do a little more work on the sector mapping though.. I couldn't (quickly) find sectors I wrote on the PC, using LBA addressing. I think that's a sector, but I need to double-check.

CF seems pretty forgiving, I was even able to command reads and writes through Easy Bug. But I did hit the issue with larger cards just not working when I tried my 512MB card. Reading would hang in EasyBug (on the LED at least), and I would forever get the first byte from the sector only.

Oddly, the startup was able to overwrite my boot sector (grr...), so I guess access is intermittent. It'd be neat to figure out why the cards don't work, but I guess I have bigger fish to fry right now.

My 32MB card works fine, so I guess I'll go try to find some mid-size cards at Fry's tomorrow and see if any of them work. If I can just find one that works, then I can write some code to program Dragon's Lair right from the compact flash card, just using sector reads.

It'd be fun to someday write a replacement DSR that could read a normal card... but add that to the huge stack of things I'll never get to...

Thursday, February 7, 2019

Dragon's Lair Status

While you really want to be watching Twitter for the silly raw status, but some big changes happened recently that I figured I'd chat about.

Basically, we got everything up, we got the code finished, we got the cart stable, and I went ahead and opened up orders. Then I started building and realized that building SMT PCBs is a level 9 skill, and I'm at best a mid-level 8. They're coming, very slowly, but the quality is lower than I am happy with.

Of course, if I had more time, I could work at it and level up my skills. But I'm down to about 45 days before the license expires. So, I panicked.

I will keep working on it, but I decided to investigate manufacture, which I should have done in the first place. The reason that I didn't, you see, was because I didn't provide a way for the flash chip to be programmed on the board. In my mind, at the time, I needed a way to get 56 pins off the board and into my EPROM programmer, which seemed hard. And hey, how hard can assembling 120 boards be?

I've worked late into the last couple of nights and tonight finally got everything going, and so I thought I'd chat about the challenges I went through. Cause they were fun. Ish.

In studying the datasheet, I realized that I actually had all the important pins running through the CPLD already, except two. I had locked down both Output Enable (OE) and Write Enable (WE). OE because the gating to the TI bus was performed by the CPLD. WE because I decided I didn't need to support writing the flash.

It's important to note that the CPLD is totally full - I actually can't support flash writes in the standard cart. But it's trivial to reprogram the CPLD, and so I realized I could use a second CPLD load and write through the card edge connector, if I only just routed OE and WE through the CPLD too. So, I tied up two of the spare lines for that.

The next question was how I was going to use that card edge connector. I eventually realized that I could use my CF7 - this is a compact flash adapter for the TI that simulates 3 floppy drives. But it's possible to change the active disk image from software, and I believe there are 256 available disks. If true, at 400k each that gives us 100MB, which is smaller than the flash but big enough for Dragon's Lair.

Now there is an issue in this interface, and that is control. In order to erase and write a flash chip, you have to be able to issue a precise sequence of writes without any intervening reads. Furthermore, since I'm in 8-bit mode, they need to be 8-bit writes. The problem is that the TI is a 16-bit machine: every access is /always/ 16-bits. Furthermore, every write is preceded by a read - the TI always does a read-before-write access.

So, this means, at the 8-bit cartridge port, every 8-bit write is actually four accesses long - two reads and two writes, only one of which we care about.

Now, the way that the cart works right now, is that we have 13 bits of address space (8k) and 8 bits of data. During a write, we simply capture 12 of those address bits and use them to extend the address bus - this is a pretty simple mapper. Write to ROM and the address you wrote to is used to change the upper 12 address bits. (Why 12? Because of the 16-bit-to-8-bit issue, since every write always becomes two writes, we can't trust the least significant bit. So we ignore it.)

12 bits doesn't give us enough latch though - 2^12 * 8k gives us 32MB. To get 128MB, we need two more bits of latch -- so we just take them from the data bus.

So, in order to program the entire flash, we still need that latch to work, so I thought about using the GROM side to manage the flash writes. But the GROM side is rather tricky - it doesn't have dedicated address pins and instead needs an onboard address register - and all the gates needed to sort data writes from address writes. With it, there's really no room in the CPLD for changes.

After a little consideration, I decided to hack my TI. I disabled the GROM Select line, and tied it to one of the memory expansion pins. This basically gives me a different select line already wired into the CPLD - I just access the cartridge port from a different address. This let me preserve all the existing functionality - read data from >6000, and write the latch at >6000. I decided the new address - nicely out of the way at >E000, would be solely dedicated to writing the flash. Reads from >E000 would be completely ignored.

Unfortunately, GROM was how I managed the reset timing, which is longer than the TI startup. So I decided to make the reset software controlled. I took one of the unused data bits in the latch block, and used it to directly manage the reset line. So now the TI software can explicitly reset and unreset the flash.

So setting the CPLD to relay those writes was easy, but now I come back to the problem - I need to control the writes at a byte level. I decided to use two more bits to control the MSB write, and the LSB byte. If they were both set, then the full 16 bit write is available, which I thought would be helpful to speed up the buffer fill.

When I fired this up - I ran into a new issue that was completely unexpected. Two of the data lines to the flash were input-only. I could not switch them to bidirectional for the writes. This means that a PCB change was going to be required, but there was really no way around it. I took the last two spare pins and remapped them as the data pins.

Then I loaded the cart up and tried it. I was able to put the flash in CFI mode and read back the data, but this was easy. It's just a single write. But I wasn't able to get the write to work.

The first thing I found was that the address for unlock was wrong in the datasheet for 8-bit mode. It reported writes to 0xAAA and 0x555. This required me to go back to 0x6000 inbetween to switch from MSB writes to LSB writes. In 16-bit mode, the addresses are 0x555 and 0x2AA. Noting that the addresses in CFI mode were doubled, I found that double addresses are, indeed, 0xAAA and 0x554. As an advantage, it is all MSB writes. I tried this, and was pleased to see that my single byte write worked!

However, LSB writes didn't work.

I finally had to spend a lot of time with the scope to see what was going on, and I realized that when I went back to 0x6000 to change the byte mask, the hardware was performing a read before the write, and interfering with the sequence.

Fortunately, I had one setting left - if the two bits of the word mask were 00, neither write would reach the flash. So all I did was say that if either bit was set, reads to 0x6000 were disabled. Finally, it worked!

So, I have a lot of software to write now, and I have to prepare a compact flash card. But I've proven that the hardware can do what I need to do, so I have sent off the PCB for quote. If it works, it will set me back 3 weeks but also should give much higher quality results. I hope so anyway!

I dunno, just wanted to talk about that somewhere. Haven't officially announced this cause I'm waiting for feedback from the manufacturer, tomorrow I hope. ;)