It is currently Tue Dec 18, 2018 6:40 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 13 posts ] 
Author Message
PostPosted: Mon Dec 03, 2018 1:31 am 
Offline

Joined: Sat May 26, 2018 6:14 am
Posts: 57
Location: Italy
Hello to everyone, I'm working on my NES game every weekend, and everytime I discover a new limit on this machine :P. This time the compiler ( NESASM ) give me this error "Bank overflow, offset > $1FFF!". I supposed it depend on how many code I write in a single bank. So my question is, how can I organize my files to continue to write code for my game? What's the code limit that I can write? And, if I get the Bank Overflow error, how can I add more bank for my code?

This code show how I organized my code ( I take it from another opensource project ), but I can't understard how to add more banks and if I can add more banks to my code.

Thanks a lot!

Code:
;; NES HEADERS
  .inesprg 1 ; 1x 16KB PRG code
  .ineschr 1 ; 1x  8KB CHR data
  .inesmap 0 ; mapper 0 = NROM, no bank swapping
  .inesmir 1 ; background mirroring

;; Constants and Variables
  .include "Macros.asm"
  .include "MacrosPlayer.asm"
  .include "EnemiesManager2.asm"
  .include "Variables.asm"
  .include "Constants.asm"

;; Code starting point
  .bank 0
  .org $C000

;; RESET Routine. Initialize Title, clear NMI ready flag
  .include "Reset.asm"
 
;; MAIN LOOP
MainLoop:
  .include "ReadControllers.asm"
  .include "GameEngine.asm"

  lda #READY       ;frameready is now set to 1. This will Allow NMI to Draw To Screen
  sta FRAME_READY

WaitForNMI:       ;Allow NMI to complete one pass before Starting Main Loop again. This ensure no game logic will happen during NMI while its writing.
  lda FRAME_READY ;01
  cmp #READY      ;01
  beq WaitForNMI  ;Since both frameready and READY are 01 this will loop back to WaitForNMI until NMI clears the frameready flag.

  jmp MainLoop     ;jump back to MainLoop, infinite loop

; The NMI
  .include "NMI.asm"

; Load Title Screen
  .include "StartTitleScreen.asm"
; Update Title Screen
  .include "UpdateTitleScreen.asm"

; Load Gameplay Screen
  .include "StartGamePlay.asm"
; Update Gameplay
  .include "UpdateGamePlay.asm"

;; data tables
  .bank 1
  .org $E000
  ; Subroutines
  ;.include "BackgroundUpdater.asm"
  .include "EnemyAnimationRoutines.asm"
  .include "PlayerManager.asm"
  ;.include "EnemiesManager.asm"
  .include "GameplayManager.asm"
 
  .include "Graphics.asm"
 

;;;;; The Vectors

  .org $FFFA      ;first of the three vectors starts here
  .dw NMI         ;when an NMI happens (once per frame if enabled) the
                  ;processor will jump to the label NMI:
  .dw RESET       ;when the processor first turns on or is reset, it will jump
                  ;to the label RESET:
  .dw 0

  .bank 2
  .org $0000
  .incbin "ShootingLikeAStar.chr"   


Top
 Profile  
 
PostPosted: Mon Dec 03, 2018 2:22 am 
Offline
User avatar

Joined: Tue Jun 24, 2008 8:38 pm
Posts: 2131
Location: Fukuoka, Japan
I didn't use nesasm for ages so I guess I should wait for people that know more about it but I will try to guess :lol:

First, I would try to run it with -S to have more information about how banks are used. This should help find issue and check where things are allocated. My guess would be that you have include set before .bank 0 so I would be concerned where the code ends up. This could be one possible cause of issue.

I'm just guessing here so I will let people with more knowledge answer properly. -S should be a good start for debugging, at the least.


Top
 Profile  
 
PostPosted: Mon Dec 03, 2018 2:34 am 
Offline

Joined: Sat May 26, 2018 6:14 am
Posts: 57
Location: Italy
I deleted a lot of old code, so now it compile without problem. Btw I have this:

