Designing MD sdcard flashcart for fun, advice?

For anything related to cart (SRAM, SF2 mapper, audio, CD mode 1, ...)

Moderator: BigEvilCorporation

Post Reply
MrD
Interested
Posts: 21
Joined: Sun Jan 26, 2014 4:29 pm

Designing MD sdcard flashcart for fun, advice?

Post by MrD » Fri Oct 25, 2019 2:50 pm

Hello, I'm designing a basic flash-style cart to read games and demos from an SD card and write them to flash memory, as an exercise. I'd like to get Titan's OVERDRIVE demo working as I've met some of the makers. :)

I'm somewhat new to hardware engineering so I'd like a critical eye over my hardware and software design before I try to make it for real. Any advice would be appreciated!

(You might like my Ocelot Arcade System, PSCD32 controller adapter, my little Master System game or my YM2612 FM instrument editor from waaaaaaaaay back.)

My hardware stuff up until now has been pretty basic through-hole stuff. I was thinking of getting the PCB and SMT assembly done by JLCPCB so I'm constrained by the choice of parts they have. Luckily, the ones they have seem to lend themselves to a good layout.

My cart will have a 64Mbit Flash (8 MByte, 16-bit wide, 22-bit address space A0-A21) which I'll consider as two 4MByte halves. The lower 4MByte will be the BOOT half and will be selected when the FLASH A21 is low, this will contain the menu software and so on. The upper half will be a flat 4MByte address space to write a cartridge ROM image into.

Here's my organisation for the cart: click to enlarge

Image

Not shown is the 5V->3.3V regulator, a tank cap for the board, or the caps for each IC or the !CART grounded detection pin.

It'll boot up into a menu, read a list of files from the SD card, ask the user to pick one, then write the image to the upper 4MByte, then jump to it. I use a pin on the MCU to tristate the cart off the buses when I'm reading the file list or writing to the Flash, the 68000 has to wait until this is done before the next step can happen.

A basic summary of the steps:

1) !VRES is asserted, then negated. The cart starts connected to the 68000 address and data buses. The MCU sets up a rising edge interrupt on DETECTREGISTERCLK, then idles. The default state of !BOOT/GAME is to bankswitch in the lower 4MByte of the Flash. This will contain my menu code, etc. (I'm also going to use a 32Kbyte block of it to store the list of game names read from the SD card later.)

2) The Mega Drive performs the normal boot/TMSS sequence reading from the lower 4MByte of the Flash, and then boots into the set-up sequence of my cart's firmware.

3) The intro graphic is displayed, and a small code stub is copied to the Mega Drive RAM.

4) The stub is jumped to - the stub writes $0000 to the !TIME address $A13000, then NOPs for 0.5s, then continually reads $000006.w and loops continually while the LSB is set. The 68000 is locked in this loop until the cart signals its ready to resume.

5) The write to the !TIME address $A13000 is decoded by the cart and both populates the content of the 16-bit register and triggers the MCU interrupt. The MCU NOPs briefly before acting.

6) The MCU raises MCU!68000 high, which isolates the cartridge from the 68000 bus by tristating all the transceivers in both directions. Since D0 is pulled up by the cart, any word reads to cart space will have their LSB set (other bits indeterminate). Since I know that the lowest bit of $000007 will be zero (since this is the entry point vector in the header, it must be a multiple of two), the 68000 stub will continually read 1 in the LSB of $000006.w while isolated and 0 when the cart is non-isolated.

7) While isolated, the MCU reads game filenames, titles and sizes from the SD card (or whatever data it needs) and uses FLASH!WE, the cart address and data buses to write the retrieved data to a 32 Kbyte block within the lower 4MByte of the Flash. (While isolated from the 68000 bus, the Flash chip's !C_CE will be pulled low.)

8) When finished, the MCU sets up another rising edge interrupt on DETECTREGISTERCLK and lowers MCU!68000 to reconnect the cart to the 68000 buses.

9) The 68000 can now exit the busy loop.

10) The Mega Drive jumps back into the lower 4Mbyte of the cart Flash to run a menu program, with all the available games data available within that 32Kbyte block.

11) The user selects a game - this is encoded as a 16-bit value (the index of the game in the order retrieved from the directory listing, or some other numeric identifier).

12) A second stub is jumped to in RAM, and the selected game value is written to the !TIME address $A13000, then the Mega Drive NOPs for 0.5s, then continually reads $000006.w and loops continually while the LSB is set as before.

13) The write to the !TIME address $A13000 is decoded by the cart and both populates the content of the 16-bit register and triggers the MCU interrupt. The MCU NOPs briefly before acting.

14) The MCU raises MCU!68000 high again to isolate the cart.

