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

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
(Homebrew) Help with ASM6! Also horizontal blanking help!
by on (#200603)
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:
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:
.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:
.db $4E,$45,$53,$1A,$10,$10,$4A,$00,$00,$00,$00,$00,$00,$00,$00,$00


PRG/PRG00.asm
Code:
.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:
.org $8000


PRG/PRG24.asm (also for banks 25-29)
Code:
.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?
Re: (Homebrew) Help with ASM6! Also horizontal blanking help
by on (#200616)
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.
Re: (Homebrew) Help with ASM6! Also horizontal blanking help
by on (#200621)
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.
Re: (Homebrew) Help with ASM6! Also horizontal blanking help
by on (#200641)
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?
Re: (Homebrew) Help with ASM6! Also horizontal blanking help
by on (#200652)
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.
Re: (Homebrew) Help with ASM6! Also horizontal blanking help
by on (#200653)
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.
Re: (Homebrew) Help with ASM6! Also horizontal blanking help
by on (#201548)
After the following subroutine is called:
Code:
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:
NMI:
   lda #$08
   sta $2006
   lda #$00
   sta $2005
   sta $2005
   sta $2006
   rti


And the IRQ routine:
Code:
Interrupt:
   rti