Primary slots and secondary slots

ページ 1/2
| 2

By sc3000survivors

Rookie (28)

sc3000survivors さんの画像

31-10-2010, 17:39

Hi guys... I was working around slots handling of my AS3 emulator and I'm finding some difficulties in understanding the Secondary slots handling. As I said I'm new to MSX, and what I can't understand is how it Handle the whole rom ( 128K and more ).

I've understood that it is treated as a sequence of 16k pages, but i can't understand the order, and the associatin with the 0xFFFF memory register to select them.

I've deepely googled it, but every doc I've found don't explain how the system interprets the 128k/256K/... block of pages...

I understood the way it build the CPU memory space by selecting primary slot pages. but I'm confused when the stystem must select more pages from a ( for example ) 128 Kb rom...

Is there some doc you know that explains how the system associates pages to the 0xFFFF register ?
Thank you very much!


By hap

Paragon (2041)

hap さんの画像

31-10-2010, 19:57

I assume you want to get games like Gradius (128KB ROM) working? You're zooming in on the wrong hardware details then. The 'items' you'd have to emulate are mapper chips inside game cartridges. This should get you started then:

By marlon-B

Expert (88)

marlon-B さんの画像

31-10-2010, 23:36

you're mixing up some issues:

the value in &HFFFF determine the subslot selections.

every primary slot in the msx can be expanded meaning have 4 subslots.

slot 0 ->> 0-0 | 0-1 | 0-2 | 0-3
slot 1 ->> 1-0 | 1-1 | 1-2 | 1-3
slot 2 ->> 2-0 | 2-1 | 2-2 | 2-3
slot 3 ->> 3-0 | 3-1 | 3-2 | 3-3

the first digit (primary slot selection) is determined by value in I/O port &HA8
and the second digit (subslot selection) is determined by (written-)value in &HFFFF (I say written-value because reading &HFFFF returns complement of written value))

the value written to port &HA8 and address &HFFFF is constructed as follows:

bits 1-0: control slot selection for address-space &H0000-&H3FFF
bits 3-2: control slot selection for address-space &H4000-&H7FFF
bits 5-4: control slot selection for address-space &H8000-&HBFFF
bits 7-6: control slot selection for address-space &HC000-&HFFFF

and that's all folks !!

By sc3000survivors

Rookie (28)

sc3000survivors さんの画像

01-11-2010, 12:00

Thank you for your help,
so... please, forgive me for "bothering" you but this is really interesting, and I would like to go deeper into it Smile
Well, so now i know that every cartridge has its own "way" to give data to the bus... ( rom mapper )
ok, let's summarize... I think that can be useful.

The main memory is used by Z80 goes from 0 to 64k... this space ( z80 memory space ) is divided in 4 pages of 16k...
these pages are composed according to the port mapped to 0xA8... and the byte in this port tells where to find the 16k blok to use as a memory page.

The system has 4 slots, or 64k memory areas... they can be ROM or RAM... I've seen on docs around:

            | S0  S1  S2  S3  
C000-FFFF   |P3 |P3 |P3 |P3 |	P
            |---|---|---|---|	A
8000-BFFF   |P2 |P2 |P2 |P2 |	G
            |---|---|---|---|	E
4000-7FFF   |P1 |P1 |P1 |P1 |	S
0000-3fff   |P0 |P0 |P0 |P0 |  16k

Usually in slot 0 the system can find the BIOS, in slots 1 and 2 the system can find cartridges, and in the third the system can find the RAM.
Wht I've learned is that according to the 0xA8 port, the system can address the Z80 to read or write on different slots... so for example:
A8: 11 01 01 00 means p3: slot3, p2: slot 1, p1: slot 1, p0: slot 0;
this means that the system knows that from 0 to 3FFF finds data in slot 0 ( which is bios ), and from 4000 to BFFF can find cartridge in slot 1, and from C000 to FFFF it finds Ram

So to implement this I used 4 arrays of 64k which are slots, and at first, in memory init routine what I'm actually doing is:
1) load BIOS and ROM in separate arrays..
2) init Memory by
- putting BIOS from 0 to 8000 in Slot 0 array
- putting ROM from 4000 to BFFF in Slot 1 array
- leave Slots 2 and 3 free

Then when emulation starts, within memory access routines, I use some selector according to the A98 register, that writes or reads value im each different slots pagers according to the A8 port.

