Original Post

If one wants to play VB games on their flash cart, they need to pad the ROM to some multiple of 2MB IIRC. I updated the build system on my VBdemo repo, and I’ve been looking at creating my own tool for doing the padding/flashing myself (from the command-line in python).

I understand that it’s some sort of address decoding issue from VB CPU’s point of view, but what are the “rules” to ensure that the reset vector and the remaining code ends up in the correct place?

What address does the CPU see and how does it translate to what address is presented on the bus of the ROM? Does the ROM just ignore higher bits of the bus?

2 Replies

cr1901 wrote:
If one wants to play VB games on their flash cart, they need to pad the ROM to some multiple of 2MB IIRC.

The ROM must be padded to the size of the flash memory. No more, no less.

I understand that it’s some sort of address decoding issue from VB CPU’s point of view, but what are the “rules” to ensure that the reset vector and the remaining code ends up in the correct place?

The ROM must decode addresses so that the reset vector (as well as the others if you use interrupts) is at FFFFFFF0. It doesn’t matter from that point on because your code can then jump to any address. The simplest case is if you have a 2^n-byte ROM; it can just decode the lower n bits.

What address does the CPU see and how does it translate to what address is presented on the bus of the ROM? Does the ROM just ignore higher bits of the bus?

Exactly. The CPU always starts execution at FFFFFFF0. The VB only decodes the lower 27 bits, giving 07FFFFF0. This is why the 07xxxxxx range is reserved for cartridge ROM. It’s up to the cartridge to decode the remaining 24 bits. A 2 MB ROM would normally only decode the lower 21 bits, so FFFFFFF0 is at offset 1FFFF0 in such a ROM.

Theoretically, it could also, for example, decode the lower 20 bits and bit 23, but then the two halves would only be contiguous from 077FFFFF to 078FFFFF.

Having the upper bits set is somewhat confusing, in my opinion, so I prefer a ROM to “start” at 07000000, even though it can (in the case of 2 MB) start at FFE00000. Faceball, for example, uses such addresses, but most (if not all) homebrews start at 07000000.

The ROM does not even have to be a power of 2 in size, though at least Mednafen requires it to be. A 3 MB ROM would, for example, be composed of one 2 MB chip and one 1 MB chip, use bit 21 to select between the two chips and the lower 21 bits to select an offset within the chip, with 0 being the 2 MB chip so that all 3 MB would be contiguous in the range from 07000000 to 072FFFFF.

I hope this answers your questions and that I didn’t make a mistake somewhere.

Flash Boy is responsible for the ROM padding business: its internal 2 MiB flash memory necessitates having ROM data written in such a way that it won’t malfunction when running on the hardware. Having said that, it isn’t strictly necessary, but the flashing software requires it last I checked.

HorvatM’s post is accurate with regards to CPU to cartridge address translations. What you need to know is this:

• Virtual Boy has a 27-bit bus. The upper 5 bits are discarded for all memory accesses. The initial state of the CPU on reset places its program counter at 0xFFFFFFF0, which gets masked off to produce the effective bus address of 0x07FFFFF0.
• Addresses in the 0x07—— range are mapped to cartridge ROM. This gives 24 bits of addresses for program data. Similarly to the system bus, any cartridge with less than 16 MiB of ROM typically reduces size by eliminating upper bits, hence the power-of-two convention.
• Flash Boy and Flash Boy Plus have 2 MiB of flash memory, which is 21 bits. Therefore, from the CPU’s perspective, everything in the cartridge ROM memory range produces mirrors of 0x07000000 through 0x071FFFFF.

Padding of ROMs comes into play only when flashing ROMs that are less than 2 MiB in size to a Flash Boy. The end of the flash memory is required to contain the ROM header, which contains the code to execute on reset. However, most new software gets compiled in such a way that the program’s origin is at the beginning of the cartridge ROM space. Since you can’t write a ROM to both the beginning and the end of the FlashBoy memory chip, the ROM is padded to produce a new ROM with all the data aligned.

… or that’s the idea. Thing is, you can write it to both the beginning and the end: you just need to write multiple copies. Masking of higher bits for smaller ROMs can be simulated by repeating the ROM until all 2 MiB are filled. While the memory being accessed isn’t literally the same inside the cartridge, the bytes being returned certainly are, so it’s as though the ROM chip has only the number of bits required by the ROM data.

 

Write a reply

You must be logged in to reply to this topic.