Konami VRC4 and the iNES Mess
-
MottZilla
- Posts: 2837
- Joined: Wed Dec 06, 2006 8:18 pm
Konami VRC4 and the iNES Mess
So I thought it would be nice to add Konami VRC4 support to my emulator. I understand the different address lines being used differently in different variants.
But what I don't understand is when variants share the same number, and how you are supposed to know which address lines to use. For example mapper 21:
VRC4A uses A1 & A2.
VRC4C uses A6 & A7.
How am I supposed to know where to have the register when they use the same mapper? Will the games work properly if I have both sets for mapper 21 as valid? No information on this was on the Wiki. The information that is there is incomplete.
Edit: So far I've just started a small Checksum database and entering games into it and it uses a default if it fails to find a match. But while doing this I noticed some strange things. Like Akumajou Special (Kid Dracula) writes to $8FFF and $AFFF. But the documents tell you only to do PRG regs at $8000 to $8006 and same for $A000. If I do the whole range then it breaks the other games, not to mention Dracula doesn't seem to run then anyway. So I had to make a special case. I can't believe have disorganized all of this is.
But what I don't understand is when variants share the same number, and how you are supposed to know which address lines to use. For example mapper 21:
VRC4A uses A1 & A2.
VRC4C uses A6 & A7.
How am I supposed to know where to have the register when they use the same mapper? Will the games work properly if I have both sets for mapper 21 as valid? No information on this was on the Wiki. The information that is there is incomplete.
Edit: So far I've just started a small Checksum database and entering games into it and it uses a default if it fails to find a match. But while doing this I noticed some strange things. Like Akumajou Special (Kid Dracula) writes to $8FFF and $AFFF. But the documents tell you only to do PRG regs at $8000 to $8006 and same for $A000. If I do the whole range then it breaks the other games, not to mention Dracula doesn't seem to run then anyway. So I had to make a special case. I can't believe have disorganized all of this is.
-
Zepper
- Formerly Fx3
- Posts: 3262
- Joined: Fri Nov 12, 2004 4:59 pm
- Location: Brazil
- With respect, the mapper docs (probably the same I'm using) are slightly inaccurate. Well, I don't mind - they are different mappers, even with similarities. Here's a scop of my mapper 23:
8000 or 8FFF - PRG bankswitch
9000 - mirroring
9008 - WRAM enable/disable (japanese docs cover this register)
A000 or AFFF - PRG bankswitch
- For CHR bankswitch or IRQ, take xxx0,xxx1,xxx2,xxx3 as mirrors of xxx0,xxx4,xxx8,xxxC.
- Be clear that I didn't make any recent deep analysis in the Konami mappers. Most of my "corrections" dates ~5 years ago.
- For mapper 21, yes, I couldn't rewrite it in order to match the docs, so I left my old stuff. For IRQ register writes:
8000 or 8FFF - PRG bankswitch
9000 - mirroring
9008 - WRAM enable/disable (japanese docs cover this register)
A000 or AFFF - PRG bankswitch
- For CHR bankswitch or IRQ, take xxx0,xxx1,xxx2,xxx3 as mirrors of xxx0,xxx4,xxx8,xxxC.
- Be clear that I didn't make any recent deep analysis in the Konami mappers. Most of my "corrections" dates ~5 years ago.
- For mapper 21, yes, I couldn't rewrite it in order to match the docs, so I left my old stuff. For IRQ register writes:
Code: Select all
if(addr&0x0f) paddr=(addr&0xff00)|((addr>>1)&0x000f);
else if(addr&0xf0) paddr=(addr&0xff00)|((addr>>6)&0x000f);
switch(paddr&0xf003)
Last edited by Zepper on Sun Aug 03, 2008 8:40 am, edited 1 time in total.
-
Disch
- Posts: 1848
- Joined: Wed Nov 10, 2004 6:47 pm
One way I've seen it done (and the way I do it myself) is to just mask out the desired bits and OR them together.
For example for 021:
While this doesn't really provide correct mirroring, it works for all commercial games I've tried. (Getting correct mirroring in all cases in impossible without using a database of sorts -- the iNES number alone is not enough to know which address lines to use)
For example for 021:
Code: Select all
void Write_Mapper021(u16 a, u8 v)
{
a = (a & 0xF000) |
(a & 0x0006) |
((a & 0x00C0) >> 5);
Write_VRC4(a,v);
}
$8000 to $8006 and mirrors. Remember that unused address lines are ignored, so Akumajou Special writing to $8FFF is effectively writing to $8006.Like Akumajou Special (Kid Dracula) writes to $8FFF and $AFFF. But the documents tell you only to do PRG regs at $8000 to $8006
-
Zepper
- Formerly Fx3
- Posts: 3262
- Joined: Fri Nov 12, 2004 4:59 pm
- Location: Brazil
-
Disch
- Posts: 1848
- Joined: Wed Nov 10, 2004 6:47 pm
-
Zepper
- Formerly Fx3
- Posts: 3262
- Joined: Fri Nov 12, 2004 4:59 pm
- Location: Brazil
-
MottZilla
- Posts: 2837
- Joined: Wed Dec 06, 2006 8:18 pm
Oh so I should actually have masked for $8007, and then I suppose I could check if its $8007 instead of a number between $8000 and $8006. For some reason reading the docs made this all very unclear.
I'll try that out. But I see a checksum/hashing function is basically required to identify a database entry to ensure you use the proper lines due to iNES having not allocated each configuration a separate mapper. Does anyone have a complete list of Konami VRC games somewhere? I'm sure I don't know them all. I'd really like to know of a VRC4 game that uses the second PRG mode where $8000 and $E000 are locked but $A000 and $C000 are swappable.
As far as I've tested, every VRC4 game I've tried works fine. Including Wai Wai World as far as I could tell.
Edit: I changed this to this and everything seems to work.
I'll try that out. But I see a checksum/hashing function is basically required to identify a database entry to ensure you use the proper lines due to iNES having not allocated each configuration a separate mapper. Does anyone have a complete list of Konami VRC games somewhere? I'm sure I don't know them all. I'd really like to know of a VRC4 game that uses the second PRG mode where $8000 and $E000 are locked but $A000 and $C000 are swappable.
As far as I've tested, every VRC4 game I've tried works fine. Including Wai Wai World as far as I could tell.
Edit: I changed this to this and everything seems to work.
Code: Select all
if((Address&0xF007)>=0x8000 && (Address&0xF007)<=0x8007)
{
VRC4_PRGUpdate();
return;
}
if((Address&0xF007)>=0xA000 && (Address&0xF007)<=0xA007)
{
VRC4_PRGUpdate();
return;
}
Last edited by MottZilla on Sun Aug 03, 2008 12:28 pm, edited 1 time in total.
-
Disch
- Posts: 1848
- Joined: Wed Nov 10, 2004 6:47 pm
Well.. you wouldn't mask with $F007... rather, you'd mask with the address lines the mapper uses. So for example if the game uses A4 and A5, you'd mask with $F030.MottZilla wrote:Oh so I should actually have masked for $8007, and then I suppose I could check if its $8007 instead of a number between $8000 and $8006. For some reason reading the docs made this all very unclear.
I probably could've explained it better in my doc. But it sounds like you've got it working now anyway.
-
MottZilla
- Posts: 2837
- Joined: Wed Dec 06, 2006 8:18 pm
I believe this is a complete list of VRC games.
VRC1:
Ganbare Goemon! - Karakuri Douchuu
King Kong 2 - Ikari no Megaton Punch
Tetsuwan Atom
VRC3:
Salamander
VRC4 and VRC2:
Akumajou Special - Boku Dracula Kun
Bio Miracle Bokutte Upa
Crisis Force
Ganbare Goemon 2
Ganbare Goemon Gaiden 2 - Tenka no Zaihou
Ganbare Goemon Gaiden - Kieta Ougon Kiseru
Ganbare Pennant Race!
Getsufuu Maden
Gradius 2
Gryzor
Jarinko Chie - Bakudan Musume no Shiawase Sagashi
Parodius da!
Racer Mini Yonku - Japan Cup
Teenage Mutant Ninja Turtles 2 (J)
Teenage Mutant Ninja Turtles (J)
Tiny Toon Adventures (J)
TwinBee 3 - Poko Poko Dai Maou
Wai Wai World 2 - SOS!! Paseri Jou
Wai Wai World
VRC6:
Akumajou Densetsu
Esper Dream 2 - Aratanaru Tatakai
Mouryou Senki Madara
VRC7:
Lagrange Point
Tiny Toon Adventures 2 - Montana Land he Youkoso (J)
If any games are missing let me know. Otherwise I consider this list complete.
VRC1:
Ganbare Goemon! - Karakuri Douchuu
King Kong 2 - Ikari no Megaton Punch
Tetsuwan Atom
VRC3:
Salamander
VRC4 and VRC2:
Akumajou Special - Boku Dracula Kun
Bio Miracle Bokutte Upa
Crisis Force
Ganbare Goemon 2
Ganbare Goemon Gaiden 2 - Tenka no Zaihou
Ganbare Goemon Gaiden - Kieta Ougon Kiseru
Ganbare Pennant Race!
Getsufuu Maden
Gradius 2
Gryzor
Jarinko Chie - Bakudan Musume no Shiawase Sagashi
Parodius da!
Racer Mini Yonku - Japan Cup
Teenage Mutant Ninja Turtles 2 (J)
Teenage Mutant Ninja Turtles (J)
Tiny Toon Adventures (J)
TwinBee 3 - Poko Poko Dai Maou
Wai Wai World 2 - SOS!! Paseri Jou
Wai Wai World
VRC6:
Akumajou Densetsu
Esper Dream 2 - Aratanaru Tatakai
Mouryou Senki Madara
VRC7:
Lagrange Point
Tiny Toon Adventures 2 - Montana Land he Youkoso (J)
If any games are missing let me know. Otherwise I consider this list complete.
Last edited by MottZilla on Sun Aug 03, 2008 3:15 pm, edited 1 time in total.
-
Disch
- Posts: 1848
- Joined: Wed Nov 10, 2004 6:47 pm
-
MottZilla
- Posts: 2837
- Joined: Wed Dec 06, 2006 8:18 pm
-
MottZilla
- Posts: 2837
- Joined: Wed Dec 06, 2006 8:18 pm
Disch, would this be more accurate?
I tried this, and it works for all the games I've tried. Well except the Kid Dracula translation.
Code: Select all
int Mask = 0xF000;
Mask = Mask | VRC4.LA;
Mask = Mask | VRC4.LB;
...
if( (Address&Mask) >= 0x8000 && (Address&Mask) <= 0x8FFF )
{
VRC4.PRG0 = (Byte&0x1F) & ((PRG_Pages*2)-1);
VRC4_PRGUpdate();
return;
}-
Disch
- Posts: 1848
- Joined: Wed Nov 10, 2004 6:47 pm
That should equate to the same thing. I just prefer switch statements, myself, rather than range checks. But yeah that should work fine.
How I go about it:
021
025
As you might be able to see... with all the masking, the PRG reg is spread across all of $8xxx.
How I go about it:
021
Code: Select all
void Write(u16 a,u8 v,int cu)
{
a |= (a>>5) & 6;
NESMapperVRC4::Write(a,v,cu);
}
Code: Select all
void Write(u16 a,u8 v,int cu)
{
a = (a & 0xF000) | ((a>>2) & 3) | (a & 3);
if(a & 1) a += 4 - 1; // move bit 0 to bit 2
NESMapperVRC4::Write(a,v,cu);
}
Code: Select all
void NESMapperVRC4::Write(u16 a,u8 v,int cu)
{
u8 v5 = v & 0x1F;
v &= 0x0F;
switch(a & 0xF006)
{
case 0x8000: case 0x8002: case 0x8004: case 0x8006:
nPRG[0] = v5; SyncPRG(cu); break;
...
-
Near
- Founder of higan project
- Posts: 1553
- Joined: Mon Mar 27, 2006 5:23 pm
Range checks? Pssh, all the cool kids use bitmasks :PI just prefer switch statements, myself, rather than range checks.
if(addr >= 0x8000 && addr <= 0x8fff) == if((addr & 0xf000) == 0x8000)
if(addr >= 0x4200 && addr <= 0x421f) == if((addr & 0xffe0) == 0x4200)
In your specific case, you have a mask of either 0xf006 or 0xf0c0. Yet the lower-byte masking makes no difference since those particular bits can be anything and your test will still pass.
It would seem as though you could simply reduce it to: if((Address&0xf000) == 0x8000), and get the same result. Perhaps I'm missing something in the elipses. No big deal, just a quick observation.
-
Zepper
- Formerly Fx3
- Posts: 3262
- Joined: Fri Nov 12, 2004 4:59 pm
- Location: Brazil
It would be fine except that IRQs use 3 registers with different behaviours. Yaya, if addr AND F000h == F000h, "another" statement could start, but it's dumb.byuu wrote:It would seem as though you could simply reduce it to: if((Address&0xf000) == 0x8000), and get the same result. Perhaps I'm missing something in the elipses. No big deal, just a quick observation.