MM3 scanline counter, check multiple point possible and how?

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

User avatar
Banshaku
Posts: 2417
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

MM3 scanline counter, check multiple point possible and how?

Post by Banshaku »

I tested the counter long time ago to split the screen at a specific region but now I have different need and unfortunately I cannot figure out from the doc if I want to do is something possible with this mapper or not. My guess is yes.

What I want to do is:

- top of screen (let say 50 lines) scroll to the right
- second part of screen (almost until end of screen) scroll to the left
- last part of screen stay centered and BG bank is switched to show proper CHR data

The reason for the bank switch is to show text and it doesn't fit inside the background data. This is an animation effect during a transition so this is not used during gameplay.

With the technical reference I cannot figure it out, maybe there is a tutorial on the subject? I will check again in the wiki.

While on the subject, another use-case I will have is:
- Scroll an image from top to bottom
- leave a black window a the bottom to display text while the image is scrolled
- this mean the black window will overlay the image while scrolling

In that case I guess I will need to set horizontal mirroring then put the image first nametable and maybe it will spill in second one. Then at the end of the second nametable the text windows will be there (this is all guessing but my mental image of it).

Thank you in advance for any information on the subject.
User avatar
Bregalad
Posts: 8056
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: MM3 scanline counter, check multiple point possible and

Post by Bregalad »

Banshaku wrote: What I want to do is:

- top of screen (let say 50 lines) scroll to the right
- second part of screen (almost until end of screen) scroll to the left
- last part of screen stay centered and BG bank is switched to show proper CHR data

The reason for the bank switch is to show text and it doesn't fit inside the background data. This is an animation effect during a transition so this is not used during gameplay.
Of course this is possible, with 2 different IRQs per frame. Since you say this is not used during gameplay I assume your CPU is mostly unused and you don't even need IRQs in the first place, polling $2002 or and/or using timed loops will work as well.
While on the subject, another use-case I will have is:
- Scroll an image from top to bottom
- leave a black window a the bottom to display text while the image is scrolled
- this mean the black window will overlay the image while scrolling

In that case I guess I will need to set horizontal mirroring then put the image first nametable and maybe it will spill in second one. Then at the end of the second nametable the text windows will be there (this is all guessing but my mental image of it).
That sounds fine to me. I'm not sure what you mean by "scroll an image from top to bottom", but if this means scrolling vertically by some pixels but less than two nametables high, then it's fine.
You could also use vertical mirroring, have one nametable dedicated to the image and the other nametable dedicated to text, and write portions of the image as it scrolls vertically. This is required if it's taller than two-nametables-minus-text-height.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: MM3 scanline counter, check multiple point possible and

Post by tokumaru »

You can have as many MMC3 IRQs as you want in a single frame. If I'm not mistaken, any subsequent IRQ is set up just like the first one: latch the counter value, reload it and enable IRQs.

Also, don't forget that in order to change the vertical scroll you need to perform a full scroll reset using the $2006/5/5/6 trick.
User avatar
Bregalad
Posts: 8056
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: MM3 scanline counter, check multiple point possible and

Post by Bregalad »

tokumaru wrote:You can have as many MMC3 IRQs as you want in a single frame.
I think there's a limit to one IRQ every two lines, I'm not sure what was the reason, but I'm fairly sure this was the case. Even if you could trigger an IRQ immediately by some configuration, this is pretty useless as this'd be equivalent to a JMP or JSR instruction.
Also, don't forget that in order to change the vertical scroll you need to perform a full scroll reset using the $2006/5/5/6 trick.
Nope in many cases when changing vertical scroll only (and in this case most specifically) just $2006/$2006 will be enough.
User avatar
Banshaku
Posts: 2417
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: MM3 scanline counter, check multiple point possible and

Post by Banshaku »

So it's possible, which was my assumption but here where I feel dumb a little bit. Even though I read the wiki, I have no idea how to set 3 of them :lol: I see reload and latch which give me the impression that it would reset the currently active one, which I'm sure my interpretation is wrong but this is why I was asking for more detail on the subject.

(the numbers are just for asking the question, I do not know the exact question yet)

If for example I want to react from the beginning (I guess scanline 0), scanline 100 and something around 200:

- How do I set those 3 irq
- when one is launched, how do I know which one of the 3 was triggered so I can do the proper action