This works for max 32k cartridges... because the emulator copies rom into 4000-BFFF range...
But for 64k cart things are wrong. The trick I've done, tha for some titles works and thers not, is that if the ROM is more than 32 and the init address inside the header of the rom start from page 0, I put the rom starting from 0 instead of 4000.
Of course when the rom is 128k I cannot manage it anymore ( with this method ) so I must understand where and how the system can retrieve data form 128k wide range, by only accessing for example the memory range from 4000 to BFFF.

This is why I am confused if when carts are more than 32k I need to subdivide Primary slots. And when this happens how I can threat the ROM file.
Does it is read as an array of 16k blocks? But if this happens, means that the rom of 64k fit a secondary slot of 64k, and to access it I need to readdress the z80 to this array ?

for <=32 k cartridges ok Smile
for >32k the hell Wink

To go out from the hell I probably need to implement each different rom mapper, which can interface betreen the z80 memory space and the main rom array, not the slots.
Let's take an example:

Konami cartridges that do not have a SCC: Penguin Adventure is 128kb. 

"Since the size of the mapper is 8Kb, the memory banks are: 
	Bank 1: 4000h - 5FFFh
	Bank 2: 6000h - 7FFFh
	Bank 3: 8000h - 9FFFh
	Bank 4: A000h - BFFFh
And the address to change banks: 
	Bank 1: <none>
	Bank 2: 6000h - 7FFFh (6000h used)
	Bank 3: 8000h - 9FFFh (8000h used)
	Bank 4: A000h - BFFFh (A000h used)"

Ok pages in the z80 space are: 1 and 2, from 4000 to bfff, but when accessing to this range the rom mapper can select different 8k pages of the 128k rom ,right ?
I can't understand how Sad

By marlon-B

Expert (88)

marlon-B さんの画像

01-11-2010, 14:45

you have to see it like this:

the primary port selector(A8) and subslot selector (FFFF) just open up a "window"
to a certain rom. the size of the rom which you can see really does not matter.
what you see thru this windows is determined by the mappercircuit of this rom.

you have many different rom-mapper circuits but most common are 16k mappers and 8k mappers

the way a mapper circuit works is very simple:

because writing to roms cannot be done. this writing mechanism is used to select different
parts of the rom to display thru the window.

the way it does this is like follows:

say you have rom with 128k and it has a 8k mapper circuit.
the 8k means you have 128k/8k=16 pages of 8k you can select.
let say this rom is located in your first cartridge slot.
so your slot selection is 1-0 for address range 4000-7fff and 8000-bfff
with this you open up your "window" to see the rom.
every read or write to this address range now affects the rom you opened a window to.

let say you write the value 8 to 4000.
this means you wish to see the part of the rom wich starts at 8*8k=&H10000
at the (window) address range &h4000-&h5fff.

this value 8 is also stored in a lookup table so each time a read occurs from 4000-5fff
it really reads it from location &H10000-&H11FFF:

bank[0]=8 (4000-5fff)
bank[1]=X (6000-7fff)
bank[2]=x (8000-9fff)
bank[3]=x (a000-bfff)

so to implement this just do something like this:

declare an array msxslot[4][4][4] of which every element can point to some romstructure.

