It is currently Fri Dec 15, 2017 5:24 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 132 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6, 7 ... 9  Next
Author Message
PostPosted: Mon Aug 03, 2015 7:07 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5898
Location: Canada
dougeff wrote:
I've noticed that Mike Tyson's Punch out switches banks every few frames for the opponent (rendered as background) and I believe also switches banks mid-frame because the top of the screen uses a different tile set than the opponent. It uses MMC2, which is also an option.

The MMC2 lets you create an automatic mid-screen bankswitch by placing a special tile at the point on the screen you want to switch (there are two swiching units, one for sprites and one for background), allowing up to double the onscreen tile count without requiring any use of the CPU or timing during the frame.


Top
 Profile  
 
PostPosted: Thu Aug 06, 2015 3:04 pm 
Offline
User avatar

Joined: Sat Jul 25, 2015 1:22 pm
Posts: 501
Is there a good reference around for coding for the MMC3?

I found a simple tutorial for the MMC1 on the wiki and I'm trying to gain an understanding of it.

So, I see the instructions to perform these commands, but I don't get why:

Quote:
lda #$0E ; vertical mirroring, fixed $C000, 8 KB CHR pages
sta $8000 ; (use $0F instead for horizontal mirroring)
lsr a
sta $8000
lsr a
sta $8000
lsr a
sta $8000
lsr a
sta $8000


So, I get that you change the mirroring on the system by addressing the PPU, but this one is addressing the very start of program ROM, so I'm guessing $8000 is a special location for addressing the mapper. Is that correct?

So, in decimal format, the bytes sent to $8000 are:

%00001110
%00000111
%00000011 (carry set)
%00000001 (carry set)
%00000000 (carry set)

What does any of this do, and why does it have to be LSRed and written five times?

Then to switch banks, you have to do this:

Code:
mmc1_load_prg_bank:
  sta $E000
  lsr a
  sta $E000
  lsr a
  sta $E000
  lsr a
  sta $E000
  lsr a
  sta $E000
  rts


So this time we're addressing $E000 which I imagine is a special address for telling the mapper to switch banks. I get how the accumulator is a value from $00-$0F, except for the fact that it LSRs and writes 5 times. Seems like a common theme for addressing this mapper, but can anyone tell me why?

Then there's this bit that I'm trying to wrap my head around:

Code:
reset_stub:
  sei
  ldx #$FF
  txs        ; set the stack pointer
  stx $8000  ; reset the mapper
  jmp reset  ; must be in $C000-$FFED
  .addr nmiHandler, reset_stub, irqHandler


So, let me see if I understand what's happening here.

First off, it says that with some versions of this mapper, the end of the program is switchable. That makes me think that any bank which could be at the end of the program needs to include addresses for NMI, RESET, and IRQ starting at $FFFA. Is that correct?

Then, if your program changes, the instructions for your vectors need to be located at the same addresses, right?

So it's saying to put the above code at the last 16 bytes of a bank. So that would be like, $BFF0, right? Why does it only tell you to put the reset vector at the end of each switchable bank? Why not NMI and IRQ as well? Wouldn't those addresses need to stay the same as the banks switch?

Also it says that writing %11111111 to $8000 will reset the mapper but I don't understand why. Is there a document on the mapper instructions, particularly for MMC3?

I see now that the above code isn't a reset, but a reset stub, and I'm even more confused.

First off, wouldn't NMI, RESET, and IRQ have to be .org-ed to the same addresses in each bank?

Second, I don't really get the purpose for the above code now that I realize it's not actually the reset vector. When is this reset_stub supposed to be called? Why does it disable interrupts and set the stack to $FF when this is going to happen again anyway when it JMPs to reset?

I hope that's not too much to ask. I thought I was ready to understand this and start integrating mapper features but I need a little help. I don't even think I'm going to need to switch program banks but I'd like to understand the concepts.

Thanks for all of your help getting started!


Top
 Profile  
 
