Jump to content

Photo

Atari Bank Switching for Dummies

Bank Switching

9 replies to this topic

#1 Thomas Jentzsch OFFLINE  

Thomas Jentzsch

    Thrust, Jammed, SWOOPS!, Boulder Dash, THREE·S, Star Castle

  • 23,938 posts
  • Always left from right here!
  • Location:Düsseldorf, Germany, Europe, Earth

Posted Tue Dec 11, 2018 2:57 AM

Atari's bank switching (F8, F6, F4) is pretty straight forward. Nevertheless it can become quite complicated if you want to switch between banks a lot. Therefore I wrote myself some macros, which make things much easier.

 

Here is the basic version, just to get the idea:

; TJ's Atari standard bankswitching macros, here tailored for F4 (adapt for F8 or F6)
BANK_SIZE = $1000

; Use at the start of each bank, required by JMP_LBL macro
  MAC START_BANK ; bank number
BANK_NUM    SET {1}
BANK_ORG    SET $8000 + BANK_NUM*BANK_SIZE
BANK_RORG   SET $1000 + BANK_NUM*BANK_SIZE*2
    SEG     code
    ORG     BANK_ORG, $55
    RORG    BANK_RORG
    ECHO    "Start of bank", [BANK_NUM]d, ", ORG", BANK_ORG, ", RORG", BANK_RORG

; verify start addresses:
START{1} = (START & $fff) | BANK_RORG
    ; optional Space for RAM+
;    DS.B    $100, "#"
  ENDM
 
; a convenience macro, put at the end of every bank
  MAC END_BANK 
   RORG $ff4
    ds      8, 0 ; 
    .word   (START & $fff) | BANK_RORG  ; RESET
    .word   0                           ; BRK (unused)
  ENDM

; Insert code for executing the bankswitch,
; should be put at the very end of each bank, right before the hotspots
  MAC SWITCH_BANK
    ORG     BANK_ORG + $ff4 - BANKSWITCH_SIZE
    RORG    BANK_RORG + $ff4 - BANKSWITCH_SIZE

SwitchBank  = (. & $fff) | $1000
    pha
    txa
    pha
    lda     $fff4,y
    rts

BANKSWITCH_SIZE = ((. & $fff) | $1000) - SwitchBank
  ENDM

; Define a label which can be used by JMP_LBL macro
;Example:
;    DEF_LBL Foo
  MAC DEF_LBL ; address
{1}
{1}_BANK    = BANK_NUM
  ENDM

; Jump to a label in other or same bank. The assembler will take care if the
; code has to bankswitch or not.
; Example:
;    JMP_LBL Foo
  MAC JMP_LBL ; address
   IF {1}_BANK != BANK_NUM      ; convenience IF :)
    ldy     #{1}_BANK
    lda     #>({1}-1)
    ldx     #<({1}-1)
    jmp     SwitchBank          ; always at the same address in each bank
   ELSE
    jmp     {1}
   ENDIF
  ENDM 

So if you put these macros into your code and use DEF_LBL to define the labels you want to call, you can jump with JMP_LBL to these labels without having to care for bankswitching.

Disadvantages:

  • a bit slower than dedicated bank switching code 
  • uses A, X and Y registers, so you cannot transfer parameters (but with more code this can be reduced to one register).

BTW: This could be adapted to JSR calls to, but I never really needed those.


Edited by Thomas Jentzsch, Tue Dec 11, 2018 11:28 AM.


#2 Karl G ONLINE  

Karl G

    Dragonstomper

  • 734 posts

Posted Tue Dec 11, 2018 11:38 AM

Thank you for sharing these!



#3 BNE Jeff OFFLINE  

BNE Jeff

    Moonsweeper

  • 366 posts
  • Location:$5787

Posted Sun Dec 23, 2018 2:59 PM

Well I started out understanding none of this and now I think I understand about half of it.  Anybody care to check or correct my comments?