15) The value written to the register is retrieved into the MCU using REGISTER!OE and the cart's data bus.

16) The MCU raises !BOOT/GAME to switch in the upper 4MByte of the Flash.

17) The MCU can now open the indicated game file from the SD card and write it to the upper 4MByte of Flash.

18) When done, the MCU can lower MCU!68000 to reconnect the cart to the 68000 buses. The MCU enters a low-power idle state and takes no further action. All of its pins are inputs except !BOOT/GAME which is high.

19) The 68000 is released from its busy loop when the cart buses are reconnected.

20) The Mega Drive cleans up any RAM/VRAM it needs to using its stub (in case certain software cares?), zeroes out itself as much as it can, then jumps to ($000004).l to boot the game present in the upper 4MByte of the Flash. From this point on, the cart is completely dumb ROM. Writes to !TIME will populate the register, but it will never be read.

Does that sound like a good approach?

--

I'd like a second opinion on my glue logic and transceiver usage since I've never done this before.

My signal names are (usually) prefixed by their source (68000 bus or MCU).

I'm using transceivers to split the 5V 68000 world from the 3.3V internal world. The two 16-bit transceivers on the left should be considered as one 32-bit transceiver for the 'address and signals bus'. I'm using the !C_CE B17, !AS B18, R/!W, !TIME and !VRES signals from the cartridge slot to detect chip enables, reads, writes, strobes and reset conditions. My understanding is that !C_CE is asserted on reads or writes to $000000 - $3FFFFF and !TIME is asserted on reads or writes to $A13000-$A130FF?

I'm using the 16-bit register because the MCU is way too slow to react to the 68000 quickly writing a word to the !TIME address space. With the register, I can store the value and use the rising edge of CLK to awaken the MCU, then it can isolate the cart and read the written register value at its own pace.

Reset logic:

FLASH!RST = 68000!VRES
MCU!RESET = 68000!VRES
The PICkit is also connected to this pin when I'm programming the MCU, but you should never program the PIC while the cart is within the MD anyway. I'm going to have it so that you apply an external 5V source to the cart through header pins when programming the PIC.

Address decoding logic:

FLASH!CE = 68000!C_CE (pulled low on isolate) The Flash should be selected on access to $000000-$3FFFFF, or always if the cart is isolated.
FLASH!OE_EXTERNAL = 68000!C_CE + 68000!AS + NOT(68000R/!W) This signal represents an !OE request from a 68000 request. This happens when !C_CE is low, !AS is low and R/!W is high. I shouldn't need !C_CE strictly, but I'm using this combination as an input below.
FLASH!OE = MCUFLASH!FORCEOE * FLASH!OE_EXTERNAL I want the Flash to output a value if the MCU is forcing it to, or if the 68000 signals ask it to.
REGISTER!WE = 68000!TIME + 68000!AS + 68000R/!W I'm going to have the register respond to any write in the $A130xx range, since that's simple. The register writes on the ascending edge of this signal, so it's also listed as REGISTERCLK.
MCUDETECTREGISTERCLK = REGISTERCLK On the rising edge of the register clock, the MCU awakes at the same time as the register is written.

Transceiver logic:

74ALVC164245 logic:
A bus = 3.3V
B bus = 5.0V
DIR L = 3.3V output <- 5V input (value into cart from 68000 - DATA: a write operation, ADDRESS: 68000 Ax enters cart address bus.)
DIR H = 3.3V input -> 5V output (value from cart into 68000 - DATA: a read operation, ADDRESS: cart address bus leaves onto 68000 Ax, do not allow this.)

ADDRESSTRANSCEIVERDIR = low Only valid direction is an address from the 5V port placed on 3.3V port if ADDRESSTRANSCEIVER!OE is low.
ADDRESSTRANSCEIVER!OE = MCU!68000 When MCU is in !RESET or if this pin has not been raised, the 68000 address appears on the 3.3V address bus.

DATATRANSCEIVERDIR = R/!W I'm surprised I don't have to invert this, the 68000's R/!W signals match the direction of the 74ALVC164245.
DATATRANSCEIVER!OE = MCU!68000 + (FLASH!OE_EXTERNAL * REGISTER!WE) I want to connect the data bus if isolation is not in effect and we're valid reading the Flash or valid writing the register. (Notice my FLASH!OE requires FLASH!CE instead of being independent of it to allow the combination to be used here.)

When the !OEs are low, the address or data buses will be floating, so I'm going to connect each pin to ground through 6k8 to prevent any unusual behaviour during isolation.

I'm also pulling up !AS, R/!W, !TIME and !VRES high whenever the cart is isolated, to disable the Flash and register ICs unless the MCU activates them itself.

