1-screen mirroring on UNROM 512?

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
k_nietfeld
Posts: 3
Joined: Fri May 20, 2022 10:11 am

1-screen mirroring on UNROM 512?

Post by k_nietfeld »

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.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: 1-screen mirroring on UNROM 512?

Post by rainwarrior »

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.
k_nietfeld
Posts: 3
Joined: Fri May 20, 2022 10:11 am

Re: 1-screen mirroring on UNROM 512?

Post by k_nietfeld »

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!
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: 1-screen mirroring on UNROM 512?

Post by rainwarrior »

k_nietfeld wrote: Sat May 21, 2022 1:37 pmI think I don't understand what writing to "$8000-$FFFF" means.
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 pm Lda #%00001000
Sta $8000
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.
Here's a quick example of one way to use this mapper. Since there are 3 functions assigned to the various bits, you probably want to adjust them all separately, so I've provided 3 example functions here. Each function combines the bits you're trying to adjust with the last written value, masking it to just affect the bits you need before writing it to the mapper register.

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
If you have a version of the mapper without bus conflicts, you can skip the bus conflict table and just write straight to any address in $C000-FFFF.
k_nietfeld
Posts: 3
Joined: Fri May 20, 2022 10:11 am

Re: 1-screen mirroring on UNROM 512?

Post by k_nietfeld »

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.
User avatar
aquasnake
Posts: 515
Joined: Fri Sep 13, 2019 11:22 pm

Re: 1-screen mirroring on UNROM 512?

Post by aquasnake »

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
Post Reply