PostPosted: Thu Aug 06, 2015 3:26 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10164
Location: Rio de Janeiro - Brazil
darryl.revok wrote:
Is there a good reference around for coding for the MMC3?

There's a reference page in the wiki, but I don't think there are any examples.

Quote:
So, I get that you change the mirroring on the system by addressing the PPU, but this one is addressing the very start of program ROM, so I'm guessing $8000 is a special location for addressing the mapper. Is that correct?

The way the program communicates with the mappers is kind of a trick: since PRG-ROM is not writable, most mappers intercept attempts to write to PRG-ROM, and use the value being written for purposes related to the mapper function. Which addresses are used for what purposes depends on the mapper.

Quote:
What does any of this do, and why does it have to be LSRed and written five times?

Because in an attempt to make the MMC1 chip cheaper, it only has 1 input bit, so you need multiple writes to send all the bits.


Top
 Profile  
 
PostPosted: Thu Aug 06, 2015 4:34 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1868
Location: DIGDUG
Each mapper switches banks completely differently, so learning how MMC1 works teaches you nothing about how MMC3 works. I wrote up some test programs for the basics of MMC3 bankswapping. I'll post it or PM it to you later, when I get back to my computer.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Thu Aug 06, 2015 5:10 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1868
Location: DIGDUG
MMC3 - bankswapping basics.

At startup, the first 2 PRG banks are loaded to $8000-bfff, and the last 2 PRG banks are loaded at $c000-ffff.

$8000-9fff and $c000-dfff are swappable. The other 2 are fixed. I would prefer to keep c000 fixed, unless you have a lot of dmc sound files (as they need to go above $c000.)


To swap PRG bank 1 (the second one) into $8000-9fff
lda #$06
sta $8000
lda #$01
sta $8001

To swap PRG bank 2 (the third one) into $8000-9fff
lda #$06
sta $8000
lda #$02
sta $8001

Etc.

MMC3 divides CHR-ROM banks into chunks of $400 bytes.
Thus 1 full set of tiles ($2000 bytes) = banks 0-7. The next set would be 8-f.

To swap a second set (8-f) into the PPU...

lda #$00 ;destination $000-7ff
sta $8000
lda #$08 ;banks 8-9
sta $8001

lda #$01 ;destination $800-fff
sta $8000
lda #$0a ;banks a-b
sta $8001

lda #$02 ;destination $1000-13ff
sta $8000
lda #$0c ;bank c
sta $8001

lda #$03 ;destination $1400-17ff
sta $8000
lda #$0d ;bank d
sta $8001

lda #$04 ;destination $1800-1bff
sta $8000
lda #$0e ;bank e
sta $8001

lda #$05 ;destination $1c00-1fff
sta $8000
lda #$0f ;bank f
sta $8001

If you want to know how the scanline IRQ works, see this tutorial...
http://bobrost.com/nes/files/mmc3irqs.txt

Hope this helps. BTW, these swaps happen instantaneously, and can be done anytime.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Last edited by dougeff on Thu Aug 06, 2015 8:36 pm, edited 3 times in total.

Top
 Profile  
 
PostPosted: Thu Aug 06, 2015 5:15 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19346
Location: NE Indiana, USA (NTSC)
dougeff wrote:
At startup, the first 2 PRG banks are loaded to $8000-bfff

Says who? I was under the impression that bank registers 6 and 7 had unspecified values at power-on, as did the bit in $8000 for swapping windows $C000 and $8000. This means your code in $E000-$FFFF must initialize these.

Quote:
BTW, these swaps happen instantaneously, and can be done anytime.

However, trying to swap in both the main program and the NMI handler takes a bit of planning, as the main program and NMI handler have to share port $8000.


Top
 Profile  
 
PostPosted: Thu Aug 06, 2015 5:34 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1868
Location: DIGDUG
How do you initialize that? (Source code please) or is it the same as I wrote, but with the banks different?

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Thu Aug 06, 2015 5:52 pm 
Offline
User avatar

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 1046
darryl.revok wrote:
Then there's this bit that I'm trying to wrap my head around:

