Page 1 of 3
Setting inesprg to 2 makes game stop running
Posted: Fri Mar 22, 2019 9:26 pm
by Jay John
The mapper is set to MMC1.
I ran out of space in the two default banks, but when I set inesprg to anything other than 1 it makes the game freeze before starting.
Now, I've heard that the bank MMC1 starts is random, but I've tried putting the init code in every single bank and it didn't help, besides the init code is in the fixed bank, which leads me to believe I must have forgotten to put something somewhere, but where?
Is there something I'm missing?
Does anyone know where I can find a simple sample code for the MMC1?
Re: Setting inesprg to 2 makes game stop running
Posted: Fri Mar 22, 2019 10:14 pm
by lidnariq
Tepples has some sample code here:
https://github.com/pinobatch/snrom-template
I'd suggest trying with some debugging emulator, such as Mesen or the windows build of FCEUX.
Re: Setting inesprg to 2 makes game stop running
Posted: Fri Mar 22, 2019 11:40 pm
by koitsu
To expand a bit on lidnariq's statement:
This part of the MMC1 page (see paragraph after register description) explains the behaviour. If you read the content and the referenced threads, you'll see that there is some variance in which PRG bank different MMC1 chips tend to start in.
Thus, from a programmer's perspective (today), the universal solution is to put your startup code (what the RESET vector points to) at the top of every bank -- and that includes the vectors themselves. That startup code should reset the MMC1 to put it into a known state where you don't have to worry.
Tepples' snrom-template code does this through use of the
STUBxx segments you see in
the ld65 cfg file, combined with
the startup code that consists of 16 bytes (which includes the vectors) which references said
STUBxx entries. The code in
resetstub_entry is what the RESET vector points to; the code is commented fairly clearly so it should make sense.
You can customise that template to work with something smaller than 2mbit; he went with the largest PRG scenario but it works universally.
Re: Setting inesprg to 2 makes game stop running
Posted: Sat Mar 23, 2019 6:22 am
by tokumaru
Jay John wrote:I ran out of space in the two default banks, but when I set inesprg to anything other than 1 it makes the game freeze before starting.
You forgot to mention which assembler you're using, but from the above I guess it's NESASM?
I must have forgotten to put something somewhere, but where?
Can't say without seeing any code.
Re: Setting inesprg to 2 makes game stop running
Posted: Sat Mar 23, 2019 10:38 am
by Jay John
tokumaru wrote:You forgot to mention which assembler you're using, but from the above I guess it's NESASM?.
Yes, that's correct.
So, I added this in every bank and it now seems to be working.
Code: Select all
resetstub_entry:
sei
ldx #$FF
txs
stx $FFF2
jmp reset_handler
.addr nmi_handler, resetstub_entry, irq_handler
But I can't switch the prg banks (the chr switches work fine).
This is the code I'm using to do so:
Code: Select all
lda bankswitch
sta $E000
lsr a
sta $E000
lsr a
sta $E000
lsr a
sta $E000
lsr a
sta $E000
rts
First bank is fixed at bank 0 and I want to switch the last bank from bank 1 to 3, but this code is doing nothing.
Do I have to put a specific number on the "bankswitch" variable? It's currently loaded with 2, but I also tried 1 and 3.
Re: Setting inesprg to 2 makes game stop running
Posted: Sat Mar 23, 2019 10:52 am
by lidnariq
Have you already written to the register at $8000? If not, you should do that first. If yes, what did you write there?
Re: Setting inesprg to 2 makes game stop running
Posted: Sat Mar 23, 2019 10:59 am
by Jay John
lidnariq wrote:Have you already written to the register at $8000? If not, you should do that first. If yes, what did you write there?
Last time I've written there is when I changed mirroring
Code: Select all
ldvermir:
lda #$80
sta $8000
lda #%00011010
sta $8000
lsr a
sta $8000
lsr a
sta $8000
lsr a
sta $8000
lsr a
sta $8000
rts
Re: Setting inesprg to 2 makes game stop running
Posted: Sat Mar 23, 2019 11:10 am
by tokumaru
Let's get something out of the way: NESASM requires everything to be formatted with these stupid 8KB banks, but the NES itself has no concept of banks whatsoever, and MMC1 banks are 16KB, so the numbering you use for NESASM is not the same you'll use with the MMC1. NESASM banks 0 and 1 will be MMC1 bank 0, NESASM banks 2 and 3 will be MMC1 bank 1, and so on. The iNES header assumes 16KB banks regardless of the mapper.
Jay John wrote:Code: Select all
resetstub_entry:
sei
ldx #$FF
txs
stx $FFF2
jmp reset_handler
.addr nmi_handler, resetstub_entry, irq_handler
This is to reset the MMC1, right? Why use address $FFF2, though? I mean, I guess it works, but why not use $8000 and keep things less cryptic?
Code: Select all
lda bankswitch
sta $E000
lsr a
sta $E000
lsr a
sta $E000
lsr a
sta $E000
lsr a
sta $E000
rts
This is in the fixed bank, right?
First bank is fixed at bank 0
While the MMC1 has a PRG switching mode that fixes the first bank to $8000-$BFFF, but most people would prefer to hardwire the last bank to $C000-$FFFF, as that's way more common, and it's the default configuration.
Do I have to put a specific number on the "bankswitch" variable? It's currently loaded with 2, but I also tried 1 and 3.
Just keep in mind what I said above: NESASM banks are 8KB, MMC1 banks are 16KB.
Re: Setting inesprg to 2 makes game stop running
Posted: Sat Mar 23, 2019 11:55 am
by Jay John
tokumaru wrote:Let's get something out of the way: NESASM requires everything to be formatted with these stupid 8KB banks, but the NES itself has no concept of banks whatsoever, and MMC1 banks are 16KB, so the numbering you use for NESASM is not the same you'll use with the MMC1. NESASM banks 0 and 1 will be MMC1 bank 0, NESASM banks 2 and 3 will be MMC1 bank 1, and so on. The iNES header assumes 16KB banks regardless of the mapper.
Oh, I've been meaning to change the assembler, but never got around to it.
So, let me see if I got this.
If I were to order them by memory, then on NESASM it'd be:
Code: Select all
.bank 0
.org $8000
;code
.bank 1
.org $A000
;code
.bank 2
.org $C000
;code
.bank 3
.org $E000
;code
While on other assemblers it'd be:
Code: Select all
.bank 0
.org $8000
;code
.bank 1
.org $C000
;code
"This is to reset the MMC1, right? Why use address $FFF2, though? I mean, I guess it works, but why not use $8000 and keep things less cryptic?
Because it's how it was written in that github file, but thanks for the heads up, it makes it a lot easier to understand it.
This is in the fixed bank, right?
Yes
While the MMC1 has a PRG switching mode that fixes the first bank to $8000-$BFFF, but most people would prefer to hardwire the last bank to $C000-$FFFF, as that's way more common, and it's the default configuration.
It's just to get the hang of it, at the moment most of the code is organized without bank shifting in mind, I'll definitely be shuffling things around to better accommodate it later.
Re: Setting inesprg to 2 makes game stop running
Posted: Sat Mar 23, 2019 1:12 pm
by tokumaru
Jay John wrote:While on other assemblers it'd be:
Code: Select all
.bank 0
.org $8000
;code
.bank 1
.org $C000
;code
Kinda, but not exactly... directives and general code organization change from assembler to assembler (e.g. most assemblers don't have a ".bank" directive). My main point is that, unlike NESASM, assemblers don't usually force the programmer to use a specific bank size, which is a good thing because bank sizes vary from mapper to mapper.
Re: Setting inesprg to 2 makes game stop running
Posted: Sat Mar 23, 2019 1:50 pm
by Nicole
For instance, asm6 (the assembler I prefer) has no built-in concept of banks at all, instead giving you very direct control over the layout of the file it outputs, so you might have something like this:
Code: Select all
; iNES header
.db "NES",$1a
; etc.
; bank 0
.base $8000
; code...
.org $c000 ; pad to $c000
; bank 1
.base $c000
; code...
.org $fffa ; pad to $fffa
.dw nmi, reset, irq
; CHR banks
.incbin "tiles0.chr"
.incbin "tiles1.chr"
; etc.
Re: Setting inesprg to 2 makes game stop running
Posted: Sat Mar 23, 2019 1:58 pm
by Jay John
tokumaru wrote:Kinda, but not exactly... directives and general code organization change from assembler to assembler (e.g. most assemblers don't have a ".bank" directive). My main point is that, unlike NESASM, assemblers don't usually force the programmer to use a specific bank size, which is a good thing because bank sizes vary from mapper to mapper.
Alright, so I've set up the banks that way. But do I have to change anything else? It doesn't want to load the $C000 and $E000 banks.
Re: Setting inesprg to 2 makes game stop running
Posted: Sun Mar 24, 2019 9:19 am
by Jay John
Anyone?
Re: Setting inesprg to 2 makes game stop running
Posted: Sun Mar 24, 2019 9:25 am
by tokumaru
Can you show the complete structure of your source code? You can omit unrelated logic/data, but I'd like to see everything from the iNES directives, going through all the .banks and .orgs, mapper writes, reset stubs and interrupt vectors. It's hard to tell what's happening when looking at just bits and pieces that don't look wrong by themselves, but may not be in the correct places or something.
Re: Setting inesprg to 2 makes game stop running
Posted: Sun Mar 24, 2019 10:25 am
by Jay John
tokumaru wrote:Can you show the complete structure of your source code? You can omit unrelated logic/data, but I'd like to see everything from the iNES directives, going through all the .banks and .orgs, mapper writes, reset stubs and interrupt vectors. It's hard to tell what's happening when looking at just bits and pieces that don't look wrong by themselves, but may not be in the correct places or something.
Code: Select all
.inesprg 2
.ineschr 3
.inesmap 1
.inesmir %10
.bank 0
.org $0000
;variables
.org $8000
start:
sei
cld
ldx #$40
stx $4017
jsr ldhormir
lda bankcheckb
cmp #$FF
beq .start2
jsr bankswitch0000bck
jsr bankswitchC000for
.start2:
jsr off
jsr vblank
jsr vblank
jsr ldscrolldefault
;code
;jmp to bank1
off:
lda #%10001000
sta $2000
lda #%00000000
sta $2001
rts
on:
lda #%10001000
sta $2000
lda #%00011110
sta $2001
rts
ldscrolldefault
lda #$00
sta scrollh
lda #$00
sta scrollv
rts
vblank:
bit $2002
bpl vblank
rts
bankswitch0000bck:
lda bankswitch
sta $A000
asl a
sta $A000
asl a
sta $A000
asl a
sta $A000
asl a
sta $A000
lda bankcheckb
sec
sbc #$01
sta bankcheckb
rts
bankswitch0000for:
lda bankswitch
sta $A000
lsr a
sta $A000
lsr a
sta $A000
lsr a
sta $A000
lsr a
sta $A000
lsr a
sta $A000
lda bankcheckb
clc
adc #$01
sta bankcheckb
rts
bankswitchC000for:
lda bankswitch
sta $C000
lsr a
sta $C000
lsr a
sta $C000
lsr a
sta $C000
lsr a
sta $C000
lda bankchecks
clc
adc #$01
sta bankchecks
rts
ldhormir:
lda #$80
sta $8000
lda #%00011011
sta $8000
lsr a
sta $8000
lsr a
sta $8000
lsr a
sta $8000
lsr a
sta $8000
rts
ldvermir:
lda #$80
sta $8000
lda #%00011010
sta $8000
lsr a
sta $8000
lsr a
sta $8000
lsr a
sta $8000
lsr a
sta $8000
rts
.org $9FF0
bfind0
sei
ldx #$FF
txs
stx $8000
jmp start
.dw NMI
.dw bfind0
.dw bfind0
NMI:
lda $2002
lda #$7E
sta $2002
lda #$00
sta $2003
lda #$00
sta $2006
sta $2006
sta $2005
sta $2005
;code
rts
.bank 1
.org $A000
jsr ldvermir
jsr bankswitch0000for
jsr bankswitch0000for
;code
jsr bankswitch0000bck
;jmp to bank2
.org $BFF0
bfind
sei
ldx #$FF
txs
stx $8000
jmp start
.dw NMI
.dw bfind
.dw bfind
.bank 2
.org $C000
;the code that's not running
.org $DFF0
bfind2
sei
ldx #$FF
txs
stx $8000
jmp start
.dw NMI
.dw bfind2
.dw bfind2
.bank 3
.org $E000
;empty
.org $FFF0
bfind3
sei
ldx #$FF
txs
stx $8000
jmp start
.dw NMI
.dw bfind3
.dw bfind3
.bank 4
.org $0000
;tile data
.bank 5
.org $0000
;sprite data
.bank 6
.org $0000
;tile data
There may be stuff in the code I missed, but most of it is here.