Jump to content
IGNORED

How do we force a variable to be a BCD compliant number?


Random Terrain

Recommended Posts

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.

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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 by bogax
Link to comment
Share on other sites

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 by Random Terrain
Link to comment
Share on other sites

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)

Link to comment
Share on other sites

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 by SeaGtGruff
Link to comment
Share on other sites

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

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

I may be completely off here because I get 180 not 175

so 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" then

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

Link to comment
Share on other sites

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! :-o That's good to know. :thumbsup:

 

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 by Random Terrain
Link to comment
Share on other sites

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" then

accumulating "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)

Link to comment
Share on other sites

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)

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 by Random Terrain
Link to comment
Share on other sites

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

Link to comment
Share on other sites

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 by Random Terrain
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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 by Random Terrain
Link to comment
Share on other sites

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 by Nukey Shay
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

Accidentally used edit instead of reply above :P.

 

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.

Link to comment
Share on other sites

Accidentally used edit instead of reply above :P.

 

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

Link to comment
Share on other sites

Accidentally used edit instead of reply above :P.

 

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

Link to comment
Share on other sites

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.

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