+Random Terrain Posted September 11, 2010 Share Posted September 11, 2010 How can I make sure a variable is always a BCD compliant number? The following will work at the beginning, but as the number grows, the score will be incorrect or become garbled as you would expect: a = a + $05 : score = score + a A for-next loop will solve the problem: a = a + $05 : for temp5 = 1 to a : score = score + 1 : next But is that the best solution? Is there some special magic with AND or OR that could be done to make sure the variable is always a BCD compliant number as long as it is less than 100? Thanks. Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted September 11, 2010 Share Posted September 11, 2010 You can turn on "decimal" mode before doing the addition or subtraction. There's no batari Basic command for that; you'd need to do it with inline assembly. Note that batari Basic automatically uses decimal mode when you add a number to, or subtract a number from, the score: .L00 ; score = score + 1 SED ; <-- This turns on decimal mode. CLC LDA score+2 ADC #$01 STA score+2 LDA score+1 ADC #$00 STA score+1 LDA score ADC #$00 STA score CLD ; <-- And this turns it back off. The above code is for adding 1 to the 3-byte (6-digit) score, which is why it has to add (ADC, or "add with carry") to each of the three bytes, one after the other, in case adding 1 to the lowest byte causes a carry that affects one or both of the other bytes. If you're working with just a 1-byte BCD variable, then this should work, as long as variable a already contains a legal BCD value: dim variable = a rem * a = a + 1 asm SED CLC LDA variable ADC #1 STA variable CLD end You can also use decimal mode with subtraction. If you don't want to use inline assembly, you'll need to check each nibble to make sure the result is legal, and adjust each nibble as needed. For example: a = $49 : rem * set a to a BCD value of 49 a = a + $26 : rem * add a BCD value of 26 to 49 temp1 = a & $0F : rem * get the lo nibble if temp1 < 10 then goto check_hi_nibble temp1 = temp1 - 10 : rem * get rid of the "overflow" a = a & $F0 : rem * clear the lo nibble a = a | temp1 : rem * replace the lo nibble with the corrected value a = a + $10 : rem * add the "carry" to the hi nibble check_hi_nibble temp1 = a & $F0 : rem * get the hi nibble if temp1 < 10 then goto all_done temp1 = temp1 - 10 : rem * get rid of the "overflow" a = a & $0F : rem * clear the hi nibble a = a | temp1 : rem * replace the hi nibble with the corrected value all_done rem * this assumes you don't need to add the "carry" to another byte This example should work like this: $49 + $26 = $6F lo nibble = $F (or 15) temp1 = 15 - 10 = 5 change $6F to $60 (with the &) change $60 to $65 (with the |) change $65 to $75 (by adding the carry to the hi nibble) new hi nibble = $7 (or 7) so the BCD answer is $75 Michael Quote Link to comment Share on other sites More sharing options...
bogax Posted September 11, 2010 Share Posted September 11, 2010 (edited) How can I make sure a variable is always a BCD compliant number? The following will work at the beginning, but as the number grows, the score will be incorrect or become garbled as you would expect: a = a + $05 : score = score + a A for-next loop will solve the problem: a = a + $05 : for temp5 = 1 to a : score = score + 1 : next But is that the best solution? Is there some special magic with AND or OR that could be done to make sure the variable is always a BCD compliant number as long as it is less than 100? Thanks. I don't know what you're doing but making sure "a" is BCD compliant may not be enough. You may have to make "a" BCD. That is treat, it as BCD. If you never add more than 6 to "a" then it's relatively simple, mask off the digits individually and test if they're greater than 9 and if a digit is greater than 9 add 6 to it, starting with the ones digit. If you add more than 6 it starts getting messy. If you do add more than 6 there's the possibility of a carry out of the ones digit which you'd have to detect independent of what ever you add to the tens digit. Probably be easiest to treat the digits seperately, ie add the digits one at a time, add the ones digit then adjust, then add the tens digit and adjust. I'm not that familiar with batari Basic but it would be something like: if (a & $0F) > 9 then a = a + 6 if (a & $F0) > $90 then a = a + $60 Edit: That code is just to make "a" BCD compliant (it doesn't convert binary to BCD) Here's code to add "n" to "a" (I hope ) "n" doesn't (necessarily) need to be BCD (if "n" is a single hex digit 0-F it should work) Not sure if this is proper batari Basic temp = (a & $0F) + (n & $0F) : REM seperate ones digit and add them : REM result in temp so they can be : REM decimal adjusted seperately if temp > 9 then temp = temp + 6 : REM decimal adjust the ones digit a = (a & $F0) + temp + (n & $F0) : REM add it all together if a > $9F then a = a + $60 : REM decimal adjust the tens digit Edited September 11, 2010 by bogax Quote Link to comment Share on other sites More sharing options...
RevEng Posted September 11, 2010 Share Posted September 11, 2010 (edited) Similar to what SeaGtGruff is suggesting, just bracket your a=a+5 thusly... asm sed ; set decimal mode end a=a+5 asm cld ; clear decimal mode end Edited September 11, 2010 by RevEng Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted September 11, 2010 Author Share Posted September 11, 2010 (edited) If you don't want to use inline assembly, you'll need to check each nibble to make sure the result is legal, and adjust each nibble as needed. For example: a = $49 : rem * set a to a BCD value of 49 a = a + $26 : rem * add a BCD value of 26 to 49 temp1 = a & $0F : rem * get the lo nibble if temp1 < 10 then goto check_hi_nibble temp1 = temp1 - 10 : rem * get rid of the "overflow" a = a & $F0 : rem * clear the lo nibble a = a | temp1 : rem * replace the lo nibble with the corrected value a = a + $10 : rem * add the "carry" to the hi nibble check_hi_nibble temp1 = a & $F0 : rem * get the hi nibble if temp1 < 10 then goto all_done temp1 = temp1 - 10 : rem * get rid of the "overflow" a = a & $0F : rem * clear the hi nibble a = a | temp1 : rem * replace the hi nibble with the corrected value all_done rem * this assumes you don't need to add the "carry" to another byte This example should work like this: $49 + $26 = $6F lo nibble = $F (or 15) temp1 = 15 - 10 = 5 change $6F to $60 (with the &) change $60 to $65 (with the |) change $65 to $75 (by adding the carry to the hi nibble) new hi nibble = $7 (or 7) so the BCD answer is $75 Michael Thanks. I adapted the code bogax posted and it seems to be working: if (a & $0F) > 9 then a = a + 6 if (a & $F0) > $90 then a = a + $60 Here's the adapted code: temp5 = a & $0F : if temp5 > 9 then a = a + 6 temp5 = a & $F0 : if temp5 > $90 then a = a + $60 It seems to be working great so far. I also just tried the following from RevEng and it seems to give the same great results as the one from bogax: Similar to what SeaGtGruff is suggesting, just bracket your a=a+5 thusly... asm sed ; set decimal mode end a=a+5 asm cld ; clear decimal mode end Which solution do you think would be better to put on the bB page? Maybe I should include both? One thing I'll need is how you can use an if-then to limit a = a + 5. Decimal and hex don't seem to match up. For example, if a < 65 then score = score + a will limit it to 175, but I don't know how or why. Thanks. Edited September 11, 2010 by Random Terrain Quote Link to comment Share on other sites More sharing options...
bogax Posted September 11, 2010 Share Posted September 11, 2010 One thing I'll need is how you can use an if-then to limit a = a + 5. Decimal and hex don't seem to match up. For example, if a < 65 then score = score + a will limit it to 175, but I don't know how or why. Thanks. I may be completely off here because I get 180 not 175 so maybe I don't understand what you're doing. Assuming "a" and "score" both start at 0 and both are BCD, 65 looks like 41 BCD so the last "a" you add to "score" will be 40 and by that time "score" will be 180 ie presummably the IF statement does't know the difference and just treats both as straight binary. btw you do know that accumulating a constant in "a" then accumulating "a" in "score" will make "score" go up quadratically (graph "score" and it will be parabolic) Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted September 11, 2010 Share Posted September 11, 2010 (edited) Which solution do you think would be better to put on the bB page? Maybe I should include both? The solution from bogax is simpler (and therefore more elegant) than the one I suggested, because it checks for overflow *before* you add 1 to the score, whereas the code I posted checks for overflow *after*. But the "+ 6" solution is specifically designed for adding 1 (incrementing the lo nibble), and "+ $60" is specifically designed for adding 10 (incrementing the hi nibble). The solution I posted is more generalized, because you don't have to add 1 or 10 in a loop if you want to add, say, 25 to the BCD variable. The solution from RevEng is easier than the inline assembly I suggested, because all you really need to do in the inline assembly is turn decimal mode on, then off. But I think you should always make sure you add hex values-- for example, if you want to add 25, use "a = a + $25" instead of "a = a + 25," since decimal 25 equals $19, so adding decimal 25 would actually add a BCD value of 19. One thing I'll need is how you can use an if-then to limit a = a + 5. Decimal and hex don't seem to match up. For example, if a < 65 then score = score + a will limit it to 175, but I don't know how or why. I thought bB couldn't handle adding variables to the score yet? Michael Edited September 11, 2010 by SeaGtGruff Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted September 11, 2010 Share Posted September 11, 2010 I'm not that familiar with batari Basic but it would be something like: if (a & $0F) > 9 then a = a + 6 if (a & $F0) > $90 then a = a + $60 Oops, I think I misunderstood what you're doing here. This should be done *after* adding to a, correct? For some reason, I was thinking more along these lines when I first saw your post: if a & $0F > 8 then a = a + 8 else a = a + 1 : rem * to increment the lo nibble by 1, with possible carry if a & $F0 > $80 then a = a + $80 else a = a + $10 : rem * to increment the hi nibble by 1 I think it was because Random Terrain was referring to using a for-next loop, so I was thinking you meant for the ifs to be in a for-next loop. But you're really talking about normalizing the results after adding, with no for-next loop needed. The two ifs I gave above would need to be inside for-next loops of some kind, to increment either the lo nibble or the hi nibble. That's obviously not the best solution, since it would take up a lot of cycles. In retrospect, I think your solution is better than the "AND-OR-AND" solution I originally gave! Michael Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted September 11, 2010 Share Posted September 11, 2010 Hold on, I tried this and it works: a = $42 score = score + a So I guess the old bB problem of adding a variable to the score was corrected somewhere along the way, and I missed it! That's good to know. Michael Quote Link to comment Share on other sites More sharing options...
bogax Posted September 11, 2010 Share Posted September 11, 2010 I'm not that familiar with batari Basic but it would be something like: if (a & $0F) > 9 then a = a + 6 if (a & $F0) > $90 then a = a + $60 Oops, I think I misunderstood what you're doing here. This should be done *after* adding to a, correct? Correct but like I said it's only sure to work if there's no carry out from a digit, which can't happen if what you add <= 6 it should always result in a BCD compliant number but it may not be the right number if you add more than 6 to a digit. Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted September 11, 2010 Author Share Posted September 11, 2010 I may be completely off here because I get 180 not 175so maybe I don't understand what you're doing. Oops. I forgot to mention that I was starting out with a = 5 instead of 0. I'm working on a crappy little game where you shoot playfield pixels. You get bonus points for shooting more than one playfield pixel with the same missile. The first one will be 10 points, second 15, third 20, fourth 25, fifth 30, and so on. I'm not sure what the limit should be. Right now in my tests, a bonus for 7 playfield pixels in a row is the limit. I don't want to give players too many points, but the bonus needs to be high enough to be worth it. I'll have to keep playing with it to see what seems right. Assuming "a" and "score" both start at 0 and both are BCD,65 looks like 41 BCD so the last "a" you add to "score" will be 40 and by that time "score" will be 180 ie presummably the IF statement does't know the difference and just treats both as straight binary. Now I get what I was doing wrong. I knew that by the time I got to around 40, the score should be 175, but I need to put 40 in the hex box, not the decimal box: http://www.randomterrain.com/atari-2600-memories-batari-basic-tools-toys.html#conversion btw you do know that accumulating a constant in "a" thenaccumulating "a" in "score" will make "score" go up quadratically (graph "score" and it will be parabolic) I don't understand them thar big words, but I am trying to add 10, then 15, then 20, then 25, then 30, then 35, and so on. Thanks. Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted September 11, 2010 Author Share Posted September 11, 2010 (edited) Hold on, I tried this and it works: a = $42 score = score + a So I guess the old bB problem of adding a variable to the score was corrected somewhere along the way, and I missed it! That's good to know. Yeah, that works, but try adding to the variable a and you'll have to use one of the solutions posted in this thread. Now that you guys have thought it about it some more, and in case anything has changed, which one should I put on the bB page: Example #1 a = a + $05 temp5 = a & $0F : if temp5 > 9 then a = a + 6 temp5 = a & $F0 : if temp5 > $90 then a = a + $60 score = score + a Example #2 asm sed ; set decimal mode end a = a + $05 asm cld ; clear decimal mode end score = score + a Thanks. Edited September 11, 2010 by Random Terrain Quote Link to comment Share on other sites More sharing options...
bogax Posted September 11, 2010 Share Posted September 11, 2010 You get bonus points for shooting more than one playfield pixel with the same missile. The first one will be 10 points, second 15, third 20, fourth 25, fifth 30, and so on. I'm not sure what the limit should be. Right now in my tests, a bonus for 7 playfield pixels in a row is the limit. I don't want to give players too many points, but the bonus needs to be high enough to be worth it. I'll have to keep playing with it to see what seems right. btw you do know that accumulating a constant in "a" thenaccumulating "a" in "score" will make "score" go up quadratically (graph "score" and it will be parabolic) I don't understand them thar big words, but I am trying to add 10, then 15, then 20, then 25, then 30, then 35, and so on. Thanks. It's probably nothing The score goes up proportional to the square of the number of bonuses you get so it's going to go up fast. Potentially the first points you score could be microscopic compared to the last points you score. Since you limit it to 7 it's not going to get too far out. You know what you want and I don't so take this with a grain of salt, but I would have guessed that a smaller increment for "a" and a larger limit would work better. (And I'm not at all sure I know what's going on with game play so like I said a grain of salt ie I'm probably speaking out of turn, it's just my gut reaction to the numbers) Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted September 11, 2010 Author Share Posted September 11, 2010 (edited) You know what you want and I don't so take this witha grain of salt, but I would have guessed that a smaller increment for "a" and a larger limit would work better. (And I'm not at all sure I know what's going on with game play so like I said a grain of salt ie I'm probably speaking out of turn, it's just my gut reaction to the numbers) Nothing is set in stone. I'm still trying to figure out what is best. If a = a + $02 turns out to be better, I can go with that. The only thing I know for sure is that shooting two pixels with one missile should give the player more points than shooting two pixels with two separate missiles. Thanks. Edited September 11, 2010 by Random Terrain Quote Link to comment Share on other sites More sharing options...
SeaGtGruff Posted September 11, 2010 Share Posted September 11, 2010 Now that you guys have thought it about it some more, and in case anything has changed, which one should I put on the bB page: Example #1 a = a + $05 temp5 = a & $0F : if temp5 > 9 then a = a + 6 temp5 = a & $F0 : if temp5 > $90 then a = a + $60 score = score + a Example #2 asm sed ; set decimal mode end a = a + $05 asm cld ; clear decimal mode end score = score + a Example 2 is the faster and cleaner solution. As bogax stated, example 1 fails if you add more than 6 to a digit; also, it might be harder for a beginner to understand how/why it works. Michael Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted September 11, 2010 Author Share Posted September 11, 2010 (edited) Example 2 is the faster and cleaner solution. As bogax stated, example 1 fails if you add more than 6 to a digit; also, it might be harder for a beginner to understand how/why it works. Thanks. I'll add it tonight. Edited September 12, 2010 by Random Terrain Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 11, 2010 Share Posted September 11, 2010 also, it might be harder for a beginner to understand how/why it works Agreed...that is the important thing. There are other ways of handling the situation depending on how the program is intended to work. One method that's kind of neat is to use a seperate variable (referred to as "Adder" here). When points are scored, they go into the Adder variable...which is regular non-BCD hex. Once per frame, the program executes an assembly portion which looks at Adder's contents. If non-zero, it's DECremented and a decimal routine adds 1 point to the score. So the effect is that you see the point value roll up rather than instantly becoming a new total. asm lda Adder beq No_Points_To_Add dec Adder sed clc lda sc3 adc #1 sta sc3 lda sc2 adc #0 sta sc2 lda sc1 adc #0 sta sc1 cld No_Points_To_Add: end The only drawback to this method is that "Adder" cannot contain more than 255 points at any time. Correcting that would either require an additional variable...or increasing the number of points added to the score for each tick of the variable. Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted September 11, 2010 Author Share Posted September 11, 2010 (edited) Agreed...that is the important thing. There are other ways of handling the situation depending on how the program is intended to work. One method that's kind of neat is to use a seperate variable (referred to as "Adder" here). When points are scored, they go into the Adder variable...which is regular non-BCD hex. . . That's a cool effect. Do you know how I could make Adder be a BCD number? Here's some fake example code: If missile did not hit pfpixel then Skip_Missile_Hit asm sed ; set decimal mode end a = a + $05 asm cld ; clear decimal mode end Adder = a Skip_Missile_Hit asm lda Adder beq No_Points_To_Add dec Adder sed clc lda sc3 adc #1 sta sc3 lda sc2 adc #0 sta sc2 lda sc1 adc #0 sta sc1 cld No_Points_To_Add: end If a is 10, the score would add up to 16. Is there a simple way to make the score add up to 10 instead? Edited September 11, 2010 by Random Terrain Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 11, 2010 Share Posted September 11, 2010 (edited) I should mention that this could also be a way of handling bonus multipliers. Just use that as the amount added in BCD: asm lda Adder beq No_Points_To_Add dec Adder sed clc lda sc3 adc multiplier sta sc3 lda sc2 adc #0 sta sc2 lda sc1 adc #0 sta sc1 cld No_Points_To_Add: end So in Basic, a routine may award 10 points for a specific action (Adder = Adder + 10)...and an additional part of the program could keep track of whether those points are doubled, tripled, etc (multipler = multiplier + 1 if 5 levels have been beaten, for example). In that example, the variable "multiplier" is expected to be BCD...or at the very least, always a low enough value to not matter (1 through 9). Edited September 11, 2010 by Nukey Shay Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted September 11, 2010 Author Share Posted September 11, 2010 No, Adder is non-BCD (trying to force it to be BCD wouldn't work in the above example anyway, since DEC is always a hex operation). If you want to add 10 points, add $0A (decimal 10) to the variable. There's no need to have Adder be BCD. For that matter, there's no need to switch to assembly when increasing it...no need to use seperate A and Adder variables. The assembly routine that slowly bleeds Adder takes care of converting the value as it increases the score in BCD. Thanks. I just drop the decimal mode stuff because it isn't needed for this. My rigid thinking strikes again. Looks like I'll still need Adder, though. If I used a instead of Adder, the score would constantly increase. Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 11, 2010 Share Posted September 11, 2010 Accidentally used edit instead of reply above . Why would the score constantly increase? The assembly portion takes care of reducing the point value being added to the score. It doesn't matter if that variable is called A or Adder. For example, if a shot alien = 15 points, give that to A if you want. if alien = shot then A = A + 15 No assembly. No decimal mode invoked. The assembly portion that reduces A (via DEC) and increases the score takes care of all that. As mentioned, you only need to be concerned with if that value is not bleeding off quickly enough to avoid it rolling over a value of 255 as more points are scored. Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted September 12, 2010 Author Share Posted September 12, 2010 Accidentally used edit instead of reply above . Why would the score constantly increase? The assembly portion takes care of reducing the point value being added to the score. It doesn't matter if that variable is called A or Adder. For example, if a shot alien = 15 points, give that to A if you want. if alien = shot then A = A + 15 No assembly. No decimal mode invoked. The assembly portion that reduces A (via DEC) and increases the score takes care of all that. As mentioned, you only need to be concerned with if that value is not bleeding off quickly enough to avoid it rolling over a value of 255 as more points are scored. I had that wrong. Every time you shoot a missile, a = 5, so if no pfpixels are hit, the player would still get 5 points just for shooting. And a would never increase from 10 to 15 to 20 to 25 to 30 and so on. It would keep getting knocked down to zero. For example, if I shoot two pfpixels with one missile, the score should be 25 (10 + 15). If I don't use Adder and use a instead, the score will be 15 (5 + 5 + 5). Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted September 12, 2010 Author Share Posted September 12, 2010 Accidentally used edit instead of reply above . Why would the score constantly increase? The assembly portion takes care of reducing the point value being added to the score. It doesn't matter if that variable is called A or Adder. For example, if a shot alien = 15 points, give that to A if you want. if alien = shot then A = A + 15 No assembly. No decimal mode invoked. The assembly portion that reduces A (via DEC) and increases the score takes care of all that. As mentioned, you only need to be concerned with if that value is not bleeding off quickly enough to avoid it rolling over a value of 255 as more points are scored. I had that wrong. Every time you shoot a missile, a = 5, so if no pfpixels are hit, the player would still get 5 points just for shooting. And a would never increase from 10 to 15 to 20 to 25 to 30 and so on. It would keep getting knocked down to zero. For example, if I shoot two pfpixels with one missile, the score should be 25 (10 + 15). If I don't use Adder and use a instead, the score will be 15 (5 + 5 + 5). Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted September 12, 2010 Author Share Posted September 12, 2010 The BCD section has been updated. Here's my first draft: http://www.randomterrain.com/atari-2600-memories-batari-basic-commands.html#bcd Quote Link to comment Share on other sites More sharing options...
Nukey Shay Posted September 12, 2010 Share Posted September 12, 2010 I had that wrong. Every time you shoot a missile, a = 5, so if no pfpixels are hit, the player would still get 5 points just for shooting. And a would never increase from 10 to 15 to 20 to 25 to 30 and so on. It would keep getting knocked down to zero. For example, if I shoot two pfpixels with one missile, the score should be 25 (10 + 15). If I don't use Adder and use a instead, the score will be 15 (5 + 5 + 5). Hmm...it's difficult to visualize what you have in mind. It seems that with each successful hit effectively becoming a bonus multiplier, that it wouldn't be long until it becomes unmanageable (reaching astronomical scores with very little effort). IMO it might be better to try to work some kind of decay into the "kitty" that is added for each successful hit. That is to say, that the first successful hit nets 5 points...but 5 is also dumped into a variable that slowly bleeds to zero (i.e. put 5 in the pot, add pot to score). If you score another successful hit, the same thing...5 points to the decaying kitty and dump it's amount to the score. The idea is that if you can hit pixels quickly/accurately, you get higher points each time. Maybe not straight multiples of 5...but certianly higher than 5 points per hit. In that manner, a variable "Decay" would reduce at a set rate...perhaps 1 tick after 8 frames or something. I dunno if bBasic already has some kind of framecounting happening under the hood that you could utilize...but if not, it's not too difficult to come up with something. Because "Decay" would take the place of A in your example and is added directly to the score, it would need to be BCD-compliant. Reducing it (via SBC)/bumping it (via ADC) after successful hits should be preceded by the inline SED instruction to treat it as such. "Adder" would no longer be needed unless you wanted the score to slowly roll visually - which makes the process a bit more involved. To do THAT, instead of dumping whatever point value exists in Decay to the score, give it directly to Adder instead. Adder is then added to the score point-by-point. Neither Decay nor Adder need to be BCD-compliant. As mentioned, the inline routine that bumps the score point-by-point would handle that. 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.