Convert 16-bit address to banked ram address (and back)
Posted: Wed Apr 16, 2025 6:00 am
I needed a system of addressing some banks in high RAM as though they were one continuous block of memory, and here's what I came up with. The following two subroutines will take a 16-bit "virtual" address and convert it to the appropriate bank number and windowed address (i.e., between A000..BFFF), as well as the inverse operation.
Here's a bonus routine for increasing the MSB of the banked address by one, handling the wrapping from BFFF -> A000, and increasing the bank number. Use this when you want to carry into the MSB after manipulating the LSB.
Code: Select all
VirtualAddress_to_BankedAddress:
lda virtualAddressL
sta bankedAddressL
lda virtualAddressH
and #$E0 ; hhh00000
asl ; h <- hh000000
rol ; h <- h000000h
rol ; h <- 000000hh
rol ; 0 <- 00000hhh, clears carry
adc #DATA_BANK
sta bankedBank
lda virtualAddressH
and #$1F
ora #$A0
sta bankedAddressH
rts
Code: Select all
BankedAddress_to_VirtualAddress:
lda bankedAddressL
sta virtualAddressL
lda bankedBank
sec
sbc #DATA_BANK ; 00000hhh
lsr ; 000000hh -> h
ror ; h000000h -> h
ror ; hh000000 -> h
ror ; hhh00000 -> 0
eor bankedAddressH ; hl hl hl l l l l l
and #$E0 ; hl hl hl 0 0 0 0 0
eor bankedAddressH ; h h h l l l l l
sta virtualAddressH
rts
Code: Select all
BankedAddress_IncreaseMSB:
inc bankedAddressH
; The 3 MSBs are usually 101, but become 110 when we advance to Cxxx.
bit bankedAddressH
bvc :+
; Wrap from BFFF -> A000 and increase RAM bank.
lda #$A0
sta bankedAddressH
inc bankedBank
:
rts