Jump to content
IGNORED

Bankswitching from bB multisprite kernel to bB code?


MemberAtarian

Recommended Posts

Hi guys, you know, I make a TBS game for the VCS in bB and I have to check the mouse sensors very often. I do it 8 times during overscan and 2 times in vblank now. But there is the "drawscreen" part that is only accessable in assemby, modifing the kernel. I calculated the cycles, so it's not the cause of the problem: First, I do this code where I want to do the checking:

 

     lda #8
     bit SWCHB
     BNE .skipping
     LDA e
     AND #32
     BEQ .skipping
     JSR CheckMouse

This checks if the bw switch is set to 1 and the fifth bit of 'e' variable is set to 1 (it means you are in a loop that allows you using the mouse), and if it's ok, it goes to CheckMouse. Checkmouse looks like this:

 

CheckMouse
     LDA e
     ORA #16
     STA e     
     LDY #<$1F
     lDA #>$F6
     LDX #2
     JMP .SetupMouse
.backback
 rts

It's an F4 cartridge, and mouse checking is in the 3rd bank of code. I set the fourth bit of 'e' to 1, so in bB code I will know when to jump back here. So this should jump to label "SetupMouse" in bank3.

 

In bB code I tried a lot of methods, simple "goto backback bank8", the "fake rts" method that was written in Hugg's book (https://8bitworkshop.com/v3.2.0/?=&file=examples%2Fbankswitching&platform=vcs)

        pha            
        tya            
        pha             
        lda $1FF4,x   
        rts  

And of course the more logical

 

 asm
     LDY #<$1F
     lDA #>$FB
     LDX #7
     JMP .backback
end

But none of them is working, it crashes and starts the ROM from the beginning. Even if I put the ASM under "SetupMouse". There was a version I made with very complicated way in vblank with a lot of jumps and that way, the assembly jump and basic code goto back worked, but the scanline number was too high and if I changed .SetupMouse to anything else, it crashed and as I put a goto for bank4 in vblank and a goto to go back, it crashed as well, so I wanted to find a simple method to fix this, but nothing is working, crashing the game as soon I set bw to 1.

 

Can you tell me how I should do a proper bankswitch is asm?

I read about 'illegal' opcodes and 'illegal' nop method for bankswitching, but bB, unlike DASM, can't use them.

Edited by MemberAtarian
Link to comment
Share on other sites

I have never used bB, but I do know how bankswitching works in assembly. The thing about bankswitching is that the bank is switched as soon as the hotspot address is accessed.

 

Think of it like a clipboard with a stack of pages representing each bank. You can only see one page at a time. The program counter marches through the program, like if you were using your finger to keep track of where you were reading. If you happen to access the addresses from $FFF4 to $FFFB, before you can even finish your sentence, the page you are reading will instantly change to another one (a bankswitch happens). Your finger doesn't move, it keeps pointing to wherever you left off on the last page, and you keep on reading like nothing happened.

 

So if I have something like this...

    lda #64    ; finish doing something important
    sta foo

    nop $FFF6  ; switch to bank 3 - IMPORTANT: switch happens instantly!
    jsr bar    ; jump to the subroutine - IMPORTANT: this never happens!

...the JSR never actually happens, because as soon as $FFF6 is accessed, we magically jump to bank 3 and continue on.

This is where the problem is happening. Your banks aren't lining up with each other, so when you switch banks, you end up in the wrong place.

 

There are many methods of fixing this, and the easiest is to simply have a list of all the "bridges" to labels you want to be able to access from other banks, like this: (the 8bitworkshop example you linked above called this type of thing a "trampoline")

goto_foo
    nop $FFF4    ; switch to bank 1
    jmp foo      ; jump to "foo", which is in bank 1

goto_bar
    nop $FFF6    ; switch to bank 3
    jmp bar      ; jump to "bar", which is in bank 3

goto_etc
    nop $FFF9    ; switch to bank 6
    jmp etc      ; jump to "etc", which is in bank 6

You then put this code in all the banks, at exactly the same spot in every bank, usually at the front. This way, no matter which bank you are in, you can simply do a jmp goto_foo, and that will jump to the table, which is exactly the same in every bank. So when the bankswitch happens, it won't cause a crash.

 

Keep in mind that this only works with JMP statements, not JSR's. If you wanted that, it would be a bit more complicated. You would have to keep track of which bank you came from, and where you were inside the bank, typically by pushing this information to the stack and then pulling it out when you returned.

 

This is how you would do it in assembly. I'm not exactly sure how you would do something like this in bB, you might want to start another thread in the batari Basic Forums.

 

One super-easy solution, which might actually be best, since your CheckMouse routine is so short, would be to put a copy of CheckMouse in both banks. Then you wouldn't need to do any bankswitching at all.

Edited by JeremiahK
Link to comment
Share on other sites

I have never used bB, but I do know how bankswitching works in assembly. The thing about bankswitching is that the bank is switched as soon as the hotspot address is accessed.

 

