Working with CPU cycles in Gameboy Advance

cpugame developmentprocess

I am working on an GBA emulator and stuck at implementing CPU cycles.
I just know the basic knowledge about it, each instruction of ARM and
THUMB mode as each different set of cycles for each instructions.
Currently I am simply saying every ARM instructions cost 4 cycles and
THUMB instructions cost 2 cycles. But how do you implement it like the
CPU documentation says? Does instruction cycles vary depending on which
section of the memory it's currently accessing to?
http://nocash.emubase.de/gbatek.htm#cpuinstructioncycletimes
According to the above specification, it says different memory areas have
different waitstates but I don't know what it exactly mean. Furthermore,
what are Non-sequential cycle, Sequential cycle, Internal Cycle, Coprocessor Cycle for?
I saw in some GBA source code that they are using PC to figure out how many cycles each
instruction takes to complete, but how are they doing it?

Best Answer

This is only a partial response, so it may be disallowed:

Currently I am simply saying every ARM instructions cost 4 cycles and THUMB instructions cost 2 cycles.

Actually, if I'm remembering ARM correctly, what's actually happening is that, in a single memory cycle, you can either fetch a single 32-bit ARM instruction, or two 16-bit THUMB instructions. Execution time is, of course, instruction-dependent.

Does instruction cycles vary depending on which section of the memory it's currently accessing to? http://nocash.emubase.de/gbatek.htm#cpuinstructioncycletimes According to the above specification, it says different memory areas have different waitstates but I don't know what it exactly mean.

Different regions of memory may have more data clients than just the CPU. This is particularly true in graphics/video memory where pixels need to be pulled out of RAM to send off to the display. Unless you use faster (read: more expensive) memory, the CPU and graphics hardware will have to take turns accessing RAM. Thus, depending on how many other RAM clients there are, it may take several cycles before the CPU's turn at RAM arrives.

It may not even be this noble -- the manufacturer may have simply decided that they could get away with slower (read: cheaper) RAM for most of program and data space, and used a smaller block of fast memory only for those things that absolutely needed it.

Furthermore, what are Non-sequential cycle, Sequential cycle, Internal Cycle, Coprocessor Cycle for?

Sequential versus non-sequential refers to reading memory locations in order versus out-of-order. RAM is arranged as a two-dimensional array of memory cells indexed by row and column address. If you access memory locations in ascending address order (e.g. 0, 1, 2, 3, 4, 5, etc.), then all you need to change (most of the time) is the column address, and each successive read can be satisfied more quickly than if you accessed addresses non-sequentially. Judging from the doc you linked to, it looks like you get a CAS increment for free, but a full RAS+CAS costs an extra cycle.

Internal Cycle means the CPU is going, "Wow, this is complicated; gimme some extra time to figure this out." (The MUL instructions are sharp examples of this.)

Coprocessor Cycle refers to the time required to talk to an ARM coprocessor. I don't know what, if any, ARM coprocessors are in the GBA.

As for implementation: That doesn't lend itself to a single answer. If it were me, I'd model RAM access times independently from instruction execution times. When the CPU reads/writes memory, compare the memory address accessed with the previous memory address the CPU accessed. If they're adjacent (M(current) == M(previous) + 4), then it's free; otherwise add a one-cycle penalty. Then add the delays imposed by the memory region you're accessing.

Related Topic