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

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

##### 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
STA	score+2
LDA	score+1
STA	score+1
LDA	score
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
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

##### 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,

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

##### Share on other sites

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 by RevEng

##### 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
```

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

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

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

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

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

Michael

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

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

##### 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! 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 by Random Terrain

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

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

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

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

Edited by Random Terrain

##### 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
sed
clc
lda  sc3
sta  sc3
lda  sc2
sta  sc2
lda  sc1
sta  sc1
cld
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.

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

Skip_Missile_Hit

asm
sed
clc
lda  sc3
sta  sc3
lda  sc2
sta  sc2
lda  sc1
sta  sc1
cld
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

##### 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
sed
clc
lda  sc3
sta  sc3
lda  sc2
sta  sc2
lda  sc1
sta  sc1
cld
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

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

##### Share on other sites

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.

##### Share on other sites

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

##### Share on other sites

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

##### Share on other sites

The BCD section has been updated. Here's my first draft:

http://www.randomterrain.com/atari-2600-memories-batari-basic-commands.html#bcd

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

## Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.