romstruc {
   mapstruc mapper;
   byte romdata[128*1024];

  int banksize;//for 8k is 2048bytes
  int banks[4];

so to read the correct data for the rom example above you only have to do something like this:
void main() {
  byte value;//is gonna hold the romvalue you are reading
  word address=0x4000;//address you want to read from
  int banknr=(address & 0xC000)>>14;//banknr is now a number between 0-3 where 0=0000-3FFF ,1=4000-7fff etc..

  myrom=msxslot[banknr][pri_slot][sub_slot];//so this reads msxslot[1][1][0] and gets pointer to a rom structure stored at this location

byte readrom(romstruc* myrom,word address) {
  byte* romaddr;
  word newaddress=address & 0x1FFF;
  int banknr=((address & 0x8000)>>14)|((address & 0x2000)>>13);//calculate lookup-mappertable index which can be 0 to 3
  return myrom->romdata[(myrom->mapper->bank[banknr]*myrom->mapper->banksize)+newaddress];//return value

hope this clears it up for you !Cool

By RetroTechie

Paragon (1563)

RetroTechie さんの画像

01-11-2010, 18:39

Hello sc3000survivors, you made a pretty good summary for how primary slots work. I'll give it a shot to complete the picture.

A Z80 has 64KB address space, the MSX system adds up to 3 'layers of re-direction' to map Z80 address to final memory location:

1) Upper address bits A14 and A15 (the 16K 'page') together with the corresponding bits in I/O register A8h determine which primary slot (0-3) is accessed. This expands Z80's 64K into 4x 64K ranges. But for each 16K page, only 1 slot is 'visible' at a time, programmers / ROM software must write to A8h to change which primary slot is visible in which page.
2) If that primary slot is expanded, the corresponding bits of last value written to FFFFh of that slot determine which sub-slot (also 0 to 3) is accessed. This 're-direction layer' is optional, each primary slot can be expanded or not, independent from other primary slots. Memory location FFFFh is used to detect this: unexpanded slot -> normal memory location / empty, expanded slot -> reads back the inverse of what you write. So this mechanism can expand a 64KB primary slot into 4x 64KB subslots.
3) Within each slot, there can be various mapper mechanisms used to put more than 64KB in that slot (primary or expanded, doesn't matter for how this mapper mechanism works). And indeed you'd have to implement each individual ROM or RAM mapper to support this in an emulator. Usually there's a set of 4x 8-bit registers, upper address bits A13/A14/A15 (for mappers that switch 8KB blocks) or A14/A15 (for mappers that switch 16KB blocks) select one of those, and its contents form the upper address bits, lower address bits determine location within selected block. For ROM mappers these registers are written through specific memory area's in the ROM mapper slot, for a RAM memory mapper (64KB or more) these registers are written through I/O addresses FC~FFh (and shared for all RAM memory mappers). Note that for some ROMs it's important that get default (power-on) settings of these registers correct.

Complicated indeed, and one of the reasons MSX inserts a wait cycle into each Z80 instruction fetch (M1). As for implementation:

1) Every MSX has it, this A8h I/O register (8 bits) is part of an Intel 8255 (or compatible, integrated in other part).
2) Optional for each primary slot independent. I suppose it would depend on preferences of the emulator writer, emulated MSX model, or user settings. Needs another 8-bits register for each expanded slot.
3) Totally depends on what's in a slot. Probably depending on user settings and/or some sort of 'autodetection' of ROM type.

There aren't much rules about MSX memory layout other than BIOS ROM (32KB) should be in slot 0 (0000-7FFFh) or slot 0-0 if slot 0 happens to be expanded. Most MSX'es have 1 expanded slot, a common configuration is slots 0 (internal), 1 (=cartridgeslot 1), 2 (=cartridgeslot 2), 3-0, 3-1, 3-2 and 3-3 (internal). With RAM in one of the 3-x subslots (not important which). But there exist many configurations.

If you're still trying to figure this out, I suggest you forget about subslots for now, put plain 64KB RAM in slot 3, and focus on implementing 2 or 3 of the most common ROM mappers. That way you can emulate the bulk of MSX1 software. Then implement subslots, and put MSX2 subROM (and 2+ ROMs?) in a 3-x slot. Which allows you to emulate ROM-based MSX2 software. Then have a look at disk systems and RAM memory mappers to support disk-based MSX software.

By sc3000survivors

Rookie (28)

sc3000survivors さんの画像

01-11-2010, 19:41

Thank you guys for all of this information!
I know I am confused, and some order is needed Smile

I will put together your directions, and try to summarize...

The problem was also that I didn't understand is that I can "write" to an address in rom, and that writing action is used to configure the mapper right ? I missed that! With SC-3000 I'm used to forbidden a write action to the ROM space, this because SG-1000 games doesn't go over 40 kb.

I will change my strucure of arrays, unfortunately in Action Script 3 I haven't a struct type, but I think to solve the problem anyway.

I'll try to implement a rom mapper but I need to start a "detecting" function to establish in what way to drive the rom. I will search for a 64k or 128k title that uses a rom mapper andtry to implement it.
Maybe Gradius, which has a Konami4 Rom mapper...

Thank you very much! I will update you soon!

By sc3000survivors

Rookie (28)

sc3000survivors さんの画像

02-11-2010, 23:43

well, I must say that I should redesign a little the rom system, but actually, thanks to your suggestion and links, I could, or i think to have done, implement the Konami4 Rom Mapper.

These games works with the paging system:
// _gameRom = "F1 Spirit (1987) (Konami) (J)";// 128kb, Konami 8k
// _gameRom = "A1 Spirit (1987) (Konami) (J)"; // 128kb, Konami 8k
// _gameRom = "King's Valley 2 (1988) (Konami) (J)"; // 128kb, Konami 8k
// _gameRom = "Konami's Game Master 2 (1987) (Konami) (J)"; // 128kb, Konami 8k
// _gameRom = "Parodius (1988) (Konami) (J)"; // 128kb, Konami 8k
// _gameRom = "Q-bert (1986) (Konami) (J)"; // 32kb, Konami 8k *
// _gameRom = "Shalom (1987) (Konami) (J)"; // 256kb, Konami 8k
// _gameRom = "Super Cobra (1983) (Konami) (J)"; // 8kb, Konami 8k *
// _gameRom = "Video Hustler (1984) (Konami) (J)"; // 8kb, Konami 8k *
// _gameRom = "Yume Tairiku Adventure (1986) (Konami) (J)"; // 128kb, Konami 8k