MCU Outputs:

While the MCU is in the reset state, all its pins are tristated. My pull- resistors need to make this a good safe state for the cart to be in before the menu begin, and while the real game is running and the MCU is idle:
MCU!BOOT/GAME, low default, if low select the boot menu half of Flash, if high select the game half of Flash.
MCUFLASH!WE, high default, allows the MCU to program the Flash
MCU!68000, low default, if high the cartridge transceivers tristate the cart from the 68000 buses.
MCUFLASH!FORCEOE, high default, if low the MCU is reading the Flash (to verify a write)
MCUREGISTER!OE, high default, if low the MCU is reading the last value written to a !TIME address

MCU Inputs:
DETECTREGISTERCLK, a rising edge wakes the cart for either the 'ready to read games' state or the 'please play game REGISTER' state.
!RESET, standard reset.
The Flash indicates a busy state by toggling a Qx pin on consecutive reads during busy, so there's no busy pin to poll.

I haven't yet fully specified the SD card interface yet. I think I'm going to use the 4-wire SPI mode, with all the lines pulled to 3.3V through 3k3, and a 10R resistor on the +3.3V line to prevent high inrush current.

In summary:
1) Does my physical organisation make sense?
2) Does the sequence of events make sense, and is it safe?
3) Does my glue logic make sense?
4) What is the best way (cheapest/lowest parts/fastest) to implement the logic?

Please let me know what you think.

Datasheets:
Transceiver
Flash
Register
PIC MCU

Cheers!

Edit - I was following the 68000 timings in the book Microprocessor Systems Design by Clements, and didn't notice the 68000 R/!W signal isn't present on the cartridge port! I need to use !UDW and !LDW upper and lower data write strobes instead. So is it the case that a read is (potentially) taking place if neither !UDW and !LDW are asserted, and a write is taking place otherwise? I need R/!W in order to control the direction of the data bus transceiver and prevent contention.

So in my design I could add
DERIVED R/!W = !UDW * !LDW
and the rest of the semantics would be the same? I'd have to transceiver these and pull them up, etc.

Chilly Willy
Very interested
Posts: 2799
Joined: Fri Aug 17, 2007 9:33 pm

Re: Designing MD sdcard flashcart for fun, advice?

Post by Chilly Willy » Sun Oct 27, 2019 1:36 am

Writing the loaded game to flash every time will eventually make the flash go bad. One bad bit and potentially (depending on where the bad bit is) it becomes useless. That's why carts that load from SD load into ram, not flash. It would also be horrifically slow.

MrD
Interested
Posts: 21
Joined: Sun Jan 26, 2014 4:29 pm

Re: Designing MD sdcard flashcart for fun, advice?

Post by MrD » Sun Oct 27, 2019 1:40 am

Very true. :) I was hoping that I'd get at a few thousand goes out of my test cartridge first though!

My original plan was to use SRAM, but I couldn't find cheap 4 megabyte SRAM (as a x16 part or two x8 parts) in JLCPCB's parts list. I could have made it from 4 1Mbyte parts or something, but then I'd need 3-to-8 decoder as well and things would get more complicated. The cartridge needs some non-volatile storage to boot into before any PIC manipulations take place anyway - using a single Flash was an attempt to satisfy the need for a non-volatile boot area and the need for a 4 megabyte storage space with a single part.

I can reduce unnecessary erase cycles:
- On the game half by having a menu item to allow the user to load the currently 'installed' game without overwriting it.
- On the boot half by only loading the game list from SD and sorting it and writing to Flash when you specifically ask it to - if you have the same SD card in, with the same games in the same order then the numeric indexes are going to be the same and there's no reason to refresh the list. It'll go very weird if you have changed the SD card in the meantime, so don't do that. :D

Do you have any figures on how slow you think it would be? I've done some calculations with the datasheets of the flash and the speed of the PIC and the worst case is 30 seconds for 4 Megabytes, which isn't really so bad. There's not many games or demos that big.

Chilly Willy
Very interested
Posts: 2799
Joined: Fri Aug 17, 2007 9:33 pm

Re: Designing MD sdcard flashcart for fun, advice?

Post by Chilly Willy » Sun Oct 27, 2019 2:54 pm

Yeah, large SRAM are pricey. If you get a fast enough PSRAM, you can hide any refresh delay in the 68000 bus cycle, so many carts use that instead to keep the price down... or flat out use DRAM as it's even cheaper, and again hide the refresh in the 68000 cycle somewhere.