; TJ's Atari standard bankswitching macros, here tailored for F4 (adapt for F8 or F6)
BANK_SIZE = $1000	;j Define a constant,(4K bank size here)

; Use at the start of each bank, required by JMP_LBL macro
  MAC START_BANK ; bank number. j example: start each bank with with argument
					;j START_BANK 1, START_BANK 2, etc
BANK_NUM    SET {1}	;j Transfer the START_BANK argument to BANK_NUM
BANK_ORG    SET $8000 + BANK_NUM*BANK_SIZE ;j $8000 skips over the first potential 8
					;j (4K) banks then sets the start address (ORiGin) of the
					;j bank that was set in the argument.
BANK_RORG   SET $1000 + BANK_NUM*BANK_SIZE*2 ;j ??? If bank 2, for example, BANK_RORG
					;j would be $5000.  Why?
    SEG     code		;j Start the code segment
    ORG     BANK_ORG, $55	;j Put $55 at the start of a bank?
    RORG    BANK_RORG		;j Put the relocatable code in the calculated location?
    ECHO    "Start of bank", [BANK_NUM]d, ", ORG", BANK_ORG, ", RORG", BANK_RORG ;j print stuff

; verify start addresses:
START{1} = (START & $fff) | BANK_RORG ;j Define START of the bank as this location
					;j with the left nibble stripped off and replaced with the
					;j left nibble of BANK_RORG?
    ; optional Space for RAM+
;    DS.B    $100, "#"
  ENDM
 
; a convenience macro, put at the end of every bank
  MAC END_BANK 
   RORG $ff4
    ds      8, 0 ;j Put zeros in the last 8 bytes for the hot spots before the
			; reset and break vectors
    .word   (START & $fff) | BANK_RORG  ; RESET
    .word   0                           ; BRK (unused)
  ENDM

; Insert code for executing the bankswitch,
; should be put at the very end of each bank, right before the hotspots
  MAC SWITCH_BANK
    ORG     BANK_ORG + $ff4 - BANKSWITCH_SIZE ;j Calculate where the hot spots
											;j go in each bank
    RORG    BANK_RORG + $ff4 - BANKSWITCH_SIZE ;j Calculate where the hot spots
											;j go in the moveable code?

SwitchBank  = (. & $fff) | $1000 ;j take this location and replace the left 
								;j nibble with a 1?
    pha		;j MAC JMP_LBL jumps to here. The accumulator was loaded with one
    txa		;j nibble and x was loaded with the other.  Move it to the accumulator
    pha		;j so it can be pushed on the stack.  Setting up a return address.
    lda     $fff4,y	;j Load the accumulator with one of the hot spots, causing
			;j a bankswitch.
    rts		;j The bankswitch occurred, so this executes in the new bank
			;j The rts is to an address that was calculated in JMP_LBL

BANKSWITCH_SIZE = ((. & $fff) | $1000) - SwitchBank ;j Calculates the size of the
			;j SwitchBank code. Then take this address and limit it to a range of
			;j	%00001111 11111111 to
			;j	%00011111 11111111 .... Why the limit?
  ENDM

; Define a label which can be used by JMP_LBL macro
;Example:
;    DEF_LBL Foo	;j Insert this in the place where you want to be able to jump to.
  MAC DEF_LBL ; address	;j Figure out where we are.
{1}			;j Argument is Foo. Labels the code?
{1}_BANK    = BANK_NUM	;j Foo_BANK is the bank number we are currently in.
  ENDM

; Jump to a label in other or same bank. The assembler will take care if the
; code has to bankswitch or not.
; Example:
;    JMP_LBL Foo
  MAC JMP_LBL ; address
   IF {1}_BANK != BANK_NUM      ; convenience IF :) ;j If Foo_BANK is not current bank
    ldy     #{1}_BANK		;j Load y with the hot spot offset
    lda     #>({1}-1)		;j Load MSB of Foo's address
    ldx     #<({1}-1)		;j Load LSB of Foo's address
    jmp     SwitchBank          ; always at the same address in each bank
   ELSE		;j If we're already in the same bank
    jmp     {1}	;j then just jump Foo
   ENDIF
  ENDM 





