Jump to content
IGNORED

How to bankswitch with 32K


Propane13

Recommended Posts

Hi!

 

I want to make a demo, and I decided right off the bat to use 32K.

I am not using bAtari for this, so I need a quick refresher on how to do this in assembly.

 

On a 32K game with 8 banks, what do I need to do in order to swap between the 8 banks?

LDA $FFF<bank> or something?

 

Sorry for the easy question; there's a lot of discussion about different bankswitching methods in these forums, so searches are giving me lots of strange results.

I'm just interested in the old-fashioned LDA method, so I can get something working.

 

Any help would be appreciated.

Thanks!

-John

Link to comment
Share on other sites

That's a pretty wild table. I like it.

I tried fusing this code into Nick Bensema's "how to draw a playfield" code.

Seems that when I do this, I can't power up anymore-- I just get a black screen.

 

I think either this means I now need to pass a parameter to z26 (which is odd, because mm.bin does not need it), or that I missed something.

I have checked the code 3x, and am a little confused as to what I could have missed.

The macros are in each bank, and if I trace via start vector in any bank, it should jump to Bank8, at section Bank8Code.

So, am I missing something?

 

bob.zip

 

Thanks!

-John

Link to comment
Share on other sites

In bank 8 change the following:

	org $F100
...
org $FF00

 

to

	org $F100
rorg $F100
...
org $FF00
rorg $FF00

 

Stella's quite helpful in tracking issues like this down. I went into the debugger by hitting ~ and right away noticed that the CMP for bank 8 was followed by JMP $F030 instead of $F100 that I expected to see.

post-3056-1208123161_thumb.png

Link to comment
Share on other sites

  • 2 weeks later...

So, this framework is working great! My little project is coming along nicely.

I was thinking that eventually, I may want to give this thing a shot on real hardware.

To do that, I think I'll pick up a few of the "Atari 2600 8K/16K/32K PCB - Assembled w/Socket" boards from the Atariage store.

 

The exact item can be found here:

http://www.atariage.com/store/index.php?ma...products_id=218

 

The specs say that it supports standard "Atari F4 bankswitching". Is that what this method is called?

Is it called this because of the LDA $FF(F4) through FF(FB) loads that do the bankswitching?

 

I just don't want to mistakenly buy the wrong circuit board type.

 

Thanks!

-John

Link to comment
Share on other sites

Cool!

 

It's not the most efficient since the table has all jumps in every bank*, but I found it easy to understand.

 

I haven't bought any of those as I was able to get the Krokodile Cart, but you have to select the specific size you want(8K, 16K or 32K) in the drop-down when you order it.

 

And yep, 32K is F4. Here's a Bankswitching guide that covers the various methods.

 

* even though you're not going to jump from the Vertical Blank to the Over Scan, the bank with Vertical Blank code still has 6 bytes allocated for a jump to Over Scan.

Link to comment
Share on other sites

  • 3 months later...

So, I'm looking at taking this model, and shrinking it for 8K.

Problem is, bank 2 is booting fine. But, the jumps to Bank1 are failing.

 

Here's some code example.

 

 

;===================================
processor 6502
include vcs.h
;===================================

       MAC JUMP_TABLE ; put this at the start of every bank
       RORG $F000
Bank1
       cmp SelectBank1
       jmp Bank1Code
Bank2
       cmp SelectBank2
       jmp Bank2Code
       ENDM

;===================================

       MAC BANKS_AND_VECTORS ; put this at the end of every bank
       RORG $FFFA
SelectBank1 .byte $00
SelectBank2 .byte $00
;       .word Bank2 ; NMI and 8 overlap NMI
       .word Bank2 ; RESET
       .word Bank2 ; IRQ
       ENDM

;===================================

...



;#####################################################
; Bank 1 below
;#####################################################

org	$E000
JUMP_TABLE

org	$E100

Bank1Code ; i.e  GameInitBank1

...


;==============================
ORG $EFFA
BANKS_AND_VECTORS
;==============================

;#####################################################
; Bank 2 below
;#####################################################

org $F000
rorg $F000
JUMP_TABLE


org	$F100
rorg	$F100
      
Bank2Code

...


;==============================
ORG	$FFFA
BANKS_AND_VECTORS
;==============================

;	org	$FFFC
;	.word	Start
;	.word	Start

 

 

In Bank2, I have the following code:

 

