(Homebrew) Help with ASM6! Also horizontal blanking help!

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
Yoshimaster96
Posts: 16
Joined: Sat Jan 09, 2016 5:30 pm

(Homebrew) Help with ASM6! Also horizontal blanking help!

Post by Yoshimaster96 »

When compiling my source code, I end up with a "Value out of range." error for banks 1 through 29 of my NES homebrew game

Code: Select all

pass 1..
pass 2..
PRG/PRG01.asm(1): Value out of range.
PRG/PRG02.asm(1): Value out of range.
PRG/PRG03.asm(1): Value out of range.
PRG/PRG04.asm(1): Value out of range.
PRG/PRG05.asm(1): Value out of range.
PRG/PRG06.asm(1): Value out of range.
PRG/PRG07.asm(1): Value out of range.
PRG/PRG08.asm(1): Value out of range.
PRG/PRG09.asm(1): Value out of range.
PRG/PRG10.asm(1): Value out of range.
PRG/PRG11.asm(1): Value out of range.
PRG/PRG12.asm(1): Value out of range.
PRG/PRG13.asm(1): Value out of range.
PRG/PRG14.asm(1): Value out of range.
PRG/PRG15.asm(1): Value out of range.
PRG/PRG16.asm(1): Value out of range.
PRG/PRG17.asm(1): Value out of range.
PRG/PRG18.asm(1): Value out of range.
PRG/PRG19.asm(1): Value out of range.
PRG/PRG20.asm(1): Value out of range.
PRG/PRG21.asm(1): Value out of range.
PRG/PRG22.asm(1): Value out of range.
PRG/PRG23.asm(1): Value out of range.
PRG/PRG24.asm(1): Value out of range.
PRG/PRG25.asm(1): Value out of range.
PRG/PRG26.asm(1): Value out of range.
PRG/PRG27.asm(1): Value out of range.
PRG/PRG28.asm(1): Value out of range.
PRG/PRG29.asm(1): Value out of range.
Here are a few source files:

MAIN.asm

Code: Select all

.include INES.inc

.include PRG/PRG00.asm
.include PRG/PRG01.asm
.include PRG/PRG02.asm
.include PRG/PRG03.asm
.include PRG/PRG04.asm
.include PRG/PRG05.asm
.include PRG/PRG06.asm
.include PRG/PRG07.asm
.include PRG/PRG08.asm
.include PRG/PRG09.asm
.include PRG/PRG10.asm
.include PRG/PRG11.asm
.include PRG/PRG12.asm
.include PRG/PRG13.asm
.include PRG/PRG14.asm
.include PRG/PRG15.asm
.include PRG/PRG16.asm
.include PRG/PRG17.asm
.include PRG/PRG18.asm
.include PRG/PRG19.asm
.include PRG/PRG20.asm
.include PRG/PRG21.asm
.include PRG/PRG22.asm
.include PRG/PRG23.asm
.include PRG/PRG24.asm
.include PRG/PRG25.asm
.include PRG/PRG26.asm
.include PRG/PRG27.asm
.include PRG/PRG28.asm
.include PRG/PRG29.asm
.include PRG/PRG30.asm
.include PRG/PRG31.asm

.incbin CHR/CHR.bin
INES.inc

Code: Select all

.db $4E,$45,$53,$1A,$10,$10,$4A,$00,$00,$00,$00,$00,$00,$00,$00,$00
PRG/PRG00.asm

Code: Select all

.org $8000
.dw BitmapLogo,BitmapTitle,BitmapFileSel,$0000
.dw BitmapBonus,BitmapCredits,BitmapGameOver,BitmapDebug

BitmapLogo:
.incbin PRG/BMP/BMP0A.bin
.incbin PRG/BMP/BMP0B.bin

BitmapTitle:
.incbin PRG/BMP/BMP1A.bin
.incbin PRG/BMP/BMP1B.bin

BitmapFileSel:
.incbin PRG/BMP/BMP2A.bin
.incbin PRG/BMP/BMP2B.bin

BitmapBonus:
.incbin PRG/BMP/BMP4A.bin
.incbin PRG/BMP/BMP4B.bin

BitmapCredits:
.incbin PRG/BMP/BMP5A.bin
.incbin PRG/BMP/BMP5B.bin

BitmapGameOver:
.incbin PRG/BMP/BMP6A.bin
.incbin PRG/BMP/BMP6B.bin

BitmapDebug:
.incbin PRG/BMP/BMP7A.bin
.incbin PRG/BMP/BMP7B.bin
PRG/PRG01.asm (also for banks 2-23)

Code: Select all

.org $8000
PRG/PRG24.asm (also for banks 25-29)

Code: Select all

.org $A000
How can any value be out of range if there is no code?

~~~~~~~~~~~~~~~~

Regarding horizontal blanking, I want to split the screen at a certain scanline to draw the HUD. How do I detect horizontal blanking events?
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: (Homebrew) Help with ASM6! Also horizontal blanking help

Post by tokumaru »

You can't .org to an address lower than the current PC. To roll back the PC you need to use .base instead.

EDIT: check out my ASM6 templates to see how you can begin every bank with .base and pad them with .org.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: (Homebrew) Help with ASM6! Also horizontal blanking help

Post by tokumaru »