If you can push the flash to its fastest write times, you can write 4MB of that flash in 20 to 30 seconds. However, since you don't have ram other than in the PIC, you're going to have to write the data like 4KB at a time while reading the data off the SD card in-between block writes. That's assuming you'll have 4KB free to buffer the data. That will slow things down some. You will also need to verify each block, and possibly retry the erase/programming cycle. Since you can only erase sectors or the whole thing, any failure in programming the first time will mean rewriting the entire sector. And yes, that is something that commonly occurs when programming flash. In programming flash from a PC using a USB programmer, I've commonly burned 1 to 4MB in 1 to 8 minutes, depending on the size, and how many retries were needed to get a good burn.

As to how many writes you'll get, that depends highly on the quality of the supplier you use. Do NOT buy flash from ebay or similar places. Not unless you want pulls that are already bad or on their last few writes. Even then, remember that the max write cycles is an mean time between failures, and while most parts (brand new) will get that many cycles, some will get many more, and some will get a lot fewer. I've only had one flash get errors on me so far, but know people who got maybe a few dozen writes before a failure. It's not likely, but possible, and just something you have to deal with when using flash.

MrD
Interested
Posts: 21
Joined: Sun Jan 26, 2014 4:29 pm

Re: Designing MD sdcard flashcart for fun, advice?

Post by MrD » Sun Oct 27, 2019 2:58 pm

Thanks :) I hadn't considered that the Flash writes might not work first time. Manually reading back the results to make sure they're copied right will be a pain...

Apart from that though, does the glue logic make sense now I've accounted for combining !UDS and !LDS into a R/!W signal?

And what sort of components should I be looking at to implement it? I don't know the best type of thing to use to provide glue logic with surface mount bits

TmEE co.(TM)
Very interested
Posts: 2378
Joined: Tue Dec 05, 2006 1:37 pm
Location: Estonia, Rapla City
Contact:

Re: Designing MD sdcard flashcart for fun, advice?

Post by TmEE co.(TM) » Sun Oct 27, 2019 3:33 pm

If it is a proper NOR flash it'll take more than 100k writes before the flash fails. Overall the idea looks doable but I'm not sure if you can cleanly supply NOPs to the 68K and later get it execute something more useful. If I were you I'd pull !MRES low (this signal you can drive yourself, but only in open-drain fashion or you'll possibly bork power on reset) while flash operations are done and once they done, the machine starts as if it was first powered on.
Mida sa loed ? Nagunii aru ei saa ;)
http://www.tmeeco.eu
Files of all broken links and images of mine are found here : http://www.tmeeco.eu/FileDen

MrD
Interested
Posts: 21
Joined: Sun Jan 26, 2014 4:29 pm

Re: Designing MD sdcard flashcart for fun, advice?

Post by MrD » Sun Oct 27, 2019 4:07 pm

Thank you for your time TmEE!

What do you mean by cleanly supply the NOPs? That doesn't seem to apply in my method - I think I didn't explain it well :)

After a write to a !TIME address takes place, the 68000 will jump to code in RAM, where it NOP delays first, then displays an animation and polls move.w $000006's least significant bit to see whether the cart is busy or available.

The short NOP delay (1microsecond e.g.?) is needed here since the PIC will take a little while to wake from interrupt and take control of the bus (before it then reads the 16bit register to see what it's been told to do). Until the PIC has set MCU!68000 high, the 68000's poll will indicate the cart buses are not isolated yet. Since I know that some delay is necessary, the NOPs are there to start polling only after I know the PIC will have definitely isolated the cart.

Chilly Willy
Very interested
Posts: 2799
Joined: Fri Aug 17, 2007 9:33 pm

Re: Designing MD sdcard flashcart for fun, advice?

Post by Chilly Willy » Mon Oct 28, 2019 3:12 pm

Well, it seems a bit overly complicated for what you want, but it should work. It'll be interesting to see how it comes along.

MrD
Interested
Posts: 21
Joined: Sun Jan 26, 2014 4:29 pm

Re: Designing MD sdcard flashcart for fun, advice?

Post by MrD » Wed Nov 20, 2019 8:38 am

I've been fiddling with all of this again, and as is the way when you finish something, you discover something that lets you simplify it, possibly.

All of the documents I can find for the 68000 say that its VIH minimum is 2.0V, which means that I ought to be able to interface it with the output of a well-behaved 3.3V LVC family device. Am I reading it right?

That means I can combine the functions of the transceiver and the register into a single SN74LVCH16652 transceiver-with-register. This device doesn't have separate 5V and 3.3V output buses like the 164245 does, though. It's 3.3V on both sides, with 5V tolerant inputs.

I'm trying to think of anything that the data bus at the cartridge port would be connected to where a 3.3V high logic signal from the cart would be too low. Would it mess with DMA operations? Or can I have 3.3V logic high just fine?

Post Reply