GameCalcBank2
LDA	SWCHB
AND	#%00000011
EOR	#%00000011
BEQ	ConsoleSwitchNotHit
JMP	Bank1
ConsoleSwitchNotHit

 

 

From my perspective, everything looks the same as it did for the 32K version.

But, the behavior is weird. Bank 2 is fine (264 scanlines).

But, when I go to Bank1, it runs for 46 scanlines, and then jumps immediately back to bank 2.

That makes me think I'm going "out there" somewhere.

 

Is there something obviously wrong in the above framework?

I can post more code if necessary, but I thought I'd double-check my base bankswitch code first.

 

-John

Link to comment
Share on other sites

8K cartridges use F8 bankswitching, the hotspots in F8 do not overlap the NMI vector.

 

		MAC BANKS_AND_VECTORS; put this at the end of every bank
	RORG $FFF8
SelectBank1 .byte $00
SelectBank2 .byte $00
	.word Bank2; NMI
	.word Bank2; RESET
	.word Bank2; IRQ
	ENDM

...

;==============================
ORG $EFF8
BANKS_AND_VECTORS
;==============================


...

;==============================
ORG	$FFF8
BANKS_AND_VECTORS
;==============================

Link to comment
Share on other sites

  • 4 weeks later...

Seems I still can't get it to go....

 

I stripped it down as bare as I could.

What's missing here?

 

 

;===================================
; Constants
NTSC = 1
;===================================


;===================================
processor 6502
include vcs.h
;===================================

       MAC JUMP_TABLE ; put this at the start of every bank
       RORG $F000
Bank1
       cmp SelectBank1
       jmp Bank1Code
Bank2
       cmp SelectBank2
       jmp Bank2Code
       ENDM

;===================================

MAC BANKS_AND_VECTORS; put this at the end of every bank
RORG $FFFA
SelectBank1 .byte $00
SelectBank2 .byte $00
.word Bank2; NMI
.word Bank2; RESET
.word Bank2; IRQ
ENDM
;===================================


;#####################################################
; Bank 1 below
;#####################################################

org	$E000
JUMP_TABLE

org	$E100


;=================
Bank1Code
GameInitBank1
;=================


;=================
MainLoopBank1
;=================
JSR	VerticalBlankBank1 ;Execute the vertical blank.
JSR	GameCalcBank1      ;Do calculations during Vblank
JSR	DrawScreenBank1    ;Draw the screen
JSR	OverScanBank1      ;Do more calculations during overscan
JMP	MainLoopBank1      ;Continue forever.


;=================
VerticalBlankBank1
;=================
LDX	#0
LDA	#2
STA	WSYNC
STA	VSYNC ; Begin vertical sync.
STA	WSYNC ; First line of VSYNC
STA	WSYNC ; Second line of VSYNC.
 IF NTSC
LDA	#44
 ELSE ; (PAL)
LDA	#54
 ENDIF
STA	TIM64T
LDA	#0
STA	CXCLR ; now's as good a time as any to clear the collision latches.
; Now we can end the VSYNC period.
STA	WSYNC ; Third line of VSYNC.
STA	VSYNC ; (0)
RTS


;=================
GameCalcBank1
;=================
LDA	#0	; same as PAL and NTSC
STA	COLUBK  ; Background will be black.
; set colors for first scanline
LDA	#3
STA	CTRLPF
 IF NTSC
LDA	#$52
 ELSE ; (PAL)
LDA	#$82
 ENDIF
STA	COLUP0
 IF NTSC
LDA	#$5E
 ELSE ; (PAL)
LDA	#$8E
 ENDIF
STA	COLUPF
 IF NTSC
LDA	#$76
 ELSE ; (PAL)
LDA	#$D6
 ENDIF
STA	COLUP1
RTS

;=================
DrawScreenBank1
;=================
LDA	INTIM
BNE	DrawScreenBank1 ; Whew!
STA	WSYNC
STA	VBLANK  ; Enable drawing again (set vblank to 0)
LDY	#191
TitleScreenScanLoop1
STY	PF0
STY	PF1
STY	PF2
STA	WSYNC
DEY
BNE	TitleScreenScanLoop1

; Clear all registers here to prevent any possible bleeding.
LDA	#2
STA	WSYNC  ;Finish this scanline.
STA	VBLANK ; Make TIA output invisible,
; Now we need to worry about it bleeding when we turn
; the TIA output back on.
LDY	#0
STY	PF0
STY	PF1
STY	PF1
STY	GRP0
STY	GRP1
STY	ENAM0
STY	ENAM1
STY	ENABL
RTS