Code:
reset_stub:
  sei
  ldx #$FF
  txs        ; set the stack pointer
  stx $8000  ; reset the mapper
  jmp reset  ; must be in $C000-$FFED
  .addr nmiHandler, reset_stub, irqHandler


So, let me see if I understand what's happening here.

First off, it says that with some versions of this mapper, the end of the program is switchable. That makes me think that any bank which could be at the end of the program needs to include addresses for NMI, RESET, and IRQ starting at $FFFA. Is that correct?

That is correct.
Quote:
Then, if your program changes, the instructions for your vectors need to be located at the same addresses, right?

At reset, the CPU begins executing from the address stored at $FFFC. This is all that matters to the CPU. The reset vector is whatever two bytes happen to be stored $FFFC at reset/poweron. The NMI vector is whatever two bytes happen to be stored at $FFFA when the NMI fires. The IRQ vector is whatever two bytes happen to be stored at $FFFE when an IRQ fires.

There could be a different two bytes stored at $FFFC in every bank. It's better for consistency that it's always the same, but it doesn't need to be that way. The CPU just reads the two bytes and starts executing from that address.

Quote:
So it's saying to put the above code at the last 16 bytes of a bank. So that would be like, $BFF0, right?

Well... no and yes. Consider a bank that you .org to $8000-$BFFF. That bank can still be swapped to occupy $C000-$FFFF instead. So... yes, while code mapped to $BFF0 could end up there, you really want it in $FFF0.

The idea is to have that setup code in a part of the ROM that can't possibly be swapped "out of sync" with the vector the CPU starts executing from which will always be whatever address is at $FFFC. Using the knowledge that the reset_stub will be with a vector in the same bank, regardless of which bank that is, allows you to safely initialize the mapper to a known state using the reset_stub. Then your program can run normally.

Quote:
Why does it only tell you to put the reset vector at the end of each switchable bank? Why not NMI and IRQ as well? Wouldn't those addresses need to stay the same as the banks switch?

I don't see where you're seeing to only put the reset vector. Yes, you should have a valid IRQ and NMI vector as well. The jmp reset in the example code is not a vector at all. The reset vector is reset_stub, and the CPU has already begun executing from there by the time jmp reset is executed. reset is just a label name. It could be jmp initialize or jmp anywhereelse you wanted to go after you knew the mapper was in a known state.

I think you're getting confused by the labels. The CPU has no knowledge of what you called reset_stub or reset or anything. It only knows what address is at $FFFC. you could call "reset_stub" "homersimpson" instead, and "reset" "supermario" and the code could still work the same. It's not like C where execution starts at a given named thing. (main.)

Quote:
Also it says that writing %11111111 to $8000 will reset the mapper but I don't understand why. Is there a document on the mapper instructions, particularly for MMC3?

You can read about MMC1 here and you can read about MMC3 here.

Quote:
I see now that the above code isn't a reset, but a reset stub, and I'm even more confused.

All the CPU does when it starts is go to the address stored at $FFFC. In the example code, that address is reset_stub. The code below reset_stub just runs normally after reset.

Quote:
First off, wouldn't NMI, RESET, and IRQ have to be .org-ed to the same addresses in each bank?

Yes. As stated above, all the CPU does is read from the address at $FFFC at reset. It will treat whatever two bytes are there as the address to start executing from, so no other kind of thing should occupy that space.

Quote:
Second, I don't really get the purpose for the above code now that I realize it's not actually the reset vector. When is this reset_stub supposed to be called? Why does it disable interrupts and set the stack to $FF when this is going to happen again anyway when it JMPs to reset?

The vector is just the address at $FFFC. The CPU starts executing from whatever address is at $FFFC, always. After that, the program runs normally. So it wouldn't disable interrupts or set the stack to $FF again unless you also put those things under the reset label in the example. (And you shouldn't, because as you said it was already done.)