Yoshimaster96 wrote:Regarding horizontal blanking, I want to split the screen at a certain scanline to draw the HUD. How do I detect horizontal blanking events?
Horizontal blanking is the tiny amount of time between scanlines when the PPU is not rendering pixels. Mid-screen effects (such as scroll splits) should happen during that time to avoid visual glitches, but a greater understanding of the various tasks the PPU performs during hblank is useful for you to know when exactly it's safe to perform each of the various types of raster effects.

The NES doesn't offer any built-in methods of counting hblanks. The closest thing the NES has is the sprite 0 hit: when a solid pixel of sprite 0 overlaps a solid pixel of the background, the sprite 0 hit flag gets set, so if you wait for this flag to change in a loop you can detect when the PPU reaches a specific point of the screen. You can only use it once per frame, and you have to be actively watching the flag, so this is far from ideal.

Another option is timed code. Since each CPU cycle takes the same amount of time the PPU needs to display 3 pixels (in NTSC), you can write code that takes a known amount of cycles in order to wait a known amount of scanlines. The problem is that this uses 100% of your CPU time, so you can't really use this for games.

If you need complete control over the scanlines you need a mapper with scanline IRQs, such as the MMC3. You can program the MMC3 to "fire an IRQ X scanlines from now", so you can safely go back to running the game code and the mapper will let you know when the scanline is reached via an interrupt.
Yoshimaster96
Posts: 16
Joined: Sat Jan 09, 2016 5:30 pm

Re: (Homebrew) Help with ASM6! Also horizontal blanking help

Post by Yoshimaster96 »

tokumaru wrote:
Yoshimaster96 wrote:Regarding horizontal blanking, I want to split the screen at a certain scanline to draw the HUD. How do I detect horizontal blanking events?
Horizontal blanking is the tiny amount of time between scanlines when the PPU is not rendering pixels. Mid-screen effects (such as scroll splits) should happen during that time to avoid visual glitches, but a greater understanding of the various tasks the PPU performs during hblank is useful for you to know when exactly it's safe to perform each of the various types of raster effects.

The NES doesn't offer any built-in methods of counting hblanks. The closest thing the NES has is the sprite 0 hit: when a solid pixel of sprite 0 overlaps a solid pixel of the background, the sprite 0 hit flag gets set, so if you wait for this flag to change in a loop you can detect when the PPU reaches a specific point of the screen. You can only use it once per frame, and you have to be actively watching the flag, so this is far from ideal.

Another option is timed code. Since each CPU cycle takes the same amount of time the PPU needs to display 3 pixels (in NTSC), you can write code that takes a known amount of cycles in order to wait a known amount of scanlines. The problem is that this uses 100% of your CPU time, so you can't really use this for games.

If you need complete control over the scanlines you need a mapper with scanline IRQs, such as the MMC3. You can program the MMC3 to "fire an IRQ X scanlines from now", so you can safely go back to running the game code and the mapper will let you know when the scanline is reached via an interrupt.
My game uses MMC3, so that'd work! How would I go about it?
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: (Homebrew) Help with ASM6! Also horizontal blanking help

Post by tokumaru »

I don't remember the specifics (better check the mapper's page in the wiki and debug some MMC3 games to see how they write to the IRQ registers), but I believe you just write the number of scanlines to count to $c000, then write to $c001 to reload this value, and finally to $e001 to enable IRQs. IRQs must also be enabled on the 6502 (i.e. the I flag must be cleared). Then, in the NMI handler, you put the code that will do the scroll split itself.
User avatar
dougeff
Posts: 3079
Joined: Fri May 08, 2015 7:17 pm

Re: (Homebrew) Help with ASM6! Also horizontal blanking help

Post by dougeff »

So, keep in mind, the IRQ triggers right at the end of the rendering of a line. You are already in Hblank, and don't have enough time to do anything useful to the PPU, except maybe a $2000 write, or maybe 1 scroll write, X only (you could do a second write to $2005, but that write will not work, for reasons I don't fully understand).

So, if you want to time a complete scroll shift, you need to set your scanline count to 1 less than you want...do a very short timed wait, then do the weird $2006,$2005,$2005,$2006 write, at exactly the correct moment, and you can achieve a glitch free X/Y scroll shift.

Sorry, if that's too complicated.

EDIT-
I more common method, in real games, is to do the scroll shifts in areas of the screen that have flat colors all the way across (through both nametables). Then you could poorly time an X scroll shift and it is still glitch free.

EDIT2 - example, Megaman 5
https://www.youtube.com/watch?v=FMRHYGTFQsQ

Look at exactly 22:26. The screen splits where there is several completely gray scanlines.
nesdoug.com -- blog/tutorial on programming for the NES
Yoshimaster96
Posts: 16
Joined: Sat Jan 09, 2016 5:30 pm

Re: (Homebrew) Help with ASM6! Also horizontal blanking help

Post by Yoshimaster96 »

After the following subroutine is called:

Code: Select all

EnableHUD:
	lda #$C0
	sta $C000
	sta $C001
	sta $E001
	rts
There is no split scrolling. The HUD should start on row 192 on screen. The HUD starts on row 192 of the bottom left nametable (0x2800). The game has 4-screen scrolling.

Here is the NMI routine:

Code: Select all

NMI:
	lda #$08
	sta $2006
	lda #$00
	sta $2005
	sta $2005
	sta $2006
	rti
And the IRQ routine:

Code: Select all

Interrupt:
	rti
Post Reply