It is currently Mon Dec 11, 2017 10:18 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 15 posts ] 
Author Message
PostPosted: Wed Jul 26, 2017 11:00 am 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1510
Is there a way to read the number of the currently active bank in an UNROM game? Or do I always have to save this as a separate variable?

If I have to save it as a variable: How do I make sure that an interrupt doesn't get into the situation where the bank variable is different from the actually set bank, simply because the interrupt activated right in the moment when one of the two was already set, but the other one wasn't?

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Wed Jul 26, 2017 11:01 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10164
Location: Rio de Janeiro - Brazil
Put it in a constant location in every ROM bank.


Top
 Profile  
 
PostPosted: Wed Jul 26, 2017 11:04 am 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 6503
Location: Seattle
Is there an intrinsic way in hardware? No. Tokumaru's suggestion is it.

If you always update the shadow copy of the bank number before you change it, it can't get out of sync due to NMI or IRQ interruption. The same method works safely for MMC3 $8000.


Top
 Profile  
 
PostPosted: Wed Jul 26, 2017 11:31 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10164
Location: Rio de Janeiro - Brazil
If an interrupt needs to change banks, such as the NMI handler having to map in the sound engine/data bank, just read the current bank's number from ROM and push it to the stack before bankswitching, and when you're done, pull it from the stack and map that bank back in. This should work even if multiple interrupts that need to switch banks occur on top of each other.


Top
 Profile  
 
PostPosted: Wed Jul 26, 2017 4:00 pm 
Offline
User avatar

Joined: Mon Apr 04, 2011 11:49 am
Posts: 1933
Location: WhereverIparkIt, USA
lidnariq wrote:
If you always update the shadow copy of the bank number before you change it, it can't get out of sync due to NMI or IRQ interruption.


But if an interrupt were to occur in between the shadow update and bank write, the interrupt routine can't properly learn the current bank number by reading the shadow copy. Right? If the interrupt routine doesn't care about the current bank then this isn't an issue. Even if the ISR tries to restore the bank based on the shadow copy, it isn't a problem. The ISR will just align the shadow with the current bank before the main thread gets does the same swap again.

_________________
If you're gonna play the Game Boy, you gotta learn to play it right. -Kenny Rogers


Top
 Profile  
 
PostPosted: Wed Jul 26, 2017 4:07 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 6503
Location: Seattle
infiniteneslives wrote:
But if an interrupt were to occur in between the shadow update and bank write, the interrupt routine can't properly learn the current bank number by reading the shadow copy. Right?
Right. I was assuming that the interrupt wouldn't care about the current value, only that it be saved.


Top
 Profile  
 
PostPosted: Wed Jul 26, 2017 4:22 pm 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1510
tokumaru wrote:
Put it in a constant location in every ROM bank.

Thanks. That's what I needed.

tokumaru wrote:
If an interrupt needs to change banks, such as the NMI handler having to map in the sound engine/data bank, just read the current bank's number from ROM and push it to the stack before bankswitching, and when you're done, pull it from the stack and map that bank back in.

Yeah, using the stack in interrupts is of course logical. That's what I did anyway.

infiniteneslives wrote:
But if an interrupt were to occur in between the shadow update and bank write, the interrupt routine can't properly learn the current bank number by reading the shadow copy. Right? If the interrupt routine doesn't care about the current bank then this isn't an issue.

Yes, if your interrupt never acually reads the original bank value and only sets and resets a new value, then writing the bank variable before setting the bank itself should be sufficient.
But I still prefer the version where each bank has its own number in the same place in ROM because this one works in every constellation, even if the interrupt tries to read the value and not just set/reset it.

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Wed Jul 26, 2017 5:50 pm 
Online

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19328
Location: NE Indiana, USA (NTSC)
DRW wrote:
But I still prefer the version where each bank has its own number in the same place in ROM because this one works in every constellation, even if the interrupt tries to read the value and not just set/reset it.

That's fine for UNROM or MMC1, not so fine for something like MMC3 where you might load two consecutive bank numbers into adjacent windows (e.g. 25 in $8000 and 26 in $A000) and expect to read an array that continues from one to the next. Background tile streams, background map streams, and compressed sprite tile pages in The Curse of Possum Hollow are stored this way.


Top
 Profile  
 
