|
Post by minsoft on Oct 13, 2020 4:03:18 GMT -5
I'm trying to display some values as decimals and thought using BCD would be the way to go. I thought I understood the DAA instruction, but it doesn't always do what I expect...
This does what I'd expect, changes $0A to $10:
CLRA ADDA #10 (A = $0A) DAA (A = $10)
This doesn't do what I'd expect...why doesn't it change $10 to $16?:
CLRA ADDA #16 (A = $10) DAA (A = $10)
If $10 can mean 10 or 16 then what use is it?
|
|
|
Post by minsoft on Oct 13, 2020 8:03:59 GMT -5
I've deduced that where I'm going wrong is thinking that I can ADD decimal 16 like that...in order to add 16 I have to add 22 - BCD 0001 0110. Is there a built-in way to convert a number to BCD? Or do I need to write a routine to do that? Essentially I need to convert a value stored in a byte to BCD so I can display it. I thought that ADDing it to A, then doing DAA would do this, which is what I was trying in my original post. (It did seem a bit too easy!)
Edit: It probably does more than I need but I can start off by looking at the bios Add_Score routine as that pretty much does what I'm after.
|
|
|
Post by D-Type on Oct 13, 2020 9:11:36 GMT -5
Displaying a decimal formatted score is trickier/more expensive than it sounds!
If I had my way, I'd use hex for everything :-)
|
|
|
Post by Peer on Oct 13, 2020 12:24:36 GMT -5
Why so complicated?
One way to avoid all the costs of binary to decimal conversion is to store the score as a decimal "string" right from the beginning. In pseudo C notation:
char score[7] = "000000\x80";
You can directly print the score to the screen by using the existing Print_Str routines.
Usually, in a game, the score is only increased. So now write some custom routines which increase the score by a fixed value. Pseudo C:
void inc_score_10() { if ((score[4] += 1) > '9') { score[4] = '0'; if ((score[3] += 1) > '9') { score[3] = '0'; if ((score[2] += 1) > '9') { ... }
} } }
This might look complex, but it is quite simple and straightforward, and also pretty fast. Do this for any amount of points that can be scored in your game:
void inc_score_20(); void inc_socre_50(); void inc_score_100();
Call each specific function whenever the corresponding points are scored.
Yes, increasing the score is now slighty more expensive than just adding a constant to an integer, but you never need to convert between binary and decimal, and you never need to generate a string from whatever other encoding, which is usually much more expensive.
Hope this was understandable, and hope this helps.
Cheers, Peer
|
|
|
Post by minsoft on Oct 13, 2020 16:28:16 GMT -5
Many thanks for the replies.
In this case I am not using it for score, rather for no. shots fired & hits connected. So it isn't so important to be efficient *, since I am only using these values at the end of level, outside of gameplay. Therefore I think in this case I would rather just store the values as normal binary, and do the calculations only when needed. Storing as decimal from the start is an interesting idea though, I may look into that for scoring.
I've been able to use Add_Score_a to do what I need but this is very inefficient as I only need 4 digits max, and I expect this bios routine is doing much more than I need (I don't understand it fully). Also I have to jump through a few hoops to use it as I need, so I should write my own.
* I am using Print_Str_d to display this information (4 lines of text) and it's costing me the best part of 40,000 cycles...so having said the above I could do with saving as many cycles as possible! (Scrapping the idea completely crossed my mind...)
|
|
|
Post by gtoal on Oct 14, 2020 1:55:48 GMT -5
* I am using Print_Str_d to display this information (4 lines of text) and it's costing me the best part of 40,000 cycles...so having said the above I could do with saving as many cycles as possible! (Scrapping the idea completely crossed my mind...) I thought I had a better version of this somewhere but can't put my finger on it right now. Anyway, see if this is faster for you. Should translate fairly easily into assembler if needed. static void SHOW_NUM(signed16 num, signed8 absx, signed8 absy, unsigned16 scale) { // left-aligned
signed8 digit, zeroes;
// If scale is 0, this draws a number starting at the current position, which is at the origin
// of the previous number offset by the number width.
if (scale) position_and_scale(absx, absy, 0x20);
// This replaces code that used divide by 10 and modulo 10. Much faster.
// handles full 16 bit range of -32768:32767 - Uses negative numbers to avoid the issue of negating -32768
if (num >= 0) num = -num; else SHOW_MINUS(); // TO DO: add a font character for '-'.
digit = 0;
zeroes = 1; // CLRing is shorter
// max 11 add/subtracts...
if (num <= -20000) { num += 20000; digit += 2; zeroes = 0; }
if (num <= -10000) { num += 10000; digit += 1; zeroes = 0; }
if (!zeroes) show_digit(digit);
digit = 0;
if (num <= -8000) { num += 8000; digit += 8; zeroes = 0; } else if (num <= -4000) { num += 4000; digit += 4; zeroes = 0; }
if (num <= -2000) { num += 2000; digit += 2; zeroes = 0; }
if (num <= -1000) { num += 1000; digit += 1; zeroes = 0; }
if (!zeroes) show_digit(digit);
digit = 0;
if (num <= -800) { num += 800; digit += 8; zeroes = 0; } else if (num <= -400) { num += 400; digit += 4; zeroes = 0; }
if (num <= -200) { num += 200; digit += 2; zeroes = 0; }
if (num <= -100) { num += 100; digit += 1; zeroes = 0; }
if (!zeroes) show_digit(digit);
digit = 0;
if (num <= -80) { num += 80; digit += 8; zeroes = 0; } else if (num <= -40) { num += 40; digit += 4; zeroes = 0; }
if (num <= -20) { num += 20; digit += 2; zeroes = 0; }
if (num <= -10) { num += 10; digit += 1; zeroes = 0; }
if (!zeroes) show_digit(digit);
show_digit((signed8)-num);
}
|
|
|
Post by minsoft on Nov 10, 2020 13:00:39 GMT -5
Back to my original problem, misunderstanding DAA...I recently got a book ('Programming the 6809') which had a little sample which helped me out. This is my slightly adapted version, to keep count of sector (level) number, up to 4 digits, in BCD. (sector_lo & sector_hi are low & high bytes). Maybe this will be useful for others:
LDA sector_lo ADDA #1 DAA STA sector_lo LDA sector_hi ADCA #0 DAA STA sector_hi
|
|