Code:
segment usage:

      ZP    -
     BSS    -
                USED/FREE
BANK   0                            2806/5386
BANK   1                            7039/1153
BANK   2                            8192/   0
                ---- ----
                  18K   6K


Bank overflow can depend on compiler? If I switch on another compiler this can be fixed?

Thanks!


Top
 Profile  
 
PostPosted: Mon Dec 03, 2018 2:52 am 
Offline
User avatar

Joined: Tue Jun 24, 2008 8:38 pm
Posts: 2131
Location: Fukuoka, Japan
Yes and no. In the case of nesasm, banks are sized in 8k chunks which means once the bank has more than 8k, it will overflow. In another assembler, banks size could be set differently and the assembler would warn you when they overflow at that specific size.

- Bank 0 now seems to have only 2.8k so it won't overflow right away
- bank 1 has 7k used so my guess you removed some code in that bank and now it works
- bank 2, my guess it's the chr bank and it completely used

The error was a little bit cryptic, making it hard to understand where it overflowed. Next time you have this issue, the -S option should help you figure out where you are getting issue or getting tight in space ;)


Top
 Profile  
 
PostPosted: Mon Dec 03, 2018 3:11 am 
Offline

Joined: Sat May 26, 2018 6:14 am
Posts: 57
Location: Italy
Ok thanks! My question is: Can I add a "bank 3" and add 8k for my code? :)


Top
 Profile  
 
PostPosted: Mon Dec 03, 2018 3:57 am 
Offline

Joined: Tue Feb 27, 2018 10:41 am
Posts: 20
Location: Brazil
kikutano wrote:
Ok thanks! My question is: Can I add a "bank 3" and add 8k for my code? :)

It's depends entirely on the mapper you're using.
For NROM (mapper 0) there's a limit of 32KiB of PRG ROM and 8Kib of CHR ROM, so you can change your header to
Code:
.inesprg 2 ; 2x 16KB PRG code

If you need more CHR space, you need to use another mapper with bigger CHR ROM space (like CNROM) or switch to CHR RAM.


Top
 Profile  
 
PostPosted: Mon Dec 03, 2018 4:08 am 
Offline

Joined: Sat May 26, 2018 6:14 am
Posts: 57
Location: Italy
NOOPr wrote:
kikutano wrote:
Ok thanks! My question is: Can I add a "bank 3" and add 8k for my code? :)

It's depends entirely on the mapper you're using.
For NROM (mapper 0) there's a limit of 32KiB of PRG ROM and 8Kib of CHR ROM, so you can change your header to
Code:
.inesprg 2 ; 2x 16KB PRG code

If you need more CHR space, you need to use another mapper with bigger CHR ROM space (like CNROM) or switch to CHR RAM.


Ok thanks! For now I'm adding bank in this way:

Code:
.bank 0
.org $C000

....

.bank 1
.org $E000

....

.bank 2
  .org $0000

....

.bank 3
  .org $A000



And it's working, I've t read how to use new mappers to use more memory as you linked. But NES can only load 256 tiles per time right? And 256 for the background? So the entire graphics of a level should be on 8k?

Thanks!


Top
 Profile  
 
PostPosted: Mon Dec 03, 2018 5:28 am 
Offline

Joined: Tue Feb 27, 2018 10:41 am
Posts: 20
Location: Brazil
The NES can hold only 8Kib of CHR at a time. Since each tile is 16 bytes, you have a total of 512 tiles distributed on 2 pattern tables: named left and right, each with 256 tiles.
You choose which one will serve background or sprites by setting the bits 3 and 4 of the PPUCTRL register.
Depending on the mapper, you can have more than one page of CHR tiles, and you can do a bankswitch to switch to another page in the middle of a rendering if you want.
So, let's say that you need to draw a background with 512 tiles, the first 15 rows of you name table use all tiles of a CHR page and the other 15 rows use the tiles of another page. You can use some technique to detect witch scanline is rendering (like a sprite 0 hit) and then banckswitch to the desired CHR page in the middle of the screen.