Once I understand how this part work then the rest is just scrolling (scanline 0 and 100) and switching bank (scanline 200), which should not be that difficult and I should be careful about what you both mentioned.

Thank you again for the information on the subject.
User avatar
Bregalad
Posts: 8056
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: MM3 scanline counter, check multiple point possible and

Post by Bregalad »

Banshaku wrote: If for example I want to react from the beginning (I guess scanline 0), scanline 100 and something around 200:

- How do I set those 3 irq
- when one is launched, how do I know which one of the 3 was triggered so I can do the proper action
I've never used MMC3's scanline counter, but I'll answer what I'd do. You don't set 3 IRQs but 2 (at line 100 and 200), knowing you already have good old NMI at line 240 as usual. You don't set multiple IRQs simultaneously (that's not possible) but each IRQ is set in the previous IRQ, or in the VBlank NMI for the 1st one. In this particular case, you need to set IRQ for line 100 in the VBlank NMI, and you need to set the IRQ for line 200 in the IRQ for line 100. Just remember the # of lines to count will still be "100" obviously (or maybe 99 or something like that); because you have to use the # of scalnine to wait and not the total # of scanline since VBlank (on MMC3 - only MMC5 has an internal scanline counter, and as such always uses absolute number for scanlines instead of relative numbers like other mappers).

When having more than one IRQ per frame you need to build a simple state machine to know what you're doing. In a typical MMC3 game I'd assume there's several kinds of IRQ anyway (title screen, cutscene, gameplay, ending, whathever...) and you'll need to differenciate from them as well, to differentiate beween IRQ #1 and IRQ #2 of the cutscene would be pretty much the same mechanic.

Also you could just as well mix IRQs with good old syncronisation methods that needs no specific hardware, although there's no reason to do that other than to avoid the state machine, which is in itself a valid reason if you feel lazy (who doesn't). Just use a fixed-time loop or a sprite-zero hit to wait between scanline 100 and scanline 200; or to wait between the end of VBlank NMI until scanline 100, or whathever you feel like doing. It's all up to you.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: MM3 scanline counter, check multiple point possible and

Post by tokumaru »

Bregalad wrote:Nope in many cases when changing vertical scroll only (and in this case most specifically) just $2006/$2006 will be enough.
Nope, because the first $2006 write clears the topmost fine Y scroll bit. Just $2006 will allow you to scroll to rows 0-3 of a tile, but if you want the full range, you need the $2006/5/5/6 trick.
User avatar
za909
Posts: 249
Joined: Fri Jan 24, 2014 9:05 am
Location: Mijn hart woont al in Nederland

Re: MM3 scanline counter, check multiple point possible and

Post by za909 »

If you have a different IRQ system for different parts of your game it is pretty useful to set up multiple IRQ handlers in software by pointing the IRQ vector at RAM, where you place a JMP absolute (hex: $4C) instruction when initializing the console, and then the two byts after it will be used as the pointer to the IRQ handler currently needed. This provides some more flexibility at the cost of a 3 CPU cycle delay for all your IRQ handlers. Or if you need many IRQs you can keep count of your IRQs for the current frame and then use it as an index to fetch the next IRQ counter value from a table. Although I personally use the DMC IRQ, the principle is the same... all the stages have different split points, so I have an array of arrays containing screen split timings.
User avatar
Banshaku
Posts: 2417
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: MM3 scanline counter, check multiple point possible and

Post by Banshaku »

I'm already using custom NMI and change the address in ram when a new one is necessary. I was expecting to do the same for IRQ too.

