+Random Terrain Posted August 16, 2008 Share Posted August 16, 2008 I know we can use bit operations to basically turn a variable into 8 very simple variables, but this is something different. How do I use one variable like it is two separate variables where I can go as high as 15 in both halves? I want to use one variable as two counters, but how do I change and check the high nybble and low nybble separately? Thanks. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted August 16, 2008 Share Posted August 16, 2008 Just use inline asm within bBasic (it has that function, right?). To update either half, you'll need to clear the bits you are working with (via AND #$F0 or AND #$0F for the low or high nybbles respectively), store the value temporarily, fetch or calculate your updated value, then ORA the temp back in before the final store. To check either half, just perform an AND in reverse order than as shown above. If you are using the upper nybble for a table index, you might want to drop it down into the low nybble's position by using 4 LSR's (implied mode). Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted August 16, 2008 Author Share Posted August 16, 2008 (edited) Just use inline asm within bBasic (it has that function, right?). To update either half, you'll need to clear the bits you are working with (via AND #$F0 or AND #$0F for the low or high nybbles respectively), store the value temporarily, fetch or calculate your updated value, then ORA the temp back in before the final store. To check either half, just perform an AND in reverse order than as shown above. If you are using the upper nybble for a table index, you might want to drop it down into the low nybble's position by using 4 LSR's (implied mode). Thanks. Yep, you can use inline asm with bB, but I have limited experience with it. Seems like nybbling is more trouble than it's worth. Edited August 16, 2008 by Random Terrain Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted August 16, 2008 Share Posted August 16, 2008 (edited) It just looks complicated. It becomes quite easy when you get used to it. The difficult part is keeping track of which ones are combined (to know when to preserve bits). If one of the nybbles is to be a counter that's bumped after certian conditions, you can easily use the high nybble for that without worrying about preservation of the low (which wouldn't change so long as the carry flag is properly cleared or set)... LDA merged_variable CLC ADC #$10 ;change upper nybble only STA merged_variable The other way can be more complicated... LDA merged_variable PHA ;save original value for later CLC ADC #$01 ;upper nybble may be affected AND #$0F ;so do this to ignore those bits STA merged_variable ;and save temporarily PLA ;get back original value AND #$F0 ;keep only the upper nybble ORA merged_variable ;mix with the updated low STA merged_variable Whether or not it's worth it depends on your program's requirements. Merging (or reusing) variables is the only way to get more of them...short of using the Superchip option. Edited August 16, 2008 by Nukey Shay Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted August 17, 2008 Author Share Posted August 17, 2008 It just looks complicated. It becomes quite easy when you get used to it. The difficult part is keeping track of which ones are combined (to know when to preserve bits). If one of the nybbles is to be a counter that's bumped after certian conditions, you can easily use the high nybble for that without worrying about preservation of the low (which wouldn't change so long as the carry flag is properly cleared or set)...LDA merged_variable CLC ADC #$10 ;change upper nybble only STA merged_variable The other way can be more complicated... LDA merged_variable PHA ;save original value for later CLC ADC #$01 ;upper nybble may be affected AND #$0F ;so do this to ignore those bits STA merged_variable ;and save temporarily PLA ;get back original value AND #$F0 ;keep only the upper nybble ORA merged_variable ;mix with the updated low STA merged_variable Whether or not it's worth it depends on your program's requirements. Merging (or reusing) variables is the only way to get more of them...short of using the Superchip option. Thanks. Too bad bB can't do strings because I could use 1 through 9 and 10 through 90 and read the number by converting it to a string and just look at the ones or tens place. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted August 17, 2008 Share Posted August 17, 2008 That would also imply that both halves of the byte are being adjusted in decimal (BCD) mode. And it doesn't seem any quicker than using AND #$0F or AND #$F0 just to read the status of the lower or upper halves respectively. Bit preservation only comes into play when a value needs adjusting (which is true regardless of mode). Also, it should be mentioned that asm doesn't care how the byte is split up. You could, for example, use the 2 high bits for quick flags of single-bit variables (to be branched via BPL/BMI or BVC/BVS respectively), while the lower 6 bits are used for a counter. Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted August 17, 2008 Share Posted August 17, 2008 I know we can use bit operations to basically turn a variable into 8 very simple variables, but this is something different. How do I use one variable like it is two separate variables where I can go as high as 15 in both halves? I want to use one variable as two counters, but how do I change and check the high nybble and low nybble separately? Thanks. Here's an example that uses the "//" modulo division. The remainder is returned in temp1, but the bits are in reverse order, so we can use "//" again to reverse them back into the correct order. rem * Nybble me this, Batman! rem * Variable "a" will be used to store two nybble values. rem * You need to include div_mul.asm for this. include div_mul.asm rem * Store the two values in "b" and "c," just for now. b = 5 c = 10 rem * Use multiplication and addition to set "a." rem * The "b" value will go in the high nybble, rem * and the "c" value will go in the low nybble. a = 16 * b + c rem * Now clear "b" and "c." b = 0 c = 0 rem * Here's how to retrieve the two nybbles: b = a // 16 c = temp1 // 16 c = temp1 rem * There's a bug in the "//" routine that causes the rem * bits of remainder temp1 to be in reverse order, rem * so that's why we do "//" again on temp1. rem * Now let's use the score to display them: score = 0 if b > 0 then for i = 1 to b : score = score + 1000 : next if c > 0 then for i = 1 to c : score = score + 1 : next COLUBK = $00 scorecolor = $1A loop_1 drawscreen if !joy0fire then loop_1 rem * Here's how to change just the high nybble (to 3): a = a & %00001111 a = a | 16 * 3 rem * Here's how to change just the low nybble (to 6): a = a & %11110000 a = a | 6 rem * Now get and display the new values: b = a // 16 c = temp1 // 16 c = temp1 score = 0 if b > 0 then for i = 1 to b : score = score + 1000 : next if c > 0 then for i = 1 to c : score = score + 1 : next loop_2 drawscreen goto loop_2 Michael Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted August 17, 2008 Share Posted August 17, 2008 Here's a simpler example that doesn't use the modulo division: rem * Nybble me this, Batman! rem * Variable "a" will be used to store two nybble values. rem * You need to include div_mul.asm for this. include div_mul.asm rem * Store the two values in "b" and "c," just for now. b = 5 c = 10 rem * Use multiplication and addition to set "a." rem * The "b" value will go in the high nybble, rem * and the "c" value will go in the low nybble. a = 16 * b + c rem * Now clear "b" and "c." b = 0 c = 0 rem * Here's how to retrieve the two nybbles: b = a / 16 c = a & %00001111 rem * Now let's use the score to display them: score = 0 if b > 0 then for i = 1 to b : score = score + 1000 : next if c > 0 then for i = 1 to c : score = score + 1 : next COLUBK = $00 scorecolor = $1A loop_1 drawscreen if !joy0fire then loop_1 rem * Here's how to change just the high nybble (to 3): a = a & %00001111 a = a | 16 * 3 rem * Here's how to change just the low nybble (to 6): a = a & %11110000 a = a | 6 rem * Now get and display the new values: b = a / 16 c = a & %00001111 score = 0 if b > 0 then for i = 1 to b : score = score + 1000 : next if c > 0 then for i = 1 to c : score = score + 1 : next loop_2 drawscreen goto loop_2 Michael Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted August 17, 2008 Share Posted August 17, 2008 Much thanks for the bB equalivants. My head's stuck in .asm, so I never had time to learn it...but it looks as if it should work for smaller breakdowns as well. But wouldn't the use of variables (b) and © to calculate (a) end up causing bB to reserve 8-bits of ram for those as well...potentially 16 bits of ram wasted...unless these variables are used for other things elsewhere? If so, it might be better to just imbed some inline asm that works with (a) directly without the overhead. Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted August 17, 2008 Author Share Posted August 17, 2008 Here's a simpler example that doesn't use the modulo division: Thanks. That seems like an easier to understand solution that doesn't require asm. Looks like I can replace b and c with a couple of temporary variables such as temp1 and temp2. But wouldn't the use of variables (b) and © to calculate (a) end up causing bB to reserve 8-bits of ram for those as well...potentially 16 bits of ram wasted...unless these variables are used for other things elsewhere? If so, it might be better to just imbed some inline asm that works with (a) directly without the overhead I already use temporary variables for little jobs where the values don't need to be remembered, so they can be used instead of b and c. I knew one of you guys could figure out a fairly simple way to do this. It seems I can only get halfway there at best before my brain melts and leaks out of my ears. Quote Link to comment Share on other sites More sharing options...
+batari Posted August 17, 2008 Share Posted August 17, 2008 This question was asked a while back, and here is some more sample code (I never tested it, so I can't make any promises.) http://www.atariage.com/forums/index.php?showtopic=113003 Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted August 17, 2008 Author Share Posted August 17, 2008 (edited) Here's a simpler example that doesn't use the modulo division: I have adapted your code to work with what I already had and it seems to work. I'll show the different parts to make sure I'm not messing something up. This adds 1 to both high and low nybble counters: counter01 = counter01 + 17 ------------------------------------------------------------------- This checks the high nybble counter and skips the sprite animation if it's not time yet: temp1 = counter01 / 16 if temp1<animtrigger then goto skipanim If it's time for the sprite animation to change, the following clears the high nybble counter: counter01= counter01 & %00001111 ------------------------------------------------------------------- This checks the low nybble counter and skips background color flipping and scrolling if it's not time yet: temp1=counter01 & %00001111 if temp1<speed_current then goto skip_all If it's time for background color flipping and scrolling, the following clears the low nybble counter: counter01 = counter01 & %11110000 So far it doesn't look like I messed anything up and it seems to do exactly what I want. If there isn't a problem, I'll see how many other variables I can split in half. Maybe now I'll have enough variables to do everything I want. Thanks again. Edited August 17, 2008 by Random Terrain Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted August 17, 2008 Share Posted August 17, 2008 (edited) But wouldn't the use of variables (b) and ( c ) to calculate (a) end up causing bB to reserve 8-bits of ram for those as well...potentially 16 bits of ram wasted...unless these variables are used for other things elsewhere? Yes. I only used them because I was too lazy to look up which temp variables to stay away from! The best choice would be to use two temp variables, but bB uses the temp variables for its own purposes, and some are used in the mathematical operations. I just checked, and temp1 and temp2 are used in the "mul8" routine, but none of the temp variables are used when dividing by 16 or doing bit operations, so they should be safe to use. The modulo division example is kind of silly. When I saw "//" described in the batari Basic help manual, and that it returns the remainder in temp1, I thought that would be ideal: temp2 = a // 16 : rem * to get the high nybble in temp2 rem * and now temp1 already contains the low nybble But when I displayed the results in the score, the low nybble was wrong. And when I checked the compiled assembly code, I realized that the LSR and ROL instructions were moving the remainder into temp1 with the bits in reverse order. I think the generic "//" operation uses a routine in the div_mul16.asm include file, but if the bB compiler sees "// 16" (or 2, 4, 8, 16, 32, 64, or 128) it apparently just uses LSR for the division, and ROL for the remainder. The LSR is okay, but I think it would be easier/better to put the remainder in temp1 using AND: ; current buggy code: ; b = a // 16 LDA a ldx #0 stx temp1 lsr rol temp1 lsr rol temp1 lsr rol temp1 lsr rol temp1 STA b ; suggested replacement code: ; b = a // 16 LDA a STA temp1 AND %00001111 lsr lsr lsr lsr STA b The bB compiler would fill the section from "AND %00001111" through the last "LSR" with the appropriate bit mask and number of LSRs as determined by the power of 2 after the "//" operand. If this gets fixed in the next version of bB, then the "//" operation would be the simplest method, as shown in my first example above ("temp2 = a // 16" which would set temp1 to the low nybble automatically). Michael Edited August 17, 2008 by SeaGtGruff Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted August 21, 2008 Author Share Posted August 21, 2008 This is pretty cool. So far in the game I'm working on, I have 4 double variables and one that I'm using as 8 simple off/on variables, so now 5 variables have been turned into 16. Getting more out of these variables is really fun and makes me feel confident that I won't run out of variables before the game is done. Thanks again for the help. Quote Link to comment Share on other sites More sharing options...
CurtisP Posted August 21, 2008 Share Posted August 21, 2008 This is pretty cool. So far in the game I'm working on, I have 4 double variables and one that I'm using as 8 simple off/on variables, so now 5 variables have been turned into 16. Getting more out of these variables is really fun and makes me feel confident that I won't run out of variables before the game is done. Thanks again for the help. If you are doing simple on/off, yes/no, true/false, then you should be using single bits. This would give you 8 variables per actual variable. http://www.randomterrain.com/atari-2600-me...mmands.html#bit Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted August 21, 2008 Author Share Posted August 21, 2008 If you are doing simple on/off, yes/no, true/false, then you should be using single bits. This would give you 8 variables per actual variable. http://www.randomterrain.com/atari-2600-me...mmands.html#bit Yep, that's what I'm doing with one variable so far. I have 1 variable acting like 8 variables and 4 other variables are split in half which means 5 variables are acting like 16 (2 + 2 +2 +2 + 8 = 16). Quote Link to comment Share on other sites More sharing options...
Artlover Posted August 21, 2008 Share Posted August 21, 2008 Oh, this brings back memories of doing audio digitizing on the C64. Since the volume was only 0-15, only needed 4 bit samples, so two samples could be stored per byte. Really came in handy when doing stereo digi's, where each byte held the left & right samples. Of course in ASM, it was super ultra easy with the shift & rotate opcodes. <Artlover> needs to dig his C-64 out again one of these days. Quote Link to comment Share on other sites More sharing options...
CurtisP Posted August 27, 2008 Share Posted August 27, 2008 Of course in ASM, it was super ultra easy with the shift & rotate opcodes. Keep in mind that in Batari Basic, when you multiply or divide by a constant that is a power of two, then compiled code just does shifts, so it's really the same thing. 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.