Top
 Profile  
 
PostPosted: Mon Dec 03, 2018 5:38 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11015
Location: Rio de Janeiro - Brazil
It should actually be:

Code:
.bank 0
.org $8000
....
.bank 1
.org $A000
....
.bank 2
.org $C000
....
.bank 3
.org $E000
....
.bank 4 ;this is the CHR bank now!
.org $0000

You can't mix PRG and CHR banks, you have to define all PRG banks first, and then all CHR banks. Also, you can't have non-power-of-two ROM sizes such as 24KB of PRG-ROM (i.e. 3 x 8K), so if you need more than 16KB you have to double it to the next power of 2, which is 32KB.

As for the graphics, yes, normally you'd use only 8KB worth of tiles at a time, but there are a few ways to break that limitation. Games with CHR-RAM can rewrite tiles as levels go, and games with fine CHR-ROM bankswitching will often switch tiles every frame to animate the background and/or the main character. Some games even switch tiles mid-frame in order to draw status bars or text boxes.

You should play a few games in Mesen or FCEUX with the tile viewer open to see how the pattern tables change as things happen.


Top
 Profile  
 
PostPosted: Mon Dec 03, 2018 10:31 am 
Offline

Joined: Sat May 26, 2018 6:14 am
Posts: 57
Location: Italy
Ok thanks a lot! :)


Top
 Profile  
 
PostPosted: Tue Dec 04, 2018 1:34 am 
Offline

Joined: Sat May 26, 2018 6:14 am
Posts: 57
Location: Italy
Just another couple of questions, I'm looking to optimize my code size so I want to know:

1. I should prefer subroutines instead of macros? Macro duplicate the code meanwhile the jmp subroutine is just a jump and return? For example I've this macros:

Code:
MACRO_INC .macro
  lda \1
  clc
  adc \2
  sta \1
  .endm

MACRO_DEC .macro
  lda \1
  sec
  sbc \2
  sta \1
  .endm


And they now occupy something like 100 byte in my code. Should I prefer to use jsr?

2. The size of the code depend on the name lenght of variables and label? Or that's optimized by the compiler? Forse example I should use ShortLabel: instead of VeryLongLongClearlyLabel:?

Thanks! :)


Top
 Profile  
 
PostPosted: Tue Dec 04, 2018 1:49 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11015
Location: Rio de Janeiro - Brazil
kikutano wrote:
1. I should prefer subroutines instead of macros?

That depends. Like you said, every time you use a macro, all of it's contents are written to the ROM (takes more space but is faster), while a subroutine only appears once in the ROM and is called from multiple places (takes less space but is slower). Whether you should go with macros or subroutines for specific tasks depends on how much ROM space you can spare and how fast you need the tasks to be. In assembly there's a constant battle between size and speed, and it's up to you to decide how to allocate your resources.

Quote:
Code:
MACRO_INC .macro
  lda \1
  clc
  adc \2
  sta \1
  .endm

MACRO_DEC .macro
  lda \1
  sec
  sbc \2
  sta \1
  .endm

These are OK as macros, but they'd make terrible subroutines! You'd have to pass the addresses of the variables to change as parameters and use indirection to access them, making an otherwise simple task needlessly complicated and slow.

Quote:
And they now occupy something like 100 byte in my code. Should I prefer to use jsr?

Not in this specific case, no. Subroutines aren't normally used for tiny tasks like these, specially if passing the required parameters requires so much time and space that it basically negates the benefits of using a subroutine.

Quote:
2. The size of the code depend on the name lenght of variables and label?

No. Label names are just for us humans, when the assembler generates the binary code it only uses the addresses associated with those labels, the names are discarded and do not impact the final code size at all.


Top
 Profile  
 
PostPosted: Tue Dec 04, 2018 8:19 am 
Offline

Joined: Sat May 26, 2018 6:14 am
Posts: 57
Location: Italy
Thanks again! :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 13 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group