One idea I have after reading this thread (but I'm not sure if this is appropriate or not is):

- First trigger is NMI for top scroll
- from NMI, update IRQ handler for phase 1 and request IRQ for 100
- inside phase 1 IRQ, update IRQ handler for phase 2 then request IRQ for next step

I'm not sure if changing handler inside IRQ is a common practice but usually I try to avoid issue by first putting RTI opcode at the IRQ address location then change irq_adr+1 first then irq_adr.

I guess for now the best thing would be to try it ^^;;; The only thing is since I need to scroll one from the left and the other part from right, I think that seems to imply that the screen will requires to be split in 2 and set in different nable table to achieve this effect, so they can "reconnect" to make the main screen.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: MM3 scanline counter, check multiple point possible and

Post by tokumaru »

Banshaku wrote:I'm not sure if changing handler inside IRQ is a common practice but usually I try to avoid issue by first putting RTI opcode at the IRQ address location then change irq_adr+1 first then irq_adr.
The IRQ handler is indeed the best place to set the address of the next handler. You don't even have to replace the JMP with an RTI before changing the address, since the I flag (which gets set when an IRQ fires) will prevent other IRQs from firing, so there's absolutely no chance of an IRQ firing while you're changing the address.
User avatar
Banshaku
Posts: 2417
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: MM3 scanline counter, check multiple point possible and

Post by Banshaku »

I see. So chaining that way seems the simplest to manage states and IRQ is not triggered. I was not aware of that.

I just erased the rest of my post content because I just realized that I read "presumably at PPU cycle 260 of the current scanline" has " presumably at PPU scanline 260", which makes a hell of a difference. I hate to be sleep deprived ^^;;;;
User avatar
Bregalad
Posts: 8056
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: MM3 scanline counter, check multiple point possible and

Post by Bregalad »

tokumaru wrote:Nope, because the first $2006 write clears the topmost fine Y scroll bit. Just $2006 will allow you to scroll to rows 0-3 of a tile, but if you want the full range, you need the $2006/5/5/6 trick.
I don't think he wants to scroll vertically, but just show some fixed text on the bottom so he can do that with $2006 only; the top part is what scrolls and he can do that with $2005 normally.

Also the RAM trick is cool, but you can also use JMP (indirect) as an alternative. Replacing the JMP instruciton in RAM ($4c) by an RTI is an awful idea for IRQs, as if an IRQ effectively fires and goes to a RTI instruction, it will re-fire again immediately, and so on infinitely, crashing the program, so it's the almost same effect as jumping to an invalid address basically. It's best to be sure the I flag is set when modifying the adress; either that or just rely on proper timing so we're sure no IRQ fires when changing the address (sure this is "bad practice" (tm) but so is a lot of NES coding standard practices).
User avatar
Banshaku
Posts: 2417
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: MM3 scanline counter, check multiple point possible and

Post by Banshaku »

@Bregalad,

the first animation is separated in 3 and requires 2 scroll (top part comes from left, middle one from right, bottom one doesn't move).

The second animation is a screen separated in 2 section:

- the top part is a viewport, let say of a height of 150 pixel, that scroll an image vertically (image height of 300 pixel)
- the bottom part is static and show some text while the viewport scroll an image

I guess without seeing a concept art it is difficult to visualise. Hopefully by saying viewport it's make it a little bit clearer.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: MM3 scanline counter, check multiple point possible and

Post by tokumaru »

Bregalad wrote:I don't think he wants to scroll vertically, but just show some fixed text on the bottom so he can do that with $2006 only; the top part is what scrolls and he can do that with $2005 normally.
You're right. For some reason I thought the vertical scrolling part was in the middle of a 3-part screen, but I see now that's it's the very first part. So yeah, you can do the fixed part below using just $2006.
you can also use JMP (indirect) as an alternative.
This looks cleaner, but is also 2 cycles slower.
Replacing the JMP instruciton in RAM ($4c) by an RTI is an awful idea for IRQs, as if an IRQ effectively fires and goes to a RTI instruction, it will re-fire again immediately, and so on infinitely, crashing the program, so it's the almost same effect as jumping to an invalid address basically.
You're right. I've seen this technique bring used for NMIs, but for IRQs it indeed doesn't make much sense.
User avatar
Banshaku
Posts: 2417
Joined: Tue Jun 24, 2008 8:38 pm
Location: Japan
Contact:

Re: MM3 scanline counter, check multiple point possible and

Post by Banshaku »

oh. So this old code is better be used for NMI only?

Code: Select all

;->BEGIN----------------------------------------------------------------------
; Generate dynamic code in memory for jump to function.
;
; Note: Before updating the code, the first opcode is set to RTI prevent
; 	   a call to an half updated address.
;
.macro setDynamicRtiFunc source, destination
	lda #OPCODE_RTI				; First disable it to make sure it's not called when
	sta destination				; updating address
	
	lda #<source				   ; Set address
	sta destination+1
	lda #>source
	sta destination+2
	
	lda #OPCODE_JMP				; Then set back the jump instruction
	sta destination	
.endmacro
;-<END------------------------------------------------------------------------
I didn't try dynamic RTI yet but I was expecting to use the same pattern.
Post Reply