So in the example case, reset_stub is the very first thing executed, always.

Quote:
I thought I was ready to understand this and start integrating mapper features but I need a little help. I don't even think I'm going to need to switch program banks but I'd like to understand the concepts.

I don't think it's too worth thinking about mappers until your game is about to be larger than 24 KB. At that point you can still make it larger without a mapper, but if you plan to use a mapper that's when you have to being to plan how you'll lay out your banks so you don't end up relying on too much of it being in a fixed bank.

Edit: I should note that some mappers start with a known state, in which case you have to worry less about this stuff. But it is very worth understanding even if you use those mappers.

_________________
https://kasumi.itch.io/indivisible


Top
 Profile  
 
PostPosted: Thu Aug 06, 2015 7:42 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1868
Location: DIGDUG
OK, revision...after reviewing the init code for a MMC3 game (Batman)...

Although the emulator I've been testing MMC3 automatically loads the ROMs at startup as I described. The game does this near start-up...
07:EF66:A2 06 LDX #$06
07:EF68:8E 00 80 STX $8000
07:EF6B:A0 1C LDY #$1C
07:EF6D:8C 01 80 STY $8001
07:EF70:E8 INX
07:EF71:8E 00 80 STX $8000
07:EF74:C8 INY
07:EF75:8C 01 80 STY $8001

which has the effect of defining which bank goes at 8000-9fff, which bank goes at a000-bfff, and making c000-ffff fixed, and that the last 2 banks will be at c000-ffff.

I have to assume that actual hardware only has e000-ffff set for certain at start-up, to the last bank on the ROM.
I can't test this, because I don't have burnable/flashable cartridges, and my NES is at my dad's house.

Edit: alternatively, you could set 8000 and e000 as the fixed banks - and a000 and c000 as the swapped banks.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Fri Aug 07, 2015 5:13 am 
Offline
User avatar

Joined: Sat Jul 25, 2015 1:22 pm
Posts: 501
Quote:
I don't think it's too worth thinking about mappers until your game is about to be larger than 24 KB. At that point you can still make it larger without a mapper, but if you plan to use a mapper that's when you have to being to plan how you'll lay out your banks so you don't end up relying on too much of it being in a fixed bank.


I don't want to get ahead of myself. I'm still sticking to my animation engine until I get that perfected. I suppose I don't need to understand everything about the mapper functionality just yet, but I need to know enough to integrate it into my animation engine or I'm going to have to rewrite major portions of that down the line. I think I'm about to do a rewrite of the animation engine anyway so it seems like it would be a good time add bank support now and hopefully not have to make any big structural changes to that routine again. Plus, I already have enough animations for my main character to justify a bank swap.

Quote:
I don't see where you're seeing to only put the reset vector. Yes, you should have a valid IRQ and NMI vector as well. The jmp reset in the example code is not a vector at all. The reset vector is reset_stub, and the CPU has already begun executing from there by the time jmp reset is executed. reset is just a label name. It could be jmp initialize or jmp anywhereelse you wanted to go after you knew the mapper was in a known state.

I think you're getting confused by the labels. The CPU has no knowledge of what you called reset_stub or reset or anything. It only knows what address is at $FFFC. you could call "reset_stub" "homersimpson" instead, and "reset" "supermario" and the code could still work the same. It's not like C where execution starts at a given named thing. (main.)


Alright, I feel like I've almost got this. ALMOST. I don't plan to use MMC1 so it doesn't matter TOO much, but I would like to understand it.

Okay, the reason why I'm saying that it says to only put the reset vector is this:

Quote:
Some revisions of the MMC1 IC might power up in a mode other than fixed-$C000, requiring that the vectors and the start of the init code be placed in all banks, much as in BxROM or AxROM or GxROM. Other revisions guarantee that the fixed bank is loaded at power on. To make sure your code works on all MMC1 revisions, put the following code in the last 16 bytes of each 16384 byte bank. (Barbie uses almost identical code.)
reset_stub:
sei
ldx #$FF
txs ; set the stack pointer
stx $8000 ; reset the mapper
jmp reset ; must be in $C000-$FFED
.addr nmiHandler, reset_stub, irqHandler


