As you might have guessed since I'm using UNROM 512, I've been making a game using NESMaker. It's been a great introduction to making an NES game and I've learned a lot by tearing through the provided code and changing it to suit my needs. I'm trying to make an all direction scrolling system for my game. I tried Horizontal Mirroring first and I could continue with that if I had to but I wished there was a way to just scroll in whatever direction I wanted without running into the status bar and realized that's exactly what single screen mirroring does since the other nametable is it's own separate thing.
According to the UNROM 512 wiki, 1-screen mirroring (solder pad or switchable) is supported. Does that mean I can do One Screen Mirroring with a status bar or am I mistaken? And if I can do that, how do I get that started? I've searched for a couple days and read everything I could find about how to implement it but I'm clearly missing some key elements.
Here's what I've found so far.
Almost nobody is talking about single screen mirroring on UNROM 512, so maybe I'm just completely mistaken about all of this.
I can change the header to the mirroring mode I want, I've done it, that part's easy.
Since the one screen is mirrored to all 4 nametables, trying to write to the different nametables ($2000, $2400, etc) would only write to one nametable anyway. So you have to switch between NameTableA and NameTableB to actually make it work.
On another project I've used CHR bank switching for animated backgrounds and it seems changing between NameTableA and NameTableB works similarly to that. For this I would switch to one and draw the tiles to it then do the same with the other.
Switching requires a write to "$8000-$FFFF" and I figure I could only write to the nametables during VBlank or when rendering is turned off, but I could switch between the two after a sprite zero hit to show a portion of each onscreen at the same time.
That's all I've got so far.
I'm guessing I need to set up some kind of address or something at initialization, but I really have no idea where to start. Any help would be much appreciated.
1-screen mirroring on UNROM 512?
Moderator: Moderators
- rainwarrior
- Posts: 8735
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: 1-screen mirroring on UNROM 512?
All of what you said sounds correct to me. What do you need help with?
Twin Dragons is a game that used single screen with that mapper, if you need an example to inspect.
Twin Dragons is a game that used single screen with that mapper, if you need an example to inspect.
-
- Posts: 3
- Joined: Fri May 20, 2022 10:11 am
Re: 1-screen mirroring on UNROM 512?
Thanks for responding, it's nice to know it's possible. I think I don't understand what writing to "$8000-$FFFF" means. Or I need help knowing what to define in initialization so that it will work.
I took a shot in the dark and set select button to do this
Lda #%00001000
Sta $8000
And start button to make it #$00 again, but neither write had a noticeable effect. I figured if it worked my background would've just become blank.
I read that the fourth bit of the write needs to be 1 to set NTB as the active one but when that didn't work I tried $#FF and it still did nothing.
In FCEUX, in the name table viewer I tried clicking the other name table options and it just fades out the highlight and keeps the first single screen selected, which makes me think I need set up in the header that I have two tilemaps or something.
I guess what I'm really asking for is some example code I can fiddle with.
Is $8000 really where I want to be writing to? The range of $8000-$FFFF is quite large. What specifically is the address I should write, or is that something I would define earlier but I didn't know that step?
How do I get the switch between NametableA and NametableB to work?
If it needs to be set up in initialization, how do I do that?
I appreciate any help, thanks!
I took a shot in the dark and set select button to do this
Lda #%00001000
Sta $8000
And start button to make it #$00 again, but neither write had a noticeable effect. I figured if it worked my background would've just become blank.
I read that the fourth bit of the write needs to be 1 to set NTB as the active one but when that didn't work I tried $#FF and it still did nothing.
In FCEUX, in the name table viewer I tried clicking the other name table options and it just fades out the highlight and keeps the first single screen selected, which makes me think I need set up in the header that I have two tilemaps or something.
I guess what I'm really asking for is some example code I can fiddle with.
Is $8000 really where I want to be writing to? The range of $8000-$FFFF is quite large. What specifically is the address I should write, or is that something I would define earlier but I didn't know that step?
How do I get the switch between NametableA and NametableB to work?
If it needs to be set up in initialization, how do I do that?
I appreciate any help, thanks!
- rainwarrior
- Posts: 8735
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: 1-screen mirroring on UNROM 512?
Ah, so the mapper has one hardware register which is accessed by a write to any of those addresses. Maybe it seems weird that it affects such a whole range, but it's simpler hardware to check if the address is just > $8000 or < $8000 as opposed to looking at every bit of the address to only respond to one single memory address.k_nietfeld wrote: ↑Sat May 21, 2022 1:37 pmI think I don't understand what writing to "$8000-$FFFF" means.
So, yes that's a way to write the register. However, there are two problems:
- The screen select is bit 7, not bit 3, so I think you want %10000000. (Mapper definition: UNROM 512)
- You may need to deal with bus conflicts, meaning the value in ROM at the address you're writing should be the same as the value in A that you're trying to write, otherwise the there is hardware interference causing the wrong value to be written.
Code: Select all
.segment "ZEROPAGE"
mapreg: .res 1 ; a variable to store the last used register settings
.segment "RODATA"
; a table of all 256 values to avoid bus conflicts
; this must be somewhere in $8000-FFFF to overlap with the register write
; (though really all stuff in this example should go in the $C000-FFFF fixed bank)
bus_conflict_table:
.repeat 256, I
.byte I
.endrepeat
.segment "CODE"
set_prg_bank: ; A = $00-1F to set PRG bank
eor mapreg
and #%00011111
write_mapper:
eor mapreg
sta mapreg
tay
sta bus_conflict_table, Y
rts
set_chr_bank: ; A = $00,$20,$40,$60 to set CHR bank
eor mapreg
and #%01100000
jmp write_mapper
set_screen: ; A = $00,$80 to set 1-screen nametable
eor mapreg
and #%10000000
jmp write_mapper
; to initialize, we need to get mapreg and the actual mapper register to be the same, here I'm just setting both to 0.
init_mapper:
lda #0
sta init_mapper+1 ; writes a 0 on top of the "#0" from lda #0, avoiding bus conflict
sta mapreg
rts
-
- Posts: 3
- Joined: Fri May 20, 2022 10:11 am
Re: 1-screen mirroring on UNROM 512?
Thank you SO much!
It's like I walked past the thing I was looking for several times but missed it because I didn't know what color it was.
After reading your reply I looked at the wiki for UNROM 512 again to check if I would need to worry about bus conflicts with the INL board I'll likely be putting my game on (not with that board but if I need to solve a bus conflict someday I understand how that works) and suddenly this part I skimmed over before popped out at me
Range,Mask: $8000-FFFF, $8000
$8000: [MCCP PPPP]
M = One screen Mirroring select
C = CHR RAM bank
P = PRG ROM bank
It was right there and I missed it because I didn't understand it well enough! Thanks for explaining it to me.
When I was explaining the puzzle I was trying to solve to my wife I even said, "They say you're supposed to write to $8000-$ffff, but like, when you switch CHR banks you write to $c000, and that's in that range..."
Anyway, I've got it working now. Your example code helped me understand what all of the bits in the write do well enough that I could modify a bit of code and use the variable that was already set up for PRG ROM bank switching for mirroring select and I'll probably use it later for CHR switching.
Thanks again. I wouldn't have done it without you.
It's like I walked past the thing I was looking for several times but missed it because I didn't know what color it was.
After reading your reply I looked at the wiki for UNROM 512 again to check if I would need to worry about bus conflicts with the INL board I'll likely be putting my game on (not with that board but if I need to solve a bus conflict someday I understand how that works) and suddenly this part I skimmed over before popped out at me
Range,Mask: $8000-FFFF, $8000
$8000: [MCCP PPPP]
M = One screen Mirroring select
C = CHR RAM bank
P = PRG ROM bank
It was right there and I missed it because I didn't understand it well enough! Thanks for explaining it to me.
When I was explaining the puzzle I was trying to solve to my wife I even said, "They say you're supposed to write to $8000-$ffff, but like, when you switch CHR banks you write to $c000, and that's in that range..."
Anyway, I've got it working now. Your example code helped me understand what all of the bits in the write do well enough that I could modify a bit of code and use the variable that was already set up for PRG ROM bank switching for mirroring select and I'll probably use it later for CHR switching.
Thanks again. I wouldn't have done it without you.
Re: 1-screen mirroring on UNROM 512?
Mapper30 only has one single screen mirroring, but the unrom-512 of many homebrew carts are not mapper30, but just a superset of mapper2. It is no different except that it expands the bank bit width.
You should use H or V mirroring mode to realize up and down or left and right scrolling
You need two screen name tables to render the current screen and draw the next screen at the same time. Just like a toy train, tear down the track passed and lay it in the front
You should use H or V mirroring mode to realize up and down or left and right scrolling
You need two screen name tables to render the current screen and draw the next screen at the same time. Just like a toy train, tear down the track passed and lay it in the front