PostPosted: Thu Jul 27, 2017 2:00 am 
Offline

Joined: Mon Nov 10, 2008 3:09 pm
Posts: 431
DRW wrote:
How do I make sure that an interrupt doesn't get into the situation where the bank variable is different from the actually set bank, simply because the interrupt activated right in the moment when one of the two was already set, but the other one wasn't?


Make sure you always write to the shadow bank register before the hardware bank register. That way, if the interrupt fires in the middle of changing a bank, the bank number the interrupt thread sees will match the bank the main thread is about to set, which is what you want in order to restore the bank at the end of the interrupt.

If your interrupt thread needs to actually read data or execute code from a bank that was set by the main thread (I'm not sure why you'd ever need to do this), the interrupt thread can re-set the bank itself.


Top
 Profile  
 
PostPosted: Fri Aug 18, 2017 7:05 am 
Offline

Joined: Tue Apr 11, 2006 4:08 am
Posts: 251
I do not want to create a separate topic, so I will ask here:
Is switching a bank in UNROM (and not just in UNROM) taking up some CPU time? How many cycles / times does a bank switch take?


Top
 Profile  
 
PostPosted: Fri Aug 18, 2017 7:09 am 
Offline
User avatar

Joined: Fri Nov 19, 2004 7:35 pm
Posts: 3967
No more cycles than any other kind of CPU write.

_________________
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!


Top
 Profile  
 
PostPosted: Fri Aug 18, 2017 7:32 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10164
Location: Rio de Janeiro - Brazil
Yeah, it takes just the time used by the instructions that write to the mapper (in the case of UNROM that'd be something like lda Bank : tax : sta $XXXX, x, or about 9 cycles - could be less if the bank is constant), there's no extra delay after the switch command, the new bank is available immediately.


Top
 Profile  
 
PostPosted: Fri Aug 18, 2017 8:08 am 
Offline

Joined: Tue Apr 11, 2006 4:08 am
Posts: 251
Thanks. And are MMC1 or MMC3 somehow significantly "faster" than UNROM?


Top
 Profile  
 
PostPosted: Fri Aug 18, 2017 8:29 am 
Online

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19328
Location: NE Indiana, USA (NTSC)
MMC1 is slower, at 28 cycles.
Code:
.macro mmc1_mode_A
  sta $8000
  lsr a
  sta $8000
  lsr a
  sta $8000
  lsr a
  sta $8000
  lsr a
  sta $8000
.endmacro

.macro mmc1_prg_A
  sta $E000
  lsr a
  sta $E000
  lsr a
  sta $E000
  lsr a
  sta $E000
  lsr a
  sta $E000
.endmacro

Because it's also bigger (19 bytes), this switching is often done as a subroutine instead of inline, and it takes 12 seconds to get in and out of a subroutine. It's also a lot trickier to get correct if there's a possibility that NMI or IRQ may interrupt the switch. So I sort of treat MMC1 PRG bank switch overhead as analogous to that of a TLB miss.

Not to be confused with MMC1 is MIMIC, the mapper used in Namco 108/109/118/119. It's almost as fast as UNROM:
Code:
MMC3_MODE = $00

.macro mimic_prg_8000_A
  ldx #MMC3_MODE | $06
  stx $8000
  sta $8001
.endmacro

.macro mimic_prg_A000_A
  ldx #MMC3_MODE | $07
  stx $8000
  sta $8001
.endmacro

MMC3 is an enhanced MIMIC that needs a bit more work to account for its PPU $0000/$1000 swapping and CPU $8000/$C000 swapping features. But if you use those features the same way throughout your entire game by setting these in MMC3_MODE, there's no extra overhead.


Top
 Profile  
 
PostPosted: Fri Aug 18, 2017 9:15 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10164
Location: Rio de Janeiro - Brazil
The speed of bankswitching operations is dictated by the complexity of the interface used to communicate with the mapper (the more writes you have to do to "talk" to the mapper, the slower it'll be to complete a bank switch command), but once the CPU is done sending the command, the new bank is immediately available.

The reason it works like this is because mappers are constantly routing memory accesses, for every single read/write. A bank switch merely changes a route, there's no copying of data or any other slow operations involved, so the very next read/write is already routed to the newly mapped bank.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 15 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 7 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group