It tells you to put that code at the end of each 16384 bank. That's the only code it tells you to put there. It doesn't say to put the NMI handler or anything like that there.

1. Now, what I have learned is to put a .org statement at the end of your code so you can put the vectors at the right location in the PRG ROM. This, if I understand correctly, tells you to put those addresses for the vector at the end of each bank. So i imagine you couldn't .org $FFFA, because it might be in the first bank. So how would you make sure that what you're writing actually occupies the last 16 bytes without a .org? And when you're writing with extra program banks, how are you supposed to write code in memory spaces that are identical addresses to ones you've already written in the same program? Wouldn't the assembler throw up a flag? It's not like it understands that you're using a mapper. Do you write it in a different file and include it as a bin?

2. So if you have that at the last 16 bytes of your first bank, it won't address the vectors because they're not at the actual vector address. You will, however, have an identical label for a memory location called reset_stub as the one that lies in your second bank. Now, I know that name is only for coding and is interpreted by the assembler and doesn't make it to the actual program. but won't the assembler say, "You have two labels for reset_stub and I can't put both of them at $FFFC."?

3. I'm going to guess that when you write a bank, even if you can't know for sure if it will be booted on startup, then you'll know for sure that if it will be loaded into the top or bottom. That's gotta be true, right? Well, you said that this could actually happen.

4. It says that reset (the rest of the reset instruction not in the stub) must be located in $C000-$FFED. What about the nmi instructions and the irq instructions? Won't those have to be at the same point in all four banks in case any of those banks landed to where the vector addresses are pointing? If you could put a bank in the top that goes in the bottom, it seems like you're going to have to put copies of all of your interrupt instructions in every single bank. Why would you ever want to switch a bank between the top and bottom of your code? I can't imagine a situation in which a program would benefit from flipping the top and bottom halves in a way that couldn't be better achieved through branching and subroutines.

While writing that last paragraph I also got so frustrated that I canceled this whole post until I realized that I had spent way too long writing it and trying to understand it to just give up now. If I could hear that there is no way a person could ever want to switch a bank between the top and the bottom and it's just a glitch in the mapper that you have to account for then I'd feel decent at least about getting it. I can't imagine why it would be done on purpose.

I'm going to make another reply for a more productive and hopefully less aggravating topic, getting my game to function with MMC3 CHR switching.


Last edited by darryl.revok on Fri Aug 07, 2015 5:43 am, edited 1 time in total.

Top
 Profile  
 
PostPosted: Fri Aug 07, 2015 5:42 am 
Offline
User avatar

Joined: Sat Jul 25, 2015 1:22 pm
Posts: 501
Thank you for the instructions on bank switching. The MMC3 doesn't seem near as confusing at least when it comes to that.

So, the CHR-ROM part seems pretty simple. You write the number of the bank you're switching out, 0-8, to $8000, then write the bank you're switching in, 0-FF, to $8001. When I see that, it's simple, but when I look at the reference page in the wiki it's almost too much information to process at once. I'll try to break this down a little at a time.

Quote:
The MMC3 has 4 pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF - even addresses ($8000, $8002, etc.) select the low register and odd addresses ($8001, $8003, etc.) select the high register in each pair.


Okay, I don't get any of this. I thought a register was like the x register and the y register and the accumulator.

So when you say to STA $00 to $8000 you are addressing the low register, and when you STA $08 to $8001 you are addressing the high register. What does that mean?

Also, the MMC3 doesn't have an option for a save battery, does it? That's unfortunate, I was really hoping my game could let you save. It looks like it does have support for 4-screen nametables though. Could they put RAM in the reproduction MMC3s for 4-screen nametables? Just curious. It would make bi-directional scrolling a lot less hassle.


Top
 Profile  
 