;=================
OverScanBank1
;=================
 IF NTSC
LDA	#35
 ELSE ; (PAL)
LDA	#85
 ENDIF
STA	TIM64T
;=================
GameCalc2Bank1
;=================
;============================
; Loop to get our 30 scanlines for overscan
;============================
WaitForEndOfOverscanBank1
LDA	INTIM
BNE	WaitForEndOfOverscanBank1
STA	WSYNC	; finish scanline 30
RTS


;==============================
ORG $EFF8
BANKS_AND_VECTORS
;==============================


;#####################################################
; Bank 2 below
;#####################################################

org $F000
rorg $F000
JUMP_TABLE


org	$F100
rorg	$F100
      
;=================
Bank2Code
Start
;=================
SEI
CLD
LDX 	#$FF
TXS
LDA	#0
B1	STA	0,X ; clear $FF through $1 (not $0, VSYNC)
DEX
BNE	B1

;=================
GameInitBank2
;=================


;=================
MainLoopBank2
;=================
JSR	VerticalBlankBank2 ;Execute the vertical blank.
JSR	GameCalcBank2      ;Do calculations during Vblank
JSR	DrawScreenBank2    ;Draw the screen
JSR	OverScanBank2      ;Do more calculations during overscan
JMP	MainLoopBank2      ;Continue forever.


;=================
VerticalBlankBank2
;=================
LDX	#0
LDA	#2
STA	WSYNC
STA	VSYNC ; Begin vertical sync.
STA	WSYNC ; First line of VSYNC
STA	WSYNC ; Second line of VSYNC.
 IF NTSC
LDA	#44
 ELSE ; (PAL)
LDA	#54
 ENDIF
STA	TIM64T
LDA	#0
STA	CXCLR ; now's as good a time as any to clear the collision latches.
; Now we can end the VSYNC period.
STA	WSYNC ; Third line of VSYNC.
STA	VSYNC ; (0)
RTS  


;=================
GameCalcBank2
;=================
LDA	SWCHB
AND	#%00000011
EOR	#%00000011
BEQ	ConsoleSwitchNotHit
;========================
; Reset was pressed.  Start game
JMP	Bank1
;========================
ConsoleSwitchNotHit
LDA	#0	; Same color for PAL and NTSC
STA	COLUBK  ; Background will be black.
; set colors for first scanline
LDA 	#%00110011
STA 	CTRLPF
 IF NTSC
LDA	#$44
 ELSE ; (PAL)
LDA	#$64
 ENDIF
STA	COLUP0
 IF NTSC
LDA	#$5E
 ELSE ; (PAL)
LDA	#$8E
 ENDIF
STA	COLUPF
 IF NTSC
LDA	#$98
 ELSE ; (PAL)
LDA	#$B8
 ENDIF
STA	COLUP1
RTS


;=================
DrawScreenBank2
;=================
LDA	INTIM
BNE	DrawScreenBank2 ; Whew!
STA	WSYNC
STA	VBLANK  ; Enable drawing again (set vblank to 0)

LDY	#191
TitleScreenScanLoop2
STY	PF0
STY	PF1
STY	PF2
STA	WSYNC
DEY
BNE	TitleScreenScanLoop2

; Clear all registers here to prevent any possible bleeding.
LDA	#2
STA	WSYNC  ;Finish this scanline.
STA	VBLANK ; Make TIA output invisible,
; Now we need to worry about it bleeding when we turn
; the TIA output back on.
; Y is still zero.
STY	PF0
STY	PF1
STY	PF2
STY	GRP0
STY	GRP1
STY	ENAM0
STY	ENAM1
STY	ENABL
RTS


;=================
OverScanBank2
;=================
 IF NTSC
LDA	#35
 ELSE ; (PAL)
LDA	#85
 ENDIF
STA	TIM64T
;=================
GameCalc2Bank2
;=================
;============================
; Loop to get our 30 scanlines for overscan
;============================
WaitForEndOfOverscanBank2
LDA	INTIM
BNE	WaitForEndOfOverscanBank2
STA	WSYNC	; finish scanline 30
RTS


;==============================
ORG	$FFF8
BANKS_AND_VECTORS
;==============================

Link to comment
Share on other sites

8K cartridges are known as F8 bank switching as the hot spots are FFF8 and FFF9.

 

You correctly changed the ORGs at the end of each bank to use xxF8, but the BANKS_AND_VECTORS macro is using RORG $FFFA instead of RORG $FFF8.

 

