Chris
|
Memory Questions
Posted: Sun Mar 05, 2000 5:19 pm
|
From what I've read so far, most 8-bit processors have a
Program Counter that is 16-bit and can access up to
64K of memory. I kept hearing a little magical word
called Banks and so I looked it up and it relates to
Memory Bank Switching. The SMS uses 16K banks, right?
How does Bank Switching work? Is this a process
that's done internally by the processor or is it
a system-related process? If so, how exactly does
it work? Does the system or processor re-align
the PC to a new section of memory? I'm confused.
Chris :o)
|
Eric
|
Posted: Sun Mar 05, 2000 9:04 pm
|
Quote > From what I've read so far, most 8-bit processors have a
> Program Counter that is 16-bit and can access up to
> 64K of memory. I kept hearing a little magical word
> called Banks and so I looked it up and it relates to
> Memory Bank Switching.
This is also called "paging".
Quote > The SMS uses 16K banks, right?
Yes.
Quote > How does Bank Switching work?
Let's define a few terms first:
Bank, or Page: this is the actual section of memory that can be relocated. On the SMS all pages are 16Kbytes. Only ROM and Battery back-up RAM is paged on the SMS. You will notice that every SMS/GG ROM image is a multiple of 16Kbytes in size.
Frame: This is the group of addresses into which banks or pages can be mapped. On the SMS there are 3 frames: Frame 0 is from address 0x0000 to 0x3FFF. Frame 1 is from address 0x4000 to 0x7FFF. Frame 2 is from address 0x8000 to 0xBFFF. Each of these frames can have a different page of memory mapped into them. Basically what this means is that when the processor accesses address 0x2000 in frame 0 the data there can be different depending on which PAGE is currently mapped to Frame 0.
Bank Switching (or Paging) is how the SMS/GG can have 4-Megabit (512KByte) games, even though the Z80 can only access 64KBytes. Not all of the 512KBytes is needed at once, so data that isn't in use is not mapped into addressable memory. Only those pages that are needed are mapped. (This technique is very popular and is not SMS/GG specific. NES uses paging too.)
The actual method used to page memory is different depending on the system. In the SMS, a program writes the number of the "Bank" or "Page" it needs into special registers. These registers are located at 0xFFFD, 0xFFFE, and 0xFFFF in memory (they are memory mapped registers). Writing to 0xFFFD will change the memory bank that is mapped to Frame 0. Similarly, writing to 0xFFFE and 0xFFFF changes the page in frames 1 and 2, respectively.
Quote > Is this a process
> that's done internally by the processor or is it
> a system-related process?
It is completely invisible to the processor. Bank-switching is handled by the cartridge. The cartridge intercepts WRITES to the registers at 0xFFFD, 0xFFFE, and 0xFFFF and performs the bank-switching internally. The next time the processor accesses memory in a frame, the cartridge provides data from the new memory page.
Quote > If so, how exactly does
> it work?
See above.
Quote > Does the system or processor re-align
> the PC to a new section of memory?
No. Bank switching is invisible to the processor.
For more information, see my document about the SMSARCH available in S8-Dev's Technical Informations section.
Good luck.
Eric Quinn
|
Chris
|
Ohh, that makes sense!
Posted: Mon Mar 06, 2000 12:34 am
|
This all made sense when you said invisible to the
processor. I think I see how this process works!
It's alomst like taking a slide from a microscope
and moving another one into the microscope. You
can have as many slides as you need. And like
you said, this is how you have 512K SMS and
1200K NES Games. This bank switching is almost
like the Segment and Offset method that the
CPUs of today use. Sure, the PC can access
4 Gigs worth of program code at one time but
you can re-align the memory so it has access
up to (whateversize * 4Gigs).
Now, here's another question. Since the SMS can
access up to 64K of memory at once, why didn't
they create 64K memory banks? It seems to make
more sense to me, instead of using 16K here and
16K there. Is it the way they designed ROMs
back then? Like each ROM chip or cell could
only store 16K of data?
Oh, and if I wanted to emulate this. I can keep
my same memory allocations as before except I
manually replace what is contained in that allocated
memory? For instance...
char *bank;
bank = (BYTE *) malloc(0x4000);
If I need to use that bank, I use PC as the pointer...
whatever = bank[CPU.PC];
And If I need to perform a bank switch, I simply
swap out the memory, right?
bank = MemoryCopy(0x0000,0x3FFF);
The CPU and program variables 'n data have no idea
what as gone on, right?
Chris :o)
|
Eric
|
Re: Ohh, that makes sense!
Posted: Mon Mar 06, 2000 1:23 am
|
Quote > Now, here's another question. Since the SMS can
> access up to 64K of memory at once, why didn't
> they create 64K memory banks? It seems to make
> more sense to me, instead of using 16K here and
> 16K there. Is it the way they designed ROMs
> back then? Like each ROM chip or cell could
> only store 16K of data?
The SMS only uses bank-switching for ROM. There still needs to be some address space left over to cover RAM (so they couldn't use ALL 64KBytes for paging). The designers of the SMS felt that 48KBytes (3 pages) of accessible ROM was adequate. The remaining 16KBytes of addressable space is for RAM and the paging registers. (Remember, though, only 8KBytes of RAM exists: it is mirrored twice (minus 4 bytes for paging and battery back-up registers) to fit into the 16KBytes area at addresses 0xC000 to 0xFFFF).
I don't believe the 16KByte value is a result of any restriction due to ROM design. I think it was simply based off the 64KByte limit of the Z80 and the amount of RAM the SMS needed.
Quote > Oh, and if I wanted to emulate this. I can keep
> my same memory allocations as before except I
> manually replace what is contained in that allocated
> memory? For instance...
>
> char *bank;
> bank = (BYTE *) malloc(0x4000);
>
> If I need to use that bank, I use PC as the pointer...
>
> whatever = bank[CPU.PC];
>
> And If I need to perform a bank switch, I simply
> swap out the memory, right?
>
> bank = MemoryCopy(0x0000,0x3FFF);
>
> The CPU and program variables 'n data have no idea
> what as gone on, right?
(I think it'll be easier for me just to explain how bank-switching is typically handled in emulators:)
The easiest way to handle bank-switching is with pointers to each ROM page.
First load the entire ROM into memory. Then, since there are four frames in the SMS (Frames 0,1, and 2 are ROM, Frame 3 is RAM and paging registers) create a 4-element array of BYTE pointers. Initialize the first three pointers to point to the first three pages of your ROM:
#define PAGESIZE (0x4000) /*16KByte page size for SMS pages*/
BYTE RAMArray[8*1024]; /*8KBytes for RAM*/
BYTE ROMArray[512*1024]; /*512KBytes*/
BYTE* Frames[4];
/*Load ROM from file*/
ReadRomFromFile(FileName, ROMArray);
Frame[0] = &ROMArray[0];
Frame[1]= &ROMArray[PAGESIZE*1];
Frame[2]= &ROMArray[PAGESIZE*2];
Frame[3]= RAMArray; /* Not quite, still need to handle mirror of RAM. This detail is not important for this discussion*/
Now, to read from memory you take the address (whether it's PC, BC, DE, HL, IX, IY, SP, or an immediate 16-bit value) and get the frame number from the top two bits of the address. The offset into the page is the remaining 14 bits.
For example:
FrameNumber = Address >> 14; /* shift address 14 to left so only top two bits remain*/
Offset = Address & 0x3FFF; /* mask off the bottom 14 bits*/
Data = *(Frame[FrameNumber] + Offset);
Whenever a value is written to a bank-switch register (address 0xFFFD through 0xFFFF) you simply change the value in the Frame array:
void BankSwitch(int FrameNumber, int NewPage)
{
assert(NewPage < TotalRomPage); /* Double-check that new page actually exists in the ROM*/
Frame[FrameNumber] = &ROMArray + PAGESIZE*NewPage; /* Let Frame[FrameNumber] point to start of ROMArray plus the offset of the beginning of the new page.*/
};
Please understand there's a lot of details I've glossed over, but hopefully this is enough for you to get an idea of a typical way paging is handled by emulators.
Another method is to simply allocate 64Kbytes of space, and use memcopy to move 16Kbyte pages from ROM area to your addressable area when bank-switching. This reduces the amount of time it takes to decode each memory access, but can result in long delays whenever a bank-switch occurs. At one point someone mentioned they believed bankswitching occurs around 8 times per frame (400 to 480 times a second). If this is true, simply copying pages will result in poor emulator performance. (Personally, though, I believe this number to be greatly overestimated. I don't imagine bank-switching occurs more frequently than every few seconds and even as infrequently as every few mintues.)
I hope this answers some the questions you had above.
Good luck.
Eric Quinn
|