Think of it like a clipboard with a stack of pages representing each bank. You can only see one page at a time. The program counter marches through the program, like if you were using your finger to keep track of where you were reading. If you happen to access the addresses from $FFF4 to $FFFB, before you can even finish your sentence, the page you are reading will instantly change to another one (a bankswitch happens). Your finger doesn't move, it keeps pointing to wherever you left off on the last page, and you keep on reading like nothing happened.

 

So if I have something like this...

    lda #64    ; finish doing something important
    sta foo

    nop $FFF6  ; switch to bank 3 - IMPORTANT: switch happens instantly!
    jsr bar    ; jump to the subroutine - IMPORTANT: this never happens!

...the JSR never actually happens, because as soon as $FFF6 is accessed, we magically jump to bank 3 and continue on.

This is where the problem is happening. Your banks aren't lining up with each other, so when you switch banks, you end up in the wrong place.

 

There are many methods of fixing this, and the easiest is to simply have a list of all the "bridges" to labels you want to be able to access from other banks, like this: (the 8bitworkshop example you linked above called this type of thing a "trampoline")

goto_foo
    nop $FFF4    ; switch to bank 1
    jmp foo      ; jump to "foo", which is in bank 1

goto_bar
    nop $FFF6    ; switch to bank 3
    jmp bar      ; jump to "bar", which is in bank 3

goto_etc
    nop $FFF9    ; switch to bank 6
    jmp etc      ; jump to "etc", which is in bank 6

You then put this code in all the banks, at exactly the same spot in every bank, usually at the front. This way, no matter which bank you are in, you can simply do a jmp goto_foo, and that will jump to the table, which is exactly the same in every bank. So when the bankswitch happens, it won't cause a crash.

 

Keep in mind that this only works with JMP statements, not JSR's. If you wanted that, it would be a bit more complicated. You would have to keep track of which bank you came from, and where you were inside the bank, typically by pushing this information to the stack and then pulling it out when you returned.

 

This is how you would do it in assembly. I'm not exactly sure how you would do something like this in bB, you might want to start another thread in the batari Basic Forums.

 

One super-easy solution, which might actually be best, since your CheckMouse routine is so short, would be to put a copy of CheckMouse in both banks. Then you wouldn't need to do any bankswitching at all.

Oh my, there is so many things wrong with this. :/

 

First, I told you, illegal 'nop' is not working with bB. I would do that if I could, I tried NOP $1FF_, NOP $FFF_, even these with STA, LDA, BIT, but none of them works.

