MemberAtarian Posted October 19, 2018 Share Posted October 19, 2018 (edited) 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 October 19, 2018 by MemberAtarian Quote Link to comment Share on other sites More sharing options...
JeremiahK Posted October 20, 2018 Share Posted October 20, 2018 (edited) 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 October 20, 2018 by JeremiahK Quote Link to comment Share on other sites More sharing options...
MemberAtarian Posted October 20, 2018 Author Share Posted October 20, 2018 (edited) 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 October 20, 2018 by MemberAtarian Quote Link to comment Share on other sites More sharing options...
MemberAtarian Posted October 20, 2018 Author Share Posted October 20, 2018 (edited) 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 October 20, 2018 by MemberAtarian Quote Link to comment Share on other sites More sharing options...
JeremiahK Posted October 20, 2018 Share Posted October 20, 2018 (edited) 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 October 20, 2018 by JeremiahK Quote Link to comment Share on other sites More sharing options...
MemberAtarian Posted October 20, 2018 Author Share Posted October 20, 2018 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. Quote Link to comment Share on other sites More sharing options...
MemberAtarian Posted October 20, 2018 Author Share Posted October 20, 2018 I put the CheckMouse in bB code in bank8, outside the kernel, now it's working fine. Quote Link to comment Share on other sites More sharing options...
JeremiahK Posted October 20, 2018 Share Posted October 20, 2018 That's good that you got it working. I wonder if the stack was somehow getting modified? I had a bug yesterday where I had forgotten to reset the stack pointer after switching to a bank, and it caused all sorts of issues. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.