#4 Thomas Jentzsch OFFLINE  

Thomas Jentzsch

    Thrust, Jammed, SWOOPS!, Boulder Dash, THREE·S, Star Castle

  • Topic Starter
  • 23,938 posts
  • Always left from right here!
  • Location:Düsseldorf, Germany, Europe, Earth

Posted Mon Dec 24, 2018 2:23 AM

 

Well I started out understanding none of this and now I think I understand about half of it.  Anybody care to check or correct my comments?

; TJ's Atari standard bankswitching macros, here tailored for F4 (adapt for F8 or F6)
BANK_SIZE = $1000	;j Define a constant,(4K bank size here)

; Use at the start of each bank, required by JMP_LBL macro
  MAC START_BANK ; bank number. j example: start each bank with with argument
					;j START_BANK 1, START_BANK 2, etc TJ: for F4 you should start with 0, else the following variables will overrun
BANK_NUM    SET {1}	;j Transfer the START_BANK argument to BANK_NUM
BANK_ORG    SET $8000 + BANK_NUM*BANK_SIZE ;j $8000 skips over the first potential 8
					;j (4K) banks then sets the start address (ORiGin) of the
					;j bank that was set in the argument.
BANK_RORG   SET $1000 + BANK_NUM*BANK_SIZE*2 ;j ??? If bank 2, for example, BANK_RORG
					;j would be $5000.  Why? TJ: Because we need an odd first nibble here
    SEG     code		;j Start the code segment
    ORG     BANK_ORG, $55	;j Put $55 at the start of a bank? TJ: This is the address of the bank in the ROM. These can be anything, but they must be consecutive overall. $55 is just redefining the default fill value for unused areas
    RORG    BANK_RORG		;j Put the relocatable code in the calculated location? TJ: The origin used by the code in this bank. Different origins per bank make debugging easier.
    ECHO    "Start of bank", [BANK_NUM]d, ", ORG", BANK_ORG, ", RORG", BANK_RORG ;j print stuff

; verify start addresses:
START{1} = (START & $fff) | BANK_RORG ;j Define START of the bank as this location
					;j with the left nibble stripped off and replaced with the
					;j left nibble of BANK_RORG? TJ: Startup address of the bank, this code just verifies that all banks use the place in their logical address space
    ; optional Space for RAM+
;    DS.B    $100, "#"
  ENDM
 
; a convenience macro, put at the end of every bank
  MAC END_BANK 
   RORG $ff4
    ds      8, 0 ;j Put zeros in the last 8 bytes for the hot spots before the
			; reset and break vectors
    .word   (START & $fff) | BANK_RORG  ; RESET
    .word   0                           ; BRK (unused)
  ENDM

; Insert code for executing the bankswitch,
; should be put at the very end of each bank, right before the hotspots
  MAC SWITCH_BANK
    ORG     BANK_ORG + $ff4 - BANKSWITCH_SIZE ;j Calculate where the hot spots
											;j go in each bank
    RORG    BANK_RORG + $ff4 - BANKSWITCH_SIZE ;j Calculate where the hot spots
											;j go in the moveable code? TJ: You have to update ORG and ROGR in pairs when using bankswitching, because they are different.

SwitchBank  = (. & $fff) | $1000 ;j take this location and replace the left 
								;j nibble with a 1? TJ: Just like START, this puts all bank switch code at the same spot in address space for each bank
    pha		;j MAC JMP_LBL jumps to here. The accumulator was loaded with one
    txa		;j nibble and x was loaded with the other.  Move it to the accumulator
    pha		;j so it can be pushed on the stack.  Setting up a return address.
    lda     $fff4,y	;j Load the accumulator with one of the hot spots, causing
			;j a bankswitch.
    rts		;j The bankswitch occurred, so this executes in the new bank
			;j The rts is to an address that was calculated in JMP_LBL