Second, "CheckMouse" is in bank8 (as the drawscreen loop of bB), it's just the beginning, the real thing is SetupMouse in bank3, and it's more than 1K (it's reading the mouse sensors and takes a lot of space), I can't just copy it into "Checkmouse" (after converting it to assembly, of course) or bank8 will be full and I won't have any space left for sprites. Another thing with bB that every sprite information is in bank8, because it has to be in the same bank as the drawing.

Edited by MemberAtarian
Link to comment
Share on other sites

I even tried the code that is in the temp assembly bB, so I guessed it would work.

sta	temp7
lda	#>(.SetupMouse-1)
pha
lda	#<(.SetupMouse-1)
pha
lda     temp7
pha
txa
pha
ldx	#3 ; number of bank you want
jmp	BS_jsr ; this is at the end of bank8, every jump is going there


And it's not working either. :/ And it does not seem like a wrong bank error as that would make strange glitches, but is just simply reboots the system.

Edited by MemberAtarian
Link to comment
Share on other sites

Aha, I see. Sorry, I misunderstood what was happening in CheckMouse, I see now that it is only an in-between code that jumps into your actual code.

 

As I said, this was only in answer to the question of "how would it be done in assembly?". I don't know exactly how it's done in bB, but I wanted to make sure you understood how it actually works behind the scenes.

 

I would give a longer response, but I have to head to work in a few minutes. :(

Edited by JeremiahK
Link to comment
Share on other sites

Aha, I see. Sorry, I misunderstood what was happening in CheckMouse, I see now that it is only an in-between code that jumps into your actual code.

 

As I said, this was only in answer to the question of "how would it be done in assembly?". I don't know exactly how it's done in bB, but I wanted to make sure you understood how it actually works behind the scenes.

 

I would give a longer response, but I have to head to work in a few minutes. :(

Dunno why it happens, sometimes is seems like its nearly working, but goes off. It's not restarting, but the screen freezes. I tried it even with the exact locations in the ROM, starting with $F, because it's rorg-ed, but the result was the same.

 

Krystof told me not to do bankswitch in the middle of an important kernel, maybe he is right, but my code is just too long to translate into assembly (or just copy it out from the temp output assembly of bB and copy it to the kernel), it gives "branch too long".

 

Anyway, my bB code is like this:

 

 if switchleftb then goto SetAmiga1
SetAtariST1
 if !joy0up && !joy0down  then goto Dir1
 if joy0up && !joy0down then goto Dir2
 if joy0up && joy0down then goto Dir3
 if !joy0up && joy0down then goto Dir4
SetAmiga1
 if !joy0right && !joy0down  then goto Dir1
 if joy0right && !joy0down then goto Dir2
 if joy0right && joy0down then goto Dir3
 if !joy0right && joy0down then goto Dir4

Dir1
  if !a{0} && !a{1}  then a{2} = 0 : goto NewWay
  if a{0} && !a{1}  then a{2} = 1 : a{3} = 0 : goto TO1
  if !a{0} && a{1}  then a{2} = 1 : a{3} = 1: goto TO1
  if a{0} && a{1}  then a{2} = 0 : goto NewWay
TO1
  a{0} = 0: a{1} = 0: goto Dir
Dir2
 if a{0} && !a{1} then  a{2} = 0 : goto NewWay
 if a{0} && a{1} then a{2} = 1 : a{3} = 0 : goto TO2
 if !a{0} && !a{1} then a{2} = 1 : a{3} = 1 : goto TO2
 if !a{0} && a{1} then a{2} = 0 : goto NewWay
TO2
 a{0} = 1: a{1} = 0: goto Dir
Dir3

 if a{0} && a{1}  then a{2} = 0 : goto NewWay
 if !a{0} && a{1} then a{2} = 1 : a{3} = 0 : goto TO3
 if a{0} && !a{1} then a{2} = 1 : a{3} = 1 : goto TO3
 if !a{0} && !a{1}  then a{2} = 0 : goto NewWay
TO3
 a{0} = 1: a{1} = 1: goto Dir
Dir4

 if !a{0} && a{1} then a{2} = 0 : goto NewWay
 if !a{0} && !a{1} then a{2} = 1 : a{3} = 0 : goto TO4
 if a{0} && a{1} then a{2} = 1 : a{3} = 1 : goto TO4
 if a{0} && !a{1} then a{2} = 0 : goto NewWay
TO4
 a{0} = 0: a{1} = 1
Dir
 if player0x>1 &&  a{2} &&  a{3} then player0x=player0x-2
 if player1x<152 &&  a{2} &&  !a{3} then player0x=player0x+2
 
NewWay
  if switchleftb then goto SetAmiga2
SetAtariST2
 if !joy0left && !joy0right  then goto Dir5
 if joy0left && !joy0right then goto Dir8
 if joy0left && joy0right then goto Dir7
 if !joy0left && joy0right then goto Dir6
 
SetAmiga2
 if !joy0left && !joy0up  then goto Dir5
 if joy0left && !joy0up then goto Dir8
 if joy0left && joy0up then goto Dir7
 if !joy0left && joy0up then goto Dir6


Dir5
  if !a{4} && !a{5}  then a{6} = 0 : goto Gotos
  if a{4} && !a{5}  then a{6} = 1 : a{7} = 0 : goto TO5
  if !a{4} && a{5}  then a{6} = 1 : a{7} = 1 : goto TO5
  if a{4} && a{5}  then a{6} = 0 : goto Gotos
TO5
 a{4} = 0: a{5} = 0: goto DirX
Dir6
 if a{4} && !a{5} then a{6} = 0 : goto Gotos
 if a{4} && a{5} then a{6} = 1 : a{7} = 0 : goto TO6
 if !a{4} && !a{5} then a{6} = 1 : a{7} = 1 : goto TO6
 if !a{4} && a{5} then a{6} = 0 : goto Gotos
TO6
 a{4} = 1: a{5} = 0: goto DirX
Dir7

 if a{4} && a{5}  then a{6} = 0 : goto Gotos
 if !a{4} && a{5} then a{6} = 1 : a{7} = 0 : goto TO7
 if a{4} && !a{5} then a{6} = 1 : a{7} = 1 : goto TO7
 if !a{4} && !a{5}  then a{6} = 0 : goto Gotos
TO7
 a{4} = 1: a{5} = 1: goto DirX
Dir8

 if !a{4} && a{5} then a{6} = 0 : goto Gotos
 if !a{4} && !a{5} then a{6} = 1 : a{7} = 0: goto TO8
 if a{4} && a{5} then a{6} = 1 : a{7} = 1: goto TO8
 if a{4} && !a{5} then a{6} = 0 : goto Gotos
TO8
 a{4} = 0: a{5} = 1

DirX
 if player0y>11 &&  a{6} &&  a{7} then player0y=player0y-2
 if player0y<87 &&  a{6} &&  !a{7} then player0y=player0y+2
Gotos 

So I'm using the variable bits of "a" (it's just a memory address), a{0} and a{1} for the two sensors of horizontal movement, a{2} if movement will be done, a{3} for direction (if 0, +, if 1, -), a{4} and a{5} for vertical sensors, a{6} if movement should be done and a{7} for direction.

I read the sensors, load the previous state, compare it and decide if the wheels were rolled, then save the actual sensor states.

 

 

    lda     SWCHA
    lsr
    lsr
    lsr
    lsr
    and     #%11
    ldy     lastTrack
    sta     lastTrack           
    eor     NextTrackTbl,y  
    beq     .down           
    eor     #%11
    bne     .endTC         
.up:                        
    ...
.down:                   
    ...
.endTC
    ...
NextTrackTbl
    .byte   %01
    .byte   %11
    .byte   %00
    .byte   %10

Tom sent me this code template, but I only understand half of it. And it's incompatible to what I do.

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