Convert 16-bit address to banked ram address (and back)

For posting library code and examples.
Post Reply
DragWx
Posts: 400
Joined: Tue Mar 07, 2023 9:07 pm

Convert 16-bit address to banked ram address (and back)

Post by DragWx »

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.

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
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

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
User avatar
desertfish
Posts: 1137
Joined: Tue Aug 25, 2020 8:27 pm
Location: Netherlands

Re: Convert 16-bit address to banked ram address (and back)

Post by desertfish »

clever use of BIT
cosmicr
Posts: 53
Joined: Tue Nov 14, 2023 4:29 am

Re: Convert 16-bit address to banked ram address (and back)

Post by cosmicr »

very cool, I'll have to take some time to understand it.

I wrote a similar routine for my AGI Interpreter, which needed to address memory up to 20-bits (1MB):

Code: Select all

; uses A, X, Y as 20-bit address into banked ram
.macro calc_bank_addr
   sta bank_temp   ; Store low byte of target address

   ; Calculate bank number (address/$2000)
   txa             ; Get middle byte
   lsr             ; Divide by 32 (8KB bank size)
   lsr 
   lsr
   lsr
   lsr
   sta $00         ; Store low bits of bank
   tya             ; Get high byte
   asl             ; Multiply by 8
   asl
   asl
   ora $00         ; Combine with low bits
   sta $00         ; Set final bank number

   ; Calculate address within bank window
   txa             ; Get middle byte back
   and #$1F        ; Mask for offset within bank
   ora #$A0        ; Add window base of $A000
   sta bank_temp+1 ; Store high byte of pointer
.endmacro

.proc read_bank_data
    calc_bank_addr

    ; Read the byte
    lda (bank_temp) ; Get byte from banked memory
    rts
.endproc

.proc write_bank_data  ; New write routine
    calc_bank_addr

    ; Write the byte
    lda bank_byte      ; Get byte to write
    sta (bank_temp)    ; Store byte to banked memory
    rts
.endproc
Mine uses very few cycles, but I'll have to compare it against yours!
Post Reply