BANKSWITCH_SIZE = ((. & $fff) | $1000) - SwitchBank ;j Calculates the size of the
			;j SwitchBank code. Then take this address and limit it to a range of
			;j	%00001111 11111111 to
			;j	%00011111 11111111 .... Why the limit? TJ: The limit comes from the 4K address space we are using.
  ENDM

; Define a label which can be used by JMP_LBL macro
;Example:
;    DEF_LBL Foo	;j Insert this in the place where you want to be able to jump to.
  MAC DEF_LBL ; address	;j Figure out where we are.
{1}			;j Argument is Foo. Labels the code? TJ: Yes, required to have an address
{1}_BANK    = BANK_NUM	;j Foo_BANK is the bank number we are currently in.
  ENDM

; Jump to a label in other or same bank. The assembler will take care if the
; code has to bankswitch or not.
; Example:
;    JMP_LBL Foo
  MAC JMP_LBL ; address
   IF {1}_BANK != BANK_NUM      ; convenience IF :) ;j If Foo_BANK is not current bank
    ldy     #{1}_BANK		;j Load y with the hot spot offset
    lda     #>({1}-1)		;j Load MSB of Foo's address
    ldx     #<({1}-1)		;j Load LSB of Foo's address
    jmp     SwitchBank          ; always at the same address in each bank
   ELSE		;j If we're already in the same bank
    jmp     {1}	;j then just jump Foo
   ENDIF
  ENDM 

My comments above (TJ...)



#5 BNE Jeff OFFLINE  

BNE Jeff

    Moonsweeper

  • 366 posts
  • Location:$5787

Posted Sun Dec 30, 2018 9:01 AM

Thanks A lot! I think I understand enough of it to use it now



#6 KevKelley OFFLINE  

KevKelley

    Chopper Commander

  • 149 posts
  • Lots of hobbies, little time, loads of fun.
  • Location:Orlando

Posted Tue Jan 1, 2019 8:33 AM

Curious. I am still learning but Is there a method of getting the same amount pf space without bankswitching?

#7 Thomas Jentzsch OFFLINE  

Thomas Jentzsch

    Thrust, Jammed, SWOOPS!, Boulder Dash, THREE·S, Star Castle

  • Topic Starter
  • 23,938 posts
  • Always left from right here!
  • Location:Düsseldorf, Germany, Europe, Earth

Posted Tue Jan 1, 2019 8:38 AM

Sorry, I don't get your question. 



#8 KevKelley OFFLINE  

KevKelley

    Chopper Commander

  • 149 posts
  • Lots of hobbies, little time, loads of fun.
  • Location:Orlando

Posted Fri Jan 4, 2019 1:14 AM

Sorry. I was wondering if information can only be accessed in 4k increments or is there a way to have more without bankswitching?

Not sure if I am fully understanding it or not or if my question makes much sense at all...

#9 Thomas Jentzsch OFFLINE  

Thomas Jentzsch

    Thrust, Jammed, SWOOPS!, Boulder Dash, THREE·S, Star Castle

  • Topic Starter
  • 23,938 posts
  • Always left from right here!
  • Location:Düsseldorf, Germany, Europe, Earth

Posted Fri Jan 4, 2019 1:17 AM

The Atari can only access up to 4K ROM without bankswitching. If you need more ROM space you need bankswitching.



#10 KevKelley OFFLINE  

KevKelley

    Chopper Commander

  • 149 posts
  • Lots of hobbies, little time, loads of fun.
  • Location:Orlando

Posted Fri Jan 4, 2019 10:19 AM

Okay. Thanks. That's what I thought from all the reading but wasn't sure if I missed anything.





Also tagged with one or more of these keywords: Bank Switching

0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users