PostPosted: Fri Aug 07, 2015 5:57 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19346
Location: NE Indiana, USA (NTSC)
darryl.revok wrote:
Quote:
The MMC3 has 4 pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF - even addresses ($8000, $8002, etc.) select the low register and odd addresses ($8001, $8003, etc.) select the high register in each pair.


Okay, I don't get any of this. I thought a register was like the x register and the y register and the accumulator.

They're memory-mapped I/O ports. Lately, in my own work, I have tried to use "port" for addresses that refer to something other than byte-addressed memory. What it's trying to say is that $8000, $8001, $A000, $A001, $C000, $C001, $E000, and $E001 are the actually unique ports, and all other addresses in $8002-$FFFF are mirrors of those ports.

Quote:
So when you say to STA $00 to $8000 you are addressing the low register, and when you STA $08 to $8001 you are addressing the high register. What does that mean?

The extent to which we must explain this depends on the extent to which you understand memory-mapped I/O.

Quote:
Also, the MMC3 doesn't have an option for a save battery, does it?

Kirby's Adventure saves to battery RAM, as do some hacks of Super Mario Bros. 3 that are intended to run on Kirby's Adventure circuit boards.

Quote:
Could they put RAM in the reproduction MMC3s for 4-screen nametables?

Yes, but it'd cost more.


Top
 Profile  
 
PostPosted: Fri Aug 07, 2015 6:36 am 
Offline
User avatar

Joined: Sat Jul 25, 2015 1:22 pm
Posts: 501
tepples wrote:
The extent to which we must explain this depends on the extent to which you understand memory-mapped I/O.

Well I understand that things like the CPU and PPU have two-byte addresses that are exposed for the program to send instructions to the hardware. I don't know if I need to understand it too much more than that right now other than how the processors respond to the bits they're sent.

So $8000 and $8001 are two different ports and you write to them to perform different functions?

I will say that there are almost no pages online about NES development that are not intimidating to a beginner. There are definitely helpful people in the forums and helpful posts if you dig for them, but I would bet 9 out of 10 people who might be interested in this hobby are deterred from even starting when they look online and can't understand anything they read.

I'm not saying the information should be dumbed down. I'm a n00b and I'm not to the point where I read something like that and understand it right off. A week ago I couldn't have read 6502 assembly and understood the instructions. I'm just saying there's a huge gap in the area of information on the topic of NES programming which isn't directed to someone with a background in assembly programming. There's like one tutorial for beginners and you have to dig through forums and find people talking about it to even find that.

Is there anything I need to put at the start of my file other than changing the iNES header?

At least the $E000-$FFFF PRG-ROM bank is fixed. Whew. So I don't have to worry about sticking the interrupt vectors everywhere. Should I just put the instructions for NMI, RESET, and IRQ in here as well so I don't have to worry about them moving?


Top
 Profile  
 
PostPosted: Fri Aug 07, 2015 7:53 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10164
Location: Rio de Janeiro - Brazil
darryl.revok wrote:
So, the CHR-ROM part seems pretty simple. You write the number of the bank you're switching out, 0-8, to $8000, then write the bank you're switching in, 0-FF, to $8001.

Instead of "the number of the bank you're switching out" it would be more accurate to say "the slot where the bank will be switched in". That's how the MMC3 works: you first tell it what slot to use, and then what bank to put in that slot.

Quote:
Quote:
The MMC3 has 4 pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF - even addresses ($8000, $8002, etc.) select the low register and odd addresses ($8001, $8003, etc.) select the high register in each pair.


Okay, I don't get any of this. I thought a register was like the x register and the y register and the accumulator.

X, Y and A (and also the stack pointer, the program counter and the status flags) are CPU registers, this is talking about mapper registers. A register is simply a small unit of memory inside a chip. The same way the CPU uses its registers to perform tasks, the mapper has to keep track of things like which banks are loaded where and the current value of the scanline counter, and this information is stored in its registers.