* titles that actually shouldn't need a Rom mapper due to their size less than or equal to 32Kb

Now I need to think about some way to detect how to read/write to the rom, if the rom has a Rom Mapper or if it's needed one, because I think that in emulation something can be byassed with some trick.

I admit that it's very exciting to see a 128kb game running... And I think that some of MSX games brings TMS9928 to a really good multicolor graphic. This make me also think that SEGA could do better on SG-1000 games!!! Evil I'ts a pity.

However, I still have so much confusion in all this, so now that this Rom mapper seems to work, my question is...
for games of 8k to 32k a rom mapper is required ? I mean, the 8k titles above works with the rom mapper activated, but i think they don't need it.
A 64k games can't be put on the entire slot rght ? this because the first page would conflict with the bios page on slot 0 page 0, right ?
So if a rom Mapper is not needed fot <= 32k I can emulate it for >= 64k titles.

By RetroTechie

Paragon (1563)

RetroTechie さんの画像

03-11-2010, 05:28

I can't remember I ever saw a <=32KB game cartridge that had more than a ROM, and perhaps a simple logic chip inside. Read: it's fairly safe to assume that ROMs up to (& including) 32KB simply take up a continuous memory area. Usually starting at 4000h or 8000h (using BIOS in page 0 and RAM in page 2 and/or 3), but there are a few tricky ones - I can remember a ROM that had a start address in page 0, where IIRC the MSX BIOS doesn't look for "AB" identifier bytes. The trick: it was mirrored across all pages - the BIOS would detect it in page 1 or 2, but then call the start address in page 0 of same slot... oO

These work in a ROM mapper because that mapper's initial state looks the same as a flat 8/16/32KB ROM. Although some 8/16/32KB ROMs may try to write to themselves, as a kind of copy-protection check (original = no effect = OK, illegal copy in RAM = writable = some change in behavior). And test location(s) used may happen to fall within the 'block switch areas' for a ROM mapper. So simplest assumption: maximum 32KB -> no ROM mapper of any kind, look at size + init addresses to decide where to put 'm.

ROMs of 128KB & bigger always use some kind of mapper, and may work in several mapper types (so if you find a mapper type that works, it doesn't necessarily mean that's the mapper type used for original ROM). How to detect?

  • Use a checksum database / some other sort of 'fingerprinting' to recognise a number of known ROMs - not very good method since it only works for ROMs that are in your catalogue, and there's always (many!) ROMs that you don't know about.
  • Look for common block-switch instructions a la "LD (6000h),A" byte patterns, count/sort the findings, and try to conclude from results what ROM mapper it's using. Can work pretty good if detection routine isn't too dumb... Wink
  • Ask user / choose when selecting ROM to insert. Simple/easy but not very user friendly.
  • Any combination of above (for example use autodetect result to set default for user choice). And users may sometimes want to force a specific mapper type.

As for ROMs between 32K and 128K - dunno... go find some (they're rare), load in debugger & see what they do... Hannibal

By sc3000survivors

Rookie (28)

sc3000survivors さんの画像

03-11-2010, 17:57

Thank you for suggestions, I will try to create a "detection" on titles, but now I've put a variable passed by post on URL to FLASH Player.
Just to inform what mapper to use...

Now you can see some 128k games online Smile

And added a scanline visual effect on Screen. Smile

Can you test the speed on your PC ? Usually these visual fx slow down overall speed...

I'm having so much fun!!!! Thank to everybody for help!

By sc3000survivors

Rookie (28)

sc3000survivors さんの画像

16-11-2010, 09:30

Hi!, first of all thank you for helping me in figuring out how SLOTS and mappers work.
Actually I've reached the 91% of working titles, almost 539 of the 590 I knows... but I think that there are some still to fix even if they may appear ok.
I still have to implement the use ov SRAM Sad Which I'm having difficulties in understanding how to handle it...
Maybe some of that uses secondary slots, so now I need to go one step ahead Tongue

Do you have any advice or sugestion for SRAM handling ? Smile

Soon I will update the site by putting a select box to let you choose a title.

ページ 1/2
| 2