I fixed that and it now crashes when RESET is hit - as before the ORG $E100 needs to be followed by RORG $F100.

 

Once those changes are in place the screen shows:

post-3056-1219801746_thumb.png

 

and hitting reset causes it to show:

post-3056-1219801770_thumb.png

 

Revised source below, just change the .txt back to .asm

8k.txt

Edited by SpiceWare
Link to comment
Share on other sites

  • 2 months later...

One more 8K bank-switching question (using the current method).

 

In the 32K world, the sequence of switching to different spots within a bank seemed pretty easy to me.

1) Power-up

2) Use table to determine start vector (let's say bank 8); jump there

3) Bank 8 is a purely dedicated bank for clearing ram out, and displaying the title screen

4) In Bank 8, set a "jump address" for the program to redirect to once inside the next bank jumped to (such as $D030).

5) On "reset" event, go to any other bank (say, 2), and immediately jump to the "jump address" in that bank ($D030) using a JMP.ind.

 

It seems to work very well for 32K game design.

In that environment, if we ever jump to bank 8, we're reseting everything anyway, so having multiple addresses to jump to in that bank isn't necessary, and therefore works fine. Basically, what I'm saying is that Bank 8 has one entry point-- and that's for restarting the game via soft-reset and hard-reset.

 

Now, in an 8K world, things are different. I have multiple addresses that I want to start out from in both banks when I switch to different banks.

Say that I power up in bank 2.

In this bank, we have 2 things that happen:

1) Initial RAM clearing/setting for power-up/reset

2) Some game code (for a mini-game).

 

So, if I switch to bank 1 sometime in the game, and then need to go to bank 2, I have a problem. I need to differentiate the 2 paths.

The way I had been coding before was to essentially do a JMP.ind in a bank right away, to get to the necessary address.

However, since my initialization code is in bank 2, this won't work, as the values in my 2 return address variable bytes will either be a) random (from powerup) or b) fixed (set by me in bank 1 on purpose).

 

I was thinking the best way to alleviate this sort of problem would be to have a simple check:

Here's what I'm thinking:

 

If in bank 2,

- check return address high-byte and low-byte. Do they match valid values that could be set by bank 1?

- if yes, then jump to that address

- if no, then jump to "reset" routine address

 

Though I know this can work, there is a 1/65536 chance that due to random powerup data in RAM, we may jump to the "Gameplay" routine in this bank instead of the initialization routine. On a console that is "fried", or with slowness to clear memory out on powerdown/powerup, I'm sure this is figure is more alarming.

 

So, the questions are:

1) Is this a gamble that I can live with, without any worry?

2) Is there a better way to do this?

 

Thanks a lot!

-John

Link to comment
Share on other sites

From what I understand, you are trying to execute a random bank after ramclear has executed from a specific bank. If that's the case, just have an index register hold a random value that's used in conjunction with the bankswitch instruction (so a random hotspot is accessed). You only need 1 bit for 8k, 2 bits for 16k, and 3 bits for 32k...so you could couple this with 7800 code-detection if desired (that's not done here, tho).

 

 

Example 8k: each bank holds a different program, the second bank only holds the startup routine.

 

	  ORG $1000
  RORG $D000
;the 2600's bankswitch status is unknown
;on powerup...so just place identical code
;in both banks at the same point.  The
;start of ROM is used here...
START1:
  LDA $1FF9;select 2nd bank
  JMP START;superfluous here, used for filler
;second game
  LDA $1FF8,Y;Y should hold 0 or 1 for 8k

;...program for first bank continues here...

  ORG $1FF8
  RORG $DFF8
  .word 0,0,START1,START1

 

 

 

	  ORG $2000
  RORG $F000
START2:
  LDA $1FF9;no effect here
  JMP START;execute ram clear
Game:
  LDA $1FF8,Y;Y should hold 0 or 1 for 8k

;...program for second bank continues here...


;at some other point in the 2nd bank, place your
;ramclear loop.  Done at the end of ROM here:
  ORG $2FE5
  RORG $FFE5

START:
  LDY INTIM;used for random value later
  LDA #$00
  TAX
RamClear:
  STA $00,X
  TXS
  INX
  BNE RameClear
  TYA;now handle the random bank...
  AND #$01;keep only the low bit
  TAY;give it back to the Y register
  JMP Game

  ORG $2FF8
  RORG $FFF8
  .word 0,0,START2,START2

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...