OK, I did some tests and IFNDEF doesn't work 100% (if you reference the label before the IFNDEF block it apparently is considered defined!), so I tried a different method of creating a virtual fixed bank, using macros instead of includes and the type of label assignment I used in ASM6 (
Label = *). Here's the basic template I made:
Code: Select all
.inesprg 4
.ineschr 0
.inesmap 7
.inesmir 0
;----------------------------------------------------------------
; CONSTANTS
;----------------------------------------------------------------
NAME_TABLE_A = %00000000
NAME_TABLE_B = %00001000
;----------------------------------------------------------------
; VARIABLES
;----------------------------------------------------------------
.rsset $000
NameTable .rs 1
FrameCounter .rs 1
;----------------------------------------------------------------
; MACRO: Selects a bank without affecting name table mirroring (A = bank index)
;----------------------------------------------------------------
SelectBank .macro
ora <NameTable
tax
lda BankswitchTable, x
sta BankswitchTable, x
.endm
;----------------------------------------------------------------
; MACRO: Selects a name table without switching banks (A = name table)
;----------------------------------------------------------------
SelectNameTable .macro
sta <NameTable
ora CurrentBank
tax
lda BankswitchTable, x
sta BankswitchTable, x
.endm
;----------------------------------------------------------------
; MACRO: Generates an instance of the virtual fixed bank
;----------------------------------------------------------------
GenerateFixedBank .macro
FixedBankStart\@: ;global label to isolate local labels inside
.org $ff00 ;this address should be adjusted according to the size of this repeated chunk
CallDoSomething = *
;remember the current bank
lda CurrentBank
pha
;select the function's bank and call it
lda #BANK(DoSomething) / 4
SelectBank
jsr DoSomething
;restore the previous bank and return
pla
SelectBank
rts
Reset = *
;initialize the name table
lda #NAME_TABLE_A
SelectNameTable
;switch to the bank that contains the initialization code and jump to it
lda #BANK(Initialize) / 4
SelectBank
jmp Initialize
NMI = *
;indicate that an NMI happened
inc <FrameCounter
;return
rti
IRQ = *
;return
rti
.CurrentBank:
;index of the current bank
.db BANK(.CurrentBank) / 4
CurrentBank = .CurrentBank ;make this address visible from the outside
BankswitchTable = *
;values used to avoid bus conflicts
.db $00, $01, $02, $03, $04, $05, $06, $07, $10, $11, $12, $13, $14, $15, $16, $17
;interrupt vectors
.org $fffa
.dw NMI
.dw Reset
.dw IRQ
FixedBankEnd\@: ;global label to isolate local labels inside
.endm
;----------------------------------------------------------------
; PRG-ROM
;----------------------------------------------------------------
.bank 0
.org $8000
Initialize:
sei
cld
;(INITIALIZATION CODE GOES HERE)
Forever:
;call a function in another bank
jsr CallDoSomething
;select name table B
lda #NAME_TABLE_B
SelectNameTable
;loop forever
jmp Forever
.bank 1
.org $a000
.bank 2
.org $c000
.bank 3
.org $e000
GenerateFixedBank
.bank 4
.org $8000
DoSomething:
;(THIS IS A FUNCTION IN ANOTHER BANK)
;return
rts
.bank 5
.org $a000
.bank 6
.org $c000
.bank 7
.org $e000
GenerateFixedBank
Note that while the mirroring can be changed from anywhere (since the bank doesn't change), changing banks can only be done from the fixed bank, so you need to create trampoline functions in the fixed bank for inter-bank calls, like the "CallDoSomething" I put in the template. You could also make a more complex, generic trampoline function that can call any address, as opposed to making individual trampolines for each function.
Another important detail about this template is that it uses the "all in main" approach to handling vblanks. The NMI simply changes a a variable, that you have to watch in the main loop in order to wait for vblank. This is a very newbie-friendly approach and I figured the template would look simpler with it, but you could also turn the NMI handler into a trampoline to a more specialized handler if you wanted to.
EDIT: Corrected a few mistakes in the code.