In order to have the mapper do what we want, we have to send it data to populate these registers, and this is done through memory mapped IO. This means that memory addresses are used for communication with different parts of the system, rather than for actual memory. There are chips inside the NES and inside the cartridges that are constantly watching the addresses that are accessed by the CPU and PPU, and they can redirect these accesses to different parts of the hardware depending on what the addresses are. For example, when you do "STA $0405", how does the CPU know that the value is supposed to go to the internal 2KB of RAM, and not to the PPU or to the cartridge? It looks at the address. Any address between $0000 and $1FFF will activate the internal RAM. Anything between $2000-$3FFF will activate the PPU ports. Anything between $8000-$FFFF will activate the PRG-ROM in the cartridge. This process of selecting a device or a register based on a memory address is called address decoding.

As far as the NES is concerned, $8000-$FFFF is just a flat memory space, but mappers have the capacity to take different actions depending on which address is accessed. Each mapper will divide the memory range differently depending on its needs and implementation limitations. The MMC3 breaks the space up in 4 parts, since it has 4 pairs of registers, and alternates even and odd addresses to select a registers within the pair.

The way the registers are arranged in memory is just a side effect of using the address bits that the MMC3 designers decided to use. The MMC3 has 8 accessible registers. To address 8 positions, we need 3 bits (enough to count from 0 to 7). The guys who designed the MMC3 could have picked any 3 bits out of the 16 that form an address, but they picked bits 0, which selects between even and odd, and bits 13 and 14, which select between $8000-$9FFF, $A000-$BFFF, $C000-$DFFF or $E000-$FFFF. They could have picked other bits, but they picked these, resulting in the register layout you see in the wiki.

Quote:
Also, the MMC3 doesn't have an option for a save battery, does it? That's unfortunate, I was really hoping my game could let you save.

Several MMC3 games have battery-backed SRAM.


Top
 Profile  
 
PostPosted: Fri Aug 07, 2015 8:26 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10164
Location: Rio de Janeiro - Brazil
darryl.revok wrote:
I will say that there are almost no pages online about NES development that are not intimidating to a beginner. There are definitely helpful people in the forums and helpful posts if you dig for them, but I would bet 9 out of 10 people who might be interested in this hobby are deterred from even starting when they look online and can't understand anything they read.

Can you just imagine how things were before the internet? These days it seems like people want everything to be handed to them in a silver platter. Well, back in the 80's and 90's people didn't have video tutorials on YouTube detailing every little thing they had to do and somehow people still managed to learn assembly and make games.

Retro software development is a niche thing, it's not profitable, so there's obviously not gonna be as much material about it as there is for current technologies. Whatever is out there is the work of hobbyists, who don't always have a lot of free time.

Quote:
I'm a n00b and I'm not to the point where I read something like that and understand it right off.

That's because this is not a simple subject. To understand memory mapping and mirroring you have to understand the binary system, computer architecture, and a bit of electronics, things that most new programmers don't care about. There's too much knowledge involved and there's no amount of dumbing down that will make anyone understand these concepts right off the bat... it takes years to master all of that! The good news is that you don't have to master everything in order to make games... so don't feel bad if you don't understand every single word in a wiki page. As long as you start small (e.g. don't expect to code SMB3 as your first NES project) and do things according to the book, with help from people in this forum, things will slowly fall into place as you go. There's no rushing that process.

Quote:
Is there anything I need to put at the start of my file other than changing the iNES header?

It's not so much "changing" as it is "creating" the iNES header. Anyway, I don't remember you mentioning which assembler you're using, so I can't say much about how to set things up.

Quote:
Should I just put the instructions for NMI, RESET, and IRQ in here as well so I don't have to worry about them moving?

Definitely. If you need to access other banks from the NMI or IRQ handlers (such as the NMI needing music code and data), they can switch in whatever they need (just be careful to restore whatever banks you change, so as to not break things after you return from the interrupts).


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 132 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6, 7 ... 9  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 3 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