Truncated match.
PICList
Thread
'Binary to BCD'
1997\03\03@211117
by
John Dammeyer
|
In comp.arch.embedded a discussion went on, for a while, about the merits of
assembler verses C.
Don Yuniskis posted this little gem as an example of an efficient 16 bit
Binary to
4 digit Binary Coded Decimal routine.
Don wrote:
-->>
Here's one version of a binary-decimal conversion routine.
Call with r.hl having binary value; returns 4 digit packed BCD
in r.de -- I neglected the fifth digit :-( It can be
rewritten to preserve that extra digit. To produce ASCII,
obviously you can append a code fragment to add '0' to each
unpacked digit.
BinDec: LD B,16 ;7
LD DE,0 ;10
Loop: ADD HL,HL ;11
LD A,E ;4
ADC A,A ;4
DAA ;4
LD E,A ;4
LD A,D ;4
ADC A,A ;4
DAA ;4
LD D,A ;4
DJNZ Loop ;13/8
RET ;10
<<--
I wrote:
Of course it only works if the processor has a
DAA instruction. (Decimal Adjust Accumulator). I mentioned at the time
that both the PIC
and the 68HC05 don't have a DAA instruction and so his routine wouldn't
work. To date I
have been using the slower 16 bit to 5 digit algo. that uses the divide and
makes use of
the location that holds the remainder after a divide. It uses three bytes
of RAM and
calls the divide routine. Not a big deal if 16 bit divide is used elsewhere
and has to
be part of the application anyway.
-->>
unsigned long
ubcd(void) {
unsigned long ulResult; // Working result and arg.
unsigned int i; // loop counter
ulResult = 0;
for (i=0; i<16; i+=4) {
ulArg = ulArg / 10; // get rid of LS Digit
long_q <<= i; // put remainder in correct position.
ulResult |= long_q; // add to result
}
return ulResult; // packed BCD.
};
<<--
However the penalty in using the divide is fairly high as it shifts through
the 16 bit
quotient 16 times. Don's routine looked attractive as it also walks through
the 16 bit
binary value but only once, not five times.
So I have cloned the DAA instruction
and rewritten his routine to also generate 5 digits instead of 4. It's
written in C and
before anyone has a heart failure be aware that I wrote it in Assembler
first. Then
re-wrote it in C in a way that simulated as much of my assembler as
possible. This makes
it easier to shove it around in the source file without worrying about page
bits etc.
Assembler would be a few bytes smaller where the C compiler generates
redundant code.
The goto is there to allow this routine to be replicated three times instead
of being
used as a subroutine. Why? Because the 16C57 only has a two level stack.
BTW, Dag Bakken should note that I do indeed take advantage of the type of
code
generated by the compiler when I:
"argument + 0x66; // set C,DC flags with trial add."
I still believe that a compiler should not even generate code for this but
the MPC does
and I take advantage of it. It could 'break' in the future though with a
new compiler release which is why I really don't like doing it. <grin>
// Decimal Adjust Accumulator simulation
// Argument is the value to decimal adjust.
// Must be called immediately after addition in order to not lose
// status of CARRY and DIGIT CARRY bits in status register.
// ie: a hidden argument is the status register.
unsigned char
DAA(unsigned char argument) {
Flags.DAA_FLAG = 0; // Flag for doing code twice.
Flags.Carry = STATUS.C; // Mustn't clear if already set.
while (1) { // this could be a label that we goto.
DAA_VALUE = 0; // Clear DAA adder.
// Now custruct DAA adder
if (STATUS.DC) { // if a Half carry occured then make BCD
DAA_VALUE = 6; // by adding 6 lower digit.
};
if (STATUS.C) { // If a full carry occured make BCD digit by
DAA_VALUE |= 0x60; // adding 6 to upper digit.
};
// If digits overflowed from addition
// we now make them BCD again.
argument += DAA_VALUE; // DAA_VALUE can be 0x00, 0x06, 0x66
if (Flags.DAA_FLAG) // We do above code twice.
goto DONE_DAA; // This is how we get out.
Flags.DAA_FLAG = 1;
// Secondly test if BCD digits are in 'A'..'F' range byt a trial add.
argument + 0x66; // set flags with trial add.
};
DONE_DAA:
// Carry might be already be 1 so we cannot just assign passed parameter
CARRY flag
// which might have been zero.
if (Flags.Carry) STATUS.C = 1;
return(argument);
};
unsigned char de0,de1,de2;
int counter;
unsigned long hl;
// Binary to Decimal Conversion routine 16bit to 5 digit.
// Parameter is passed in global var. 'hl' and is cleared when complete.
// result is in 'de0,de1,de2' where 'de0' is least sig digits.
// Uses 8 bit counter to walk through binary number.
void
BinDec() {
de0 = 0; // Clear result accumulator.
de1 = 0;
de2 = 0;
counter = 16; // All 16 bits of argument.
do {
hl <<= 1; // Put MSb into Carry.
// Now if we had a ADC instruction this part wouldn't be needed.
WREG = 0;
if (STATUS.C)
WREG = 1;
// Simulate the Add with carry operation.
// At first glance it appears like a RLF would do the same thing but
// we need the STATUS.DC set if there is a digit overflow.
// 68HC05 does have ADC instruction.
de0 += de0 + WREG;
// After addition do a decimal adjust.
de0 = DAA(de0);
// if there was an overflow from the previous addition add it into
// the next BCD digits.
WREG = 0;
if (STATUS.C)
WREG = 1;
de1 += de1 + WREG;
de1 = DAA(de1);
WREG = 0;
if (STATUS.C)
WREG = 1;
de2 += de2 + WREG;
de2 = DAA(de2);
} while (--counter);
};
Finally I do welcome all input. Especially if someone can improve on the
speed/space of this one.
Cheers,
John.
Pioneers are the ones, face down in the mud,
with arrows in their backs.
Automation Artisans Inc. Ph. 1-250-544-4950
PO Box 20002 Fax 1-250-544-4954
Sidney, BC CANADA V8L 5C9
1997\03\04@004247
by
Steve Hardy
|
{Quote hidden}> From: John Dammeyer <
spam_OUTjohndTakeThisOuT
ISLANDNET.COM>
> [cut]
> Here's one version of a binary-decimal conversion routine.
> Call with r.hl having binary value; returns 4 digit packed BCD
> in r.de -- I neglected the fifth digit :-( It can be
> rewritten to preserve that extra digit. To produce ASCII,
> obviously you can append a code fragment to add '0' to each
> unpacked digit.
>
> BinDec: LD B,16 ;7
> LD DE,0 ;10
>
> Loop: ADD HL,HL ;11
>
> LD A,E ;4
> ADC A,A ;4
> DAA ;4
> LD E,A ;4
>
> LD A,D ;4
> ADC A,A ;4
> DAA ;4
> LD D,A ;4
>
> DJNZ Loop ;13/8
>
> RET ;10
> [cut]
Hmmm... suspiciously like Z80 code, even down to the clock cycle
counts, no?
> Finally I do welcome all input. Especially if someone can improve on the
> speed/space of this one.
DAA is a bit tekno for this task. My philosophy when it comes to
binary to decimal decoding is that decimal is almost always used
by humans (or printers) and hence speed is not an overriding concern.
I would go for the most compact code. Successive subtraction of
powers of ten would be my first choice. Actual division is
certainly unnecessary. Converting an unsigned 16-bit number to
5-digit decimal requires a maximum of 27 2-byte subtractions,
20 1-byte subtractions and 5 additions.
Yes of course there are much smarter ways, but this is easy to
understand and can be implemented fairly easily (even on a PIC).
Now I realise there are always exceptions, but if you find yourself
requiring more than a few decimal conversions per second, then rethink
the application because no human can read that fast.
Regards,
SJH
Canberra, Australia
1997\03\04@030036
by
John Dammeyer
|
At 04:41 PM 04/03/1997 EST, you wrote:
{Quote hidden}>> From: John Dammeyer <
.....johndKILLspam
@spam@ISLANDNET.COM>
>> [cut]
>> Here's one version of a binary-decimal conversion routine.
>> Call with r.hl having binary value; returns 4 digit packed BCD
>> in r.de -- I neglected the fifth digit :-( It can be
>> rewritten to preserve that extra digit. To produce ASCII,
>> obviously you can append a code fragment to add '0' to each
>> unpacked digit.
>>
>> BinDec: LD B,16 ;7
>> LD DE,0 ;10
>>
>> Loop: ADD HL,HL ;11
>>
>> LD A,E ;4
>> ADC A,A ;4
>> DAA ;4
>> LD E,A ;4
>>
>> LD A,D ;4
>> ADC A,A ;4
>> DAA ;4
>> LD D,A ;4
>>
>> DJNZ Loop ;13/8
>>
>> RET ;10
>> [cut]
>
>Hmmm... suspiciously like Z80 code, even down to the clock cycle
>counts, no?
Yup!
{Quote hidden}>
>
>> Finally I do welcome all input. Especially if someone can improve on the
>> speed/space of this one.
>
>
>DAA is a bit tekno for this task. My philosophy when it comes to
>binary to decimal decoding is that decimal is almost always used
>by humans (or printers) and hence speed is not an overriding concern.
>I would go for the most compact code. Successive subtraction of
>powers of ten would be my first choice. Actual division is
>certainly unnecessary. Converting an unsigned 16-bit number to
>5-digit decimal requires a maximum of 27 2-byte subtractions,
>20 1-byte subtractions and 5 additions.
Please do post it. ie: Put your opcodes down as evidence.
>
>Yes of course there are much smarter ways, but this is easy to
>understand and can be implemented fairly easily (even on a PIC).
>
>Now I realise there are always exceptions, but if you find yourself
>requiring more than a few decimal conversions per second, then rethink
>the application because no human can read that fast.
Well, the 16C57 doesn't have interrupts. I need to service I/O quite
frequently. I can't afford to spend a large amount of time in a subroutine
- including divide. The above algo. lends itself nicely to an iterative
approach.
ie: Using a flag, enter the routine, shift and calculate, leave the routine.
Do this 16 times and then set another flag that a different routine can use
as a conversion complete signal. If tiem wasn't an object here or I was
using a PIC/8HC05 with interrupt support for time critical I'd stay with the
divide algo. Short, simple, easy to follow as long as the 16 bit divide was
needed elsewhere.
Reagrds,
John
Pioneers are the ones, face down in the mud,
with arrows in their backs.
Automation Artisans Inc. Ph. 1-250-544-4950
PO Box 20002 Fax 1-250-544-4954
Sidney, BC CANADA V8L 5C9
1997\03\04@095515
by
Andy Kunz
>
>BinDec: LD B,16 ;7
> LD DE,0 ;10
>
>Loop: ADD HL,HL ;11
>
> LD A,E ;4
> ADC A,A ;4
> DAA ;4
> LD E,A ;4
>
> LD A,D ;4
> ADC A,A ;4
> DAA ;4
> LD D,A ;4
>
> DJNZ Loop ;13/8
>
> RET ;10
Ah, Z-80, my first, true love. And in Zilog mnemonics, no less!
Andy
==================================================================
Andy Kunz - Montana Design - 409 S 6th St - Phillipsburg, NJ 08865
Hardware & Software for Industry & R/C Hobbies
"Go fast, turn right, and keep the wet side down!"
==================================================================
1997\03\04@191430
by
Steve Hardy
|
> From: John Dammeyer <johnd
KILLspamISLANDNET.COM>
> >[cut]
> >DAA is a bit tekno for this task. My philosophy when it comes to
> >binary to decimal decoding is that decimal is almost always used
> >by humans (or printers) and hence speed is not an overriding concern.
> >I would go for the most compact code. Successive subtraction of
> >powers of ten would be my first choice. Actual division is
> >certainly unnecessary. Converting an unsigned 16-bit number to
> >5-digit decimal requires a maximum of 27 2-byte subtractions,
> >20 1-byte subtractions and 5 additions.
>
> Please do post it. ie: Put your opcodes down as evidence.
So you want me to put my code where my mouth is? Well I've never
needed to actually do this (let alone on a '57, since I've always
used the '74 and '84). Time does not permit me to give a real
implementation so you will have to be satisfied with pseudo C-code.
This code would translate in a fairly straightforward way into
16C57 code. Obviously, some of the code could be 'commoned'.
Contrary to my previous post this will take a worst case, for
conversion of the number 5999x, of 26 2-byte subs, 10 1-byte subs,
3 2-byte adds and 2 1-byte adds -- not counting the digit increments.
The subtractions could be replaced by additions of -ve numbers if
that makes it easier.
The conversion procedure is broken up into very small bites so
that your non-interrupt-capable processor will have only a small
latency between checking for I/O etc.
enum state { start, finish, sub10k, sub1k, sub100, sub10 }
int binary
int divisor
char digit[5]
void bin2dec()
{
switch (state)
{
case start:
state = sub10k
digit[0] = digit[1] = ... = digit[4] = '0'
divisor = 10000
return
case sub10k:
binary -= divisor
if (binary < 0) [i.e. MSB of binary changed from 0 to 1]
{
binary += divisor
state = sub1k
divisor = 1000
}
else
digit[0]++
return
case sub1k:
binary -= divisor
if (binary < 0)
{
binary += divisor
state = sub100
divisor = 100
}
else
digit[1]++
return
case sub100:
binary -= divisor
if (binary < 0)
{
binary += divisor
state = sub10
divisor = 10
}
else
digit[2]++
return
case sub10:
binary -= divisor [S.B. - single byte op]
if (binary < 0)
{
binary += divisor [S.B.]
state = finish
digit[4] += binary [S.B.]
}
else
digit[3]++
return
}
}
main()
{
...
binary = [binary value to decode]
state = start
while (state != finish)
{
bin2dec()
[do something else e.g. service I/O]
}
print("decimal = %c%c%c%c%c", digit[0], digit[1], ..., digit[4])
}
Regards,
SJH
Canberra, Australia
1997\03\05@040521
by
John Dammeyer
|
At 11:12 AM 05/03/1997 EST, you wrote:
>> From: John Dammeyer <.....johndKILLspam
.....ISLANDNET.COM>
<snip>
>The conversion procedure is broken up into very small bites so
>that your non-interrupt-capable processor will have only a small
>latency between checking for I/O etc.
I'll take a crack at it but I won't use the switch. The extra code penalty
without the ability to use a jump table on a PIC is much too high. This is
not meant as a criticism as I realize you whipped this out on the fly. The
cost of walking down to 'case sub10:' nine times in a switch statement is
expensive. I am not sure that this is actually any faster (or smaller) than
the DAA method. And yes, negative constants are usually better.
I'll post the result when I'm done and like your example I'll make it small
bite capable. BTW, to be fair you need to pack the result; mine was.
8-). Or else I need to unpack mine 8-(.
Cheers,
John
Pioneers are the ones, face down in the mud,
with arrows in their backs.
Automation Artisans Inc. Ph. 1-250-544-4950
PO Box 20002 Fax 1-250-544-4954
Sidney, BC CANADA V8L 5C9
1997\03\05@052040
by
Andrew Warren
|
John Dammeyer <EraseMEPICLISTspam_OUT
TakeThisOuTMITVMA.MIT.EDU> wrote:
> The extra code penalty without the ability to use a jump table on a
> PIC is much too high.
John:
Jump tables are trivially easy (and fast) on the PIC:
MOVF STATE,W ;switch (state)
ADDWF PCL ;{
;
GOTO CASE0 ; case 0: ....
GOTO CASE1 ; case 1: ....
GOTO CASE2 ; case 2: ....
etc... ;}
On some parts, you need to do a little fiddling with the PCLATH
register, but I'm sure you get the idea.
> I'll post the result when I'm done and like your example I'll make
> it small bite capable. BTW, to be fair you need to pack the
> result; mine was. 8-). Or else I need to unpack mine 8-(.
If you can deal with an unpacked result, just use the excellent
routine that John Payson posted here a few months ago. It's
extremely fast, easily broken-up into small pieces, and it takes
very little code space.
Since John has inexplicably decided not to end this binary-to-BCD
thread by reposting it, I will (repost it, that is... Feel free
to continue the thread):
-------------------------------------------------------------------
;
; Binary-to-BCD. Written by John Payson.
;
; Enter with 16-bit binary number in NumH:NumL.
; Exits with BCD equivalent in TenK:Thou:Hund:Tens:Ones.
;
org $0010 ;Start of user files for 16c84
NumH: ds 1
NumL: ds 1
TenK: ds 1
Thou: ds 1
Hund: ds 1
Tens: ds 1
Ones: ds 1
Convert: ; Takes number in NumH:NumL
; Returns decimal in
; TenK:Thou:Hund:Tens:Ones
swapf NumH,w
andlw $0F ;*** PERSONALLY, I'D REPLACE THESE 2
addlw $F0 ;*** LINES WITH "IORLW 11110000B" -AW
movwf Thou
addwf Thou,f
addlw $E2
movwf Hund
addlw $32
movwf Ones
movf NumH,w
andlw $0F
addwf Hund,f
addwf Hund,f
addwf Ones,f
addlw $E9
movwf Tens
addwf Tens,f
addwf Tens,f
swapf NumL,w
andlw $0F
addwf Tens,f
addwf Ones,f
rlf Tens,f
rlf Ones,f
comf Ones,f
rlf Ones,f
movf NumL,w
andlw $0F
addwf Ones,f
rlf Thou,f
movlw $07
movwf TenK
; At this point, the original number is
; equal to
TenK*10000+Thou*1000+Hund*100+Tens*10+Ones ;
if those entities are regarded as two's
compliment ; binary. To be precise, all of
them are negative ; except TenK. Now the
number needs to be normal- ; ized, but this
can all be done with simple byte ; arithmetic.
movlw $0A ; Ten
Lb1:
addwf Ones,f
decf Tens,f
btfss 3,0
goto Lb1
Lb2:
addwf Tens,f
decf Hund,f
btfss 3,0
goto Lb2
Lb3:
addwf Hund,f
decf Thou,f
btfss 3,0
goto Lb3
Lb4:
addwf Thou,f
decf TenK,f
btfss 3,0
goto Lb4
retlw 0
-------------------------------------------------------------------
-Andy
=== Andrew Warren - fastfwd
spam_OUTix.netcom.com
=== Fast Forward Engineering - Vista, California
===
=== Custodian of the PICLIST Fund -- For more info, see:
=== www.geocities.com/SiliconValley/2499/fund.html
1997\03\05@174655
by
John Dammeyer
|
At 02:27 AM 05/03/1997 -0800, you wrote:
>John Dammeyer <@spam@PICLISTKILLspam
MITVMA.MIT.EDU> wrote:
>
>> The extra code penalty without the ability to use a jump table on a
>> PIC is much too high.
>
> John:
>
> Jump tables are trivially easy (and fast) on the PIC:
>
> MOVF STATE,W ;switch (state)
> ADDWF PCL ;{
> ;
> GOTO CASE0 ; case 0: ....
> GOTO CASE1 ; case 1: ....
> GOTO CASE2 ; case 2: ....
> etc... ;}
>
> On some parts, you need to do a little fiddling with the PCLATH
> register, but I'm sure you get the idea.
True. In assembler this is a snap as long as it all fits in the one page.
If it doesn't then
there can be a second level of indirect jumps. In either case a combination
of assembler and C would make Case Statements more efficient.
eg:
Jump tables are trivially easy (and fast) on the PIC when
jump tables are placed in the same page.
MOVF STATE,W ;switch (state)
ADDWF PCL ;{
;
GOTO _CASE0 ; case 0: ....
GOTO _CASE1 ; case 1: ....
GOTO _CASE2 ; case 2: ....
_CASE0:
BSF STATUS,PA0
BCF STATUS,PA1
GOTO CASE0
_CASE1:
etc...
There is just more administration needed to keep all this organized. It
would be nice it the C compiler gave me the option to have this type of case
statement.
{Quote hidden}>
>> I'll post the result when I'm done and like your example I'll make
>> it small bite capable. BTW, to be fair you need to pack the
>> result; mine was. 8-). Or else I need to unpack mine 8-(.
>
> If you can deal with an unpacked result, just use the excellent
> routine that John Payson posted here a few months ago. It's
> extremely fast, easily broken-up into small pieces, and it takes
> very little code space.
>
As promised. Here is the C version of Steve Hardy's binary to BCD routine.
I've modified it to handle 16 bit unsigned integers. It can be called from
within the mainline polling loop so that the processor isn't tied down to
doing conversions.
What is interesting is the speed and code size is much smaller than the DAA
simulation; kudos to Steve for the idea. I've also taken advantage of
having access to the Carry flag to let it handle 16 bit unsigned 16 bit
ints. With the exception of a few places where the compiler adds redundent
PA0,PA1 bit setting for GOTO support the code generated isn't much slower or
bigger than what would be generated by directly doing this in assembler.
The most interesting part is the time taken to do each little bit - about 43
clocks on average. At 20MHz this is only 8.2 uSec and may be the best
technique to avoid impacting the polling of other I/O.
Size of DAA simulation method 94 instructions
Execution speed for 59,999 (0xEA5F) -> 2798 clocks
Size of DECIMAL SUBTRACTION method 86 instructions
Execution speed -> 1575 clocks
Average execution time for each call -> 43 clocks
Size of BCD using 16 bit division 57 instructions
Execution speed -> 2543 clocks.
I have not included the 16/16 divide as I assume it would be used elsewhere
in the application.
Conclusions so far...
If you need 16 bit divide anyway and speed isn't a problem use the inelegant
divide technique; it's easy to understand and document and IMHO a well
documented and easy to understand program is part of a correctly functioning
program.
If you need speed and space ... use Steve Hardy's successive subtraction
method. It could be made faster by doing doing all the conversion in one
time rather than in bits.
As for John Payson's method. Haven't gotton to it yet. But the assembler
version obviously takes 50 instructions. How much time is spent in the
loops? Don't know yet. It will probably be the fastest and the smallest;
understanding how it works may be more difficult.
Now I must stop having fun get back to real work. 8-)
Cheers
John.
-->>
// Default for compiler is set to 8 bit ints and 16 bit longs.
bits bcdFlags;
#define COMPLETE bcdFlags.0
int digit[5];
unsigned long binary;
unsigned long divisor;
int digitNumber;
unsigned int
bin2dec () {
if (COMPLETE) {
digit[0] = 0; // LSDigit
digit[1] = 0;
digit[2] = 0;
digit[3] = 0;
digit[4] = 0; // MSdigit
COMPLETE = 0;
digitNumber = 4;
divisor = 10000;
}
else {
binary -= divisor;
if (!STATUS.C) {
binary +=divisor;
if (--digitNumber == 0) {
COMPLETE = 1;
digit[digitNumber] = binary;
}
else {
if (digitNumber == 3)
divisor = 1000;
else if (digitNumber == 2)
divisor = 100;
else
divisor = 10;
}
}
else {
digit[digitNumber]++;
};
};
return COMPLETE;
}
main() {
COMPLETE = 1; // Signal that bin2dec() may convert a new value.
binary = 0; // force to known value.
while (1) {
if (bin2dec()) { // returns TRUE if conversion complete.
Display_BCD_Data(); // Put on LCD or LED display.
// Now get new data to display.
binary = CreateNewBinaryValueToDisplay();
};
// Do other real time processing every 10 uSeconds or so with a 20MHz
// processor.
}
}
<<--
Pioneers are the ones, face down in the mud,
with arrows in their backs.
Automation Artisans Inc. Ph. 1-250-544-4950
PO Box 20002 Fax 1-250-544-4954
Sidney, BC CANADA V8L 5C9
1997\03\05@183315
by
sdattalo
|
John Dammeyer wrote:
>
>
> As for John Payson's method. Haven't gotton to it yet. But the assembler
> version obviously takes 50 instructions. How much time is spent in the
> loops? Don't know yet. It will probably be the fastest and the smallest;
> understanding how it works may be more difficult.
Well, according to Bob Fehrenbach timing analysis:
(NB: 49 program memory locations. Executes in
153 to 198 clock cycles (worst case I could find) BF)
And according to my dissection (which I posted last November) in
response to a challenge from John:
If you have a 4 digit hexadecimal number, it may be written as
N = a_3*16^3 + a_2*16^2 + a_1*16 + a_0
where a_i, i=0,1,2,3 are the four hexadecimal digits. If you
wish to convert this to decimal, then you need to express N as
N = b_4*10^4 + b_3*10^3 + b_2*10^2 + b_1*10 + b_0
Where b_j, j=0,1,2,3,4 are the five decimal digits.
The reason there are 5 digits in the decimal representation
is because the maximum four digit hexadecimal number (0xffff)
requires 5 decimal digits (65535). Now the goal is to find
a set of equations that allow the b_j's to be expressed in
terms of the a_i's. There are infinitely many ways to do this.
Here are two of probably the simplest expressions.
First, expand the 16^i's and then collect all coefficients
of the 10^j's:
N = a_3*4096 + a_2*256 + a_1*16 + a_0
= a_3*4*10^3 + a_2*2*10^2 + (a_3*9 + a_2*5 + a_1)*10 +
6*(a_3 + a_2 + a_1) + a_0
This gives us five equations:
b_0 = 6*(a_3 + a_2 + a_1) + a_0
b_1 = a_3*9 + a_2*5 + a_1
b_2 = 2*a_2
b_3 = 4*a_3
b_4 = 0
Which as John says, must be "normalized". Normalization in
this context means we need to reduce the b_j's such that
0 <= b_j <= 9
In other words we need to find:
c_0 = b_0 mod 10
b_1 = (b_1 + (b_0 - c_0)/10)
c_1 = b_1 mod 10
b_2 = (b_2 + (b_1 - c_1)/10)
c_2 = b_2 mod 10
b_3 = (b_3 + (b_2 - c_2)/10)
c_3 = b_3 mod 10
c_4 = (b_4 + (b_3 - c_3)/10) mod 10
= (b_2 - c_2)/10
Division by 10 can be done quite efficiently (as was shown
in another thread several months ago). However, it does require
a significant amount of code space compared to say repeated
subtractions. Unfortunately, there can be very many subtractions
that are required. For example, b_1 could be as large as 15*16,
or 240. 10 would have to be subtracted 24 times if you wish to
compute 240 mod 10. I presume John realized this inefficiency
and thus sought to express N so that repeated subtractions
could be used and that the total number of subtractions are
minimized. This leads to the next way that N can be expressed:
N = a_3*(4100 - 4) + a_2*(260 - 4) + a_1*(20-4) + a_0
= 4*a_3*10^3 + (a_3 + 2*a_2)*10^2 + (6*a_2 + 2*a_1)*10 +
a_0 - 4*(a_3 + a_2 + a_1)
This gives five new equations for the b_j's.
b_0 = a_0 - 4*(a_3 + a_2 + a_1)
b_1 = 6*a_2 + 2*a_1
b_2 = a_3 + 2*a_2
b_3 = 4*a_3
b_4 = 0
However, these equations are still not conducive to the
repeated subtraction algorithm, at least the way John has
done it. In other words, it is possible to pre-condition
each of the b_j's so that they are less than zero. Then
the repeated subtractions can simultaneously perform the
"mod 10" and "/10" operations shown above. Consider the
equation b_0 for example,
b_0 = a_0 - 4*(a_3 + a_2 + a_1)
Since each a_i must satisfy: 0 <= a_i <= 15, then b_0
ranges:
-60 <= b_0 <= 15
We can make b_0 negative by subtracting any number greater than
15. A logical choice is 20. This is because if we subtract 20
from b_0, we can add 2 to b_1 to keep the net result the same.
The reason we add "2" can be seen:
b_1*10 + b_0 = b_1*10 + b_0 + 20 - 20
= (b_1 + 2)*10 + b_0 - 20
Carrying this concept out for the rest of the b_i's we have.
b_0 = a_0 - 4*(a_3 + a_2 + a_1) - 20
b_1 = 6*a_2 + 2*a_1 + 2 - 140
= 6*a_2 + 2*a_1 - 138
b_2 = a_3 + 2*a_2 + 14 - 60
= a_3 + 2*a_2 - 46
b_3 = 4*a_3 + 6 - 70
= 4*a_3 - 64
b_4 = 0 + 7
= 7
And if you look at John's code closely, you will see this is
how he has expressed the b_j's.
Scott
PS The jury is out...
1997\03\06@100304
by
Site Y
There is a borderline elegant routine for Binary to BCD conversion in
Appendix H of AN-526, which can be found in the Microchip Embedded
Control Handbook, 1995 editon. The original version of this appeared to
the best of my knowledge in the General Instrument PIC Applications
Manual, August 1980 (Note: no typo... 1 9 8 0)
The routine as presented by GI/Microchip can be further optimized by
about 5 instructions and 100 or so cycles. It can also be incorporated
into a divide routine (if you happen to need to convert the output of a
binary divide to BCD) for even greater instruction/execution economy.
Site Y
'Binary to BCD'
1998\02\28@191401
by
Bill Kennedy
Anyone have any subs that convert a 12 bit binary serial input to 4 BCD
numbers that are possibly stored in registers to send out to to
displays?
thanks in advance for any suggestions
'Binary to BCD'
1998\03\02@051214
by
Peter Baines
|
Bill, Try this code. I have used it in a recent project. I hope it helps
Peter.
;
***************************************************************************
; ASSIGN LABELS TO THE VARIOUS (RAM) DATA FILE REGISTERS USED
;
***************************************************************************
R0 RES 1 ; DECIMAL STORE FOR 1S DIGIT
R1 RES 1 ; DECIMAL STORE FOR 10S DIGIT
R2 RES 1 ; DECIMAL STORE FOR 100S DIGIT
DIGIT1 RES 1 ; STORE FOR RIGHT DISPLAY DATA
DIGIT2 RES 1 ; STORE FOR R/MIDDLE DISPLAY DATA
DIGIT3 RES 1 ; STORE FOR L/MIDDLE DISPLAY DATA
DIGIT4 RES 1 ; STORE FOR LEFT DISPLAY DATA
; *******************************************************
; * BCD CONVERSION
; *******************************************************
B2_BCD MOVFW COUNTER_LOW
MOVWF IPBUFFL
MOVFW COUNTER_HIGH
MOVWF IPBUFFH
BCF STATUS,CARRY ; NOW CONVERT THE 16 BIT NUMBER
MOVLW 16 ; INTO 5 BCD CHARACTERS - THE UPPER BCD
MOVWF COUNT1 ; IS NOT DISPLAYED BUT HAS BEEN LEFT IN
CLRF R0 ; FOR FUTURE USE
CLRF R1
CLRF R2
LOOP16 RLF IPBUFFL,F ; COUNT BUFFER LOW BYTE
RLF IPBUFFH,F ; COUNT BUFFER HIGH BYTE
RLF R2,F
RLF R1,F
RLF R0,F
DECFSZ COUNT1,F ;DECRIMENT AND SKIP IF ZERO
GOTO ADJDEC
GOTO BCDCON
ADJDEC MOVLW R2
MOVWF FSR
CALL ADJBCD
MOVLW R1
MOVWF FSR
CALL ADJBCD
MOVLW R0
MOVWF FSR
CALL ADJBCD
GOTO LOOP16
BCDCON ; CONVERT THE 4 BCD DIGITS INTO THE CORRECT
SWAPF R1,W ; FORMAT FOR THE LED BIT PATTEN.
ANDLW 0FH ; STRIP UPPER BITS
CALL GETCHAR
MOVWF DIGIT4
MOVFW R1
ANDLW 0FH ; STRIP UPPER BITS
CALL GETCHAR
MOVWF DIGIT3
SWAPF R2,W
ANDLW 0FH ; STRIP UPPER BITS
CALL GETCHAR
MOVWF DIGIT2
MOVFW R2
ANDLW 0FH ; STRIP UPPER BITS
CALL GETCHAR
MOVWF DIGIT1
RETURN
;***************************************************************************
**
; ADJUST FOR BCD
;***************************************************************************
**
ADJBCD MOVLW 3
ADDWF 0,W
MOVWF TEMP
BTFSC TEMP,3 ; TEST IF RESULT > 7
MOVWF 0
MOVLW 30H
ADDWF 0,W
MOVWF TEMP
BTFSC TEMP,7 ; TEST IF RESULT > 7
MOVWF 0 ; SAVE AS MSD
RETLW 0
;***************************************************************************
**
; GET A DISPLAY CHARACTER BIT PATTERN BY CONVERTING 'W' TO DISPLAY CODE
;***************************************************************************
**
GETCHAR
ADDWF PC,F ; USE 'W' AS AN OFFSET FOR 'PC'
RETLW B'00111111' ; RETURN WITH "0" DISPLAY CODE
RETLW B'00000110' ; RETURN WITH "1" DISPLAY CODE
RETLW B'01011011' ; RETURN WITH "2" DISPLAY CODE
RETLW B'01001111' ; RETURN WITH "3" DISPLAY CODE
RETLW B'01100110' ; RETURN WITH "4" DISPLAY CODE
RETLW B'01101101' ; RETURN WITH "5" DISPLAY CODE
RETLW B'01111101' ; RETURN WITH "6" DISPLAY CODE
RETLW B'00000111' ; RETURN WITH "7" DISPLAY CODE
RETLW B'01111111' ; RETURN WITH "8" DISPLAY CODE
RETLW B'01100111' ; RETURN WITH "9" DISPLAY CODE
RETLW B'01110111' ; RETURN WITH "A" DISPLAY CODE
RETLW B'01111100' ; RETURN WITH "B" DISPLAY CODE
RETLW B'00111001' ; RETURN WITH "C" DISPLAY CODE
RETLW B'01011110' ; RETURN WITH "D" DISPLAY CODE
RETLW B'01111001' ; RETURN WITH "E" DISPLAY CODE
RETLW B'01110001' ; RETURN WITH "F" DISPLAY CODE
====================================
Remember .... Every Silver Lining
Has It's Cloud
====================================
Mailto:KILLspamefocKILLspam
cyberstop.net
'Binary to BCD'
1998\10\14@205851
by
Sean Breheny
Hi all,
I am trying to do 16 bit binary to BCD conversion and it is becomming much
more complicated than I had initially anticipated. As far as I can see,
there are only two ways to accomplish it:
1) Integer Division by 10 (and using the remainders as the resultant digits)
2) Using a lookup table for each resultant digit to find the "contribution"
from each bit of the input number (i.e., for the hundreds digit, bits 0
thru 6 contribute zero, but bit 7 adds 100, bit 8 adds 200, bit 9 adds 500,
so you add up each of these contributions, modulo ten, and place the result
as the hundreds digit, and carry over what's left to the next digit's
contribution).
Both of these take up considerable code and register space (for method one,
I'd need a 16bit division by ten routine as well as several pairs of 8bit
file regs, for method 2 I'd need about 40 words of lookup space in addition
to some code).
Can someone provide a sanity check? Is there something I'm not seeing?
I realize that there is probably boilerplate code out there for this, and I
may ultimately resort to that, but for now, I only want to borrow ideas
from it at most, I want to write this code for its educational value.
Thanks,
Sean
+-------------------------------+
| Sean Breheny |
| Amateur Radio Callsign: KA3YXM|
| Electrical Engineering Student|
+-------------------------------+
Save lives, please look at http://www.all.org
Personal page: http://www.people.cornell.edu/pages/shb7
RemoveMEshb7TakeThisOuT
cornell.edu Phone(USA): (607) 253-0315 ICQ #: 3329174
1998\10\14@211107
by
Lee Jones
> I am trying to do 16 bit binary to BCD conversion and it is becomming
> much more complicated than I had initially anticipated. As far as I
> can see, there are only two ways to accomplish it:
> 1) Integer Division by 10 (remainders [are] digits)
> 2) Using a lookup table for each resultant digit to find the
> "contribution" from each bit of the input number
How about:
3) repeated subtraction of 10000, 1000, 100, 10; remainder is
1s digit. You do need a 16-bit subtract routine.
Lee Jones
1998\10\14@214503
by
Sean Breheny
Hi Lee,
Thanks for the idea. I'll give it a try and see how it compares in size and
resources. It certainly looks better.
Sean
At 06:08 PM 10/14/98 -0700, you wrote:
>> I am trying to do 16 bit binary to BCD conversion and it is becomming
>> much more complicated than I had initially anticipated. As far as I
>> can see, there are only two ways to accomplish it:
[SNIP]
>How about:
>
>3) repeated subtraction of 10000, 1000, 100, 10; remainder is
> 1s digit. You do need a 16-bit subtract routine.
>
> Lee Jones
>
+-------------------------------+
| Sean Breheny |
| Amateur Radio Callsign: KA3YXM|
| Electrical Engineering Student|
+-------------------------------+
Save lives, please look at http://www.all.org
Personal page: http://www.people.cornell.edu/pages/shb7
spamBeGoneshb7spamBeGone
cornell.edu Phone(USA): (607) 253-0315 ICQ #: 3329174
1998\10\14@215311
by
Sean Breheny
Lee and everyone else,
Yup. That is much easier. I don't know why, but when I was trying to come
up with a way to do this, that method seemed to have way too many
subtractions in it, but it actually has a maximum of 7+6+6+4+6=29 total 16
bit subtractions for the entire 16 bit conversion.
Thanks again,
Sean
At 06:08 PM 10/14/98 -0700, you wrote:
{Quote hidden}>> I am trying to do 16 bit binary to BCD conversion and it is becomming
>> much more complicated than I had initially anticipated. As far as I
>> can see, there are only two ways to accomplish it:
>
>> 1) Integer Division by 10 (remainders [are] digits)
>
>> 2) Using a lookup table for each resultant digit to find the
>> "contribution" from each bit of the input number
>
>
>How about:
>
>3) repeated subtraction of 10000, 1000, 100, 10; remainder is
> 1s digit. You do need a 16-bit subtract routine.
>
> Lee Jones
>
+-------------------------------+
| Sean Breheny |
| Amateur Radio Callsign: KA3YXM|
| Electrical Engineering Student|
+-------------------------------+
Save lives, please look at http://www.all.org
Personal page: http://www.people.cornell.edu/pages/shb7
TakeThisOuTshb7EraseME
spam_OUTcornell.edu Phone(USA): (607) 253-0315 ICQ #: 3329174
1998\10\14@215502
by
Dwayne Reid
|
>I am trying to do 16 bit binary to BCD conversion and it is becomming much
>more complicated than I had initially anticipated. As far as I can see,
>there are only two ways to accomplish it:
>
>1) Integer Division by 10 (and using the remainders as the resultant digits)
>
>2) Using a lookup table for each resultant digit to find the "contribution"
>from each bit of the input number (i.e., for the hundreds digit, bits 0
>thru 6 contribute zero, but bit 7 adds 100, bit 8 adds 200, bit 9 adds 500,
>so you add up each of these contributions, modulo ten, and place the result
>as the hundreds digit, and carry over what's left to the next digit's
>contribution).
Try door number 3:
save number into reg
clrf 10ks
clrf 1ks
clrf 100s
clrf 10s
clrf 1s
loop1
subtract .10000,W (use appropriate routine: make sure it preserves C)
skpc ;note result is in W
goto sub_1k ;underflow?
movwf reg ;nope, so save new value
incf 10ks ;increment 10 thousands register
goto loop1 ;do it again
sub_1k
subtract .1000
I'm sure you can see where this is going . . .
It takes a while (6 loops max for 10ks, 10 loops max for the each of the
other loops) but doesn't take too much space. Otherwise, look for Johm
Payson's neat routine that does it faster (much faster!) AND in less space!
Hope this helps.
dwayne
Dwayne Reid <RemoveMEdwayner
TakeThisOuTplanet.eon.net>
Trinity Electronics Systems Ltd Edmonton, AB, CANADA
(403) 489-3199 voice (403) 487-6397 fax
1998\10\14@220540
by
Sean Breheny
[SNIP]
>Lee and everyone else,
>
>Yup. That is much easier. I don't know why, but when I was trying to come
up with a way to do >this, that method seemed to have way too many
subtractions in it, but it actually has a >maximum >of 7+6+6+4+6=29 total
16 bit subtractions for the entire 16 bit conversion.
OOPS. That should have said 6+10+10+10+10=46.
Sean
+-------------------------------+
| Sean Breheny |
| Amateur Radio Callsign: KA3YXM|
| Electrical Engineering Student|
+-------------------------------+
Save lives, please look at http://www.all.org
Personal page: http://www.people.cornell.edu/pages/shb7
shb7EraseME
.....cornell.edu Phone(USA): (607) 253-0315 ICQ #: 3329174
1998\10\15@011650
by
Sean Breheny
Hi Duane and everyone else,
This binary to BCD conversion is really beginning to show me how little I
know about binary arithmetic! My additional question is below:
At 09:55 PM 10/14/98 -0400, you wrote:
>loop1
> subtract .10000,W (use appropriate routine: make sure it preserves C)
> skpc ;note result is in W
> goto sub_1k ;underflow?
> movwf reg ;nope, so save new value
> incf 10ks ;increment 10 thousands register
> goto loop1 ;do it again
Well, I understand what you are saying, and if I write a BASIC program in
QBASIC to do this, it works fine (using the built-in subtract routine).
However, now I am trying to port this to my PIC and I am having problems
writing a subtract routine:
Here's what I tried:
>>>>CODE STARTS HERE
; SUB16
; Does AB-CD -> AB
; Destroys A,B,W,Carry,DigitCarry
; Returns A,B,Carry
rA equ 0x0C
rB equ 0x0D
rC equ 0x0E
rD equ 0x0F
main call sub16
main2 goto main2
sub16 movf rD,W ;Do B-D -> B
subwf rB,F
movlw 1 ;Do the borrow from A if needed
skpc
subwf rA,F
movf rC,W ;Do A-C -> A
subwf rA,F
return ;Done
END
>>>>CODE ENDS HERE
When I simulate this, the result seems to be correct. However, the carry
out does not follow the rules required to be used in the above routine
provided by Duane. The reason for this is that the last subtraction (subwf
rA,F), considers rA to be a positive number, regardless of its MSB (this
doesn't affect the answer, but it does affect the carry). I could make the
routine more complicated and make a carry out which follows the criteria
needed for the routine, but why not just use the MSB of the output to tell
if it is positive or negative?
Also, what SHOULD the carry out be for such a subtract routine? If you
simply execute SUBWF A,F and A contains a negative number and W contains a
small positive number, the PIC will call the output positive ( nBORROW = 1
). Should my routine do the same if fed a negative number in AB? I realize
that it doesn't really matter for the BCD conversion application, but I
just want to understand how to write a general 16 bit subtract routine.
Thanks,
Sean
+-------------------------------+
| Sean Breheny |
| Amateur Radio Callsign: KA3YXM|
| Electrical Engineering Student|
+-------------------------------+
Save lives, please look at http://www.all.org
Personal page: http://www.people.cornell.edu/pages/shb7
EraseMEshb7
cornell.edu Phone(USA): (607) 253-0315 ICQ #: 3329174
1998\10\15@012117
by
Sean Breheny
1998\10\15@014352
by
Sean Breheny
I think I found my mistake.
This is what the subtract routine should look like:
sub16 movf rD,W ;do B-D -> B
subwf rB,F
movf rC,W ;load C into W
skpc ;add one to W to do borrow if needed
addlw 1
subwf rA,F ;Do A-C -> A
return
This preserves the carry by combining the borrow and the final subtraction
into one subwf
Thanks for all your help and I'll probably be back with more questions,
Sean
+-------------------------------+
| Sean Breheny |
| Amateur Radio Callsign: KA3YXM|
| Electrical Engineering Student|
+-------------------------------+
Save lives, please look at http://www.all.org
Personal page: http://www.people.cornell.edu/pages/shb7
RemoveMEshb7spam_OUT
KILLspamcornell.edu Phone(USA): (607) 253-0315 ICQ #: 3329174
1998\10\15@014609
by
Tony Nixon
Sean Breheny wrote:
> Also, what SHOULD the carry out be for such a subtract routine?
A - B
if B = A then C = 1, Z = 1
if B < A then C = 1, Z = 0
if B > A then C = 0, Z = 0
--
Best regards
Tony
Multimedia 16F84 Beginners PIC Tools.
**New Improved PicNPost**
http://www.picnpoke.com
Email RemoveMEpicnpokeTakeThisOuT
spamcdi.com.au
1998\10\15@015425
by
Sean Breheny
Hi Tony,
At 03:42 PM 10/15/98 +1000, you wrote:
>Sean Breheny wrote:
>> Also, what SHOULD the carry out be for such a subtract routine?
>
>A - B
>
>if B = A then C = 1, Z = 1
>if B < A then C = 1, Z = 0
>if B > A then C = 0, Z = 0
>
Yes, of course, I understand that, but my point is "how do we tell if B>A
or B<A"? I ask this because we are considering A to be an unsigned number
and B to be signed. We can consider them both to be signed, and the result
doesnt change, but should the carry then be different, since for A=-1 B =
2, B is really greater than A, but when we feed the two's complement
numbers into our routine, we would get "A=0xFF B=0x02" and it would
conclude that A>B.
Sean
+-------------------------------+
| Sean Breheny |
| Amateur Radio Callsign: KA3YXM|
| Electrical Engineering Student|
+-------------------------------+
Save lives, please look at http://www.all.org
Personal page: http://www.people.cornell.edu/pages/shb7
EraseMEshb7spam
spamBeGonecornell.edu Phone(USA): (607) 253-0315 ICQ #: 3329174
1998\10\15@020252
by
William Chops Westfield
that method seemed to have way too many subtractions in it, but
it actually has a maximum of 7+6+6+4+6=29 total 16 bit
subtractions for the entire 16 bit conversion.
Ok, how did you get that sum? I get something like 35
subtractions (which still isn't that bad) for 59999... I guess
the last 10 subtracts are only 8-bit, and an additional 10
subtracts are an 8 bit quantity from a 16 bit value.
BillW
1998\10\15@021748
by
Sean Breheny
Hi Bill,
At 11:00 PM 10/14/98 PDT, you wrote:
> that method seemed to have way too many subtractions in it, but
> it actually has a maximum of 7+6+6+4+6=29 total 16 bit
> subtractions for the entire 16 bit conversion.
>
>Ok, how did you get that sum? I get something like 35
>subtractions (which still isn't that bad) for 59999... I guess
>the last 10 subtracts are only 8-bit, and an additional 10
>subtracts are an 8 bit quantity from a 16 bit value.
Yeah, you're right. I goofed that one totally. I was thinking that 65535
would yield the maximum number of subtractions. There must be a time delay
between me-the list-and you because I already sent out a message attempting
to correct what I had said before. I got 46 in that message, but that was
counting every subtraction as a 16-bit subtraction, and it was counting
subtractions for the ones place as well!! So, it should be (if I can trust
my brain now!) 6+10+10=26 16-bit subtractions and then 10 more 8-bit ones
(for the tens place and the ones remainder).
WOW! I really have to check my math before I post to 1600 people!
Thanks for the correction,
Sean
>
>BillW
>
+-------------------------------+
| Sean Breheny |
| Amateur Radio Callsign: KA3YXM|
| Electrical Engineering Student|
+-------------------------------+
Save lives, please look at http://www.all.org
Personal page: http://www.people.cornell.edu/pages/shb7
RemoveMEshb7KILLspam
cornell.edu Phone(USA): (607) 253-0315 ICQ #: 3329174
1998\10\15@031041
by
Tony Nixon
Sean Breheny wrote:
> I ask this because we are considering A to be an unsigned number
> and B to be signed.
It would obviously get tricky if one number was signed and the other
not. The signed value can never be more than half the value of the
unsigned value, assuming the same bit length. Therefore, if the MSB of
the unsigned number = 1, then it will be the larger value. If the MSB of
the signed value is negative, then it will always be the lower value. If
both numbers are positive, with number A MSB = 0, then you would need to
test for the larger of the 2 positive values.
--
Best regards
Tony
Multimedia 16F84 Beginners PIC Tools.
**New Improved PicNPost**
http://www.picnpoke.com
Email picnpokeSTOPspam
spam_OUTcdi.com.au
1998\10\15@042208
by
N Steenkamp
|
Hi,
> Lee and everyone else,
>
> Yup. That is much easier. I don't know why, but when I was trying to come
> up with a way to do this, that method seemed to have way too many
> subtractions in it, but it actually has a maximum of 7+6+6+4+6=29 total 16
> bit subtractions for the entire 16 bit conversion.
>
> Thanks again,
>
> Sean
>
[snip]
> >3) repeated subtraction of 10000, 1000, 100, 10; remainder is
> > 1s digit. You do need a 16-bit subtract routine.
> >
I usually use the plain old divide by 10 and get the remainder method.
The routine is small (16 words, including the Z flag stuff at the end)
and it executes reasonably fast (about 185 cycles). I doubt if 30+
16 bit subtractions would be significantly faster or smaller (if any).
The divide routine also scales extremely easy - A small increase in
size for every byte and an almost linear increase in execution time. The
only drawback of the divide scheme is that you receive your digits from
right to left and not left to right.
;=========================================================================
;Divide the 16 bit number in TempNum by 10 and store the result
;in TempNum and the remainder in Temp. If the quotient and the
;remainder is 0, the Z flag is set. This is usefull for leading 0
;suppression.
;=========================================================================
Div10:
movlw 16
movwf C1 ;Repeat for 16 bits
clrf Temp
Div10Loop:
rlf TempNum, W
rlf TempNum+1, F
rlf Temp, F ;Move MSB of Number into Temp
movlw 10
subwf Temp, W ;Does 10 go in?
btfsc STATUS, C
movwf Temp ;If so, update remainder
rlf TempNum, F ;If 10 went in, shift in a 1, if
;not shift in a 0
decfsz C1, F
goto Div10Loop ;Repeat for all bits
movf TempNum, W ;Test if Quotient is 0
iorwf TempNum+1, W ;Test if Quotient is 0
iorwf Temp, W ;Test if Remainder is also 0
return
Niki
1998\10\15@123045
by
Harold Hallikainen
1998\10\15@132246
by
Sean Breheny
Hi Harold,
At 12:29 PM 10/15/98 EDT, you wrote:
> I haven't looked at this closely, but how about for a 16 bit
>binary, do 16 bit tests and 16 appropriate BCD additions (using the DC
>flag)?
This is basically a more refined version of what I was talking about in
option #2 of my original message. This is probably faster than the
subtraction method, but it requires more space since it needs a lookup
table for the values to be added for each bit. There are ways to calculate
the values other than a lookup table, but I think that they would take even
more space.
Thanks,
Sean
{Quote hidden}
+-------------------------------+
| Sean Breheny |
| Amateur Radio Callsign: KA3YXM|
| Electrical Engineering Student|
+-------------------------------+
Save lives, please look at http://www.all.org
Personal page: http://www.people.cornell.edu/pages/shb7
EraseMEshb7
EraseMEcornell.edu Phone(USA): (607) 253-0315 ICQ #: 3329174
1998\10\20@114138
by
John Payson
|
part 0 1361 bytes
|It takes a while (6 loops max for 10ks, 10 loops max for the each of the
|other loops) but doesn't take too much space. Otherwise, look for Johm
|Payson's neat routine that does it faster (much faster!) AND in less space!
Thanks for the plug. I'm sure one of the Andys around here will
post my routine (who was the brilliant guy who commented the thing
far better than I could have done?) Anyway, on a related note, I
was writing a program on an 8x51 clone (ducking) and needed to
display some 32-bit numbers; in some cases I needed a straight
integer output while in others I needed to display an integer # of
miliseconds in h:mm:ss.mmm format. The techniques I used to do the
conversion may be of interest, though they were optimized to use the
8x51's DIV/MUL instructions: all divides and multiplies are by
constants, so table-lookup should be quite feasible. I'll need to
clean the algorithm up if anyone is to understand it, so I'll post
it later.
For quick mod'ing by 10 or 6 of large numbers, there's a little
trick which may also be helpful: add up all the nybbles of the
number except the least-significant nybble, multiply that sum by
six, then add the least-significant nybble and mod by 10 or 6.
Since some quick-and-dirty divide-by-10 or divide-by-6 routines
don't report a remainder the quick mod'ing routine can be quite
handy at times.
1998\10\20@135847
by
Scott Dattalo
On Tue, 20 Oct 1998, John Payson wrote:
>
> |It takes a while (6 loops max for 10ks, 10 loops max for the each of the
> |other loops) but doesn't take too much space. Otherwise, look for Johm
> |Payson's neat routine that does it faster (much faster!) AND in less space!
>
> Thanks for the plug. I'm sure one of the Andys around here will
> post my routine (who was the brilliant guy who commented the thing
> far better than I could have done?)
http://interstice.com/~sdattalo/technical/software/pic/bcd.txt
I would've posted the URL earlier, but the obligatory 3 month
non-repeating BCD thread time had not been exceeded. Sigh.
More... (looser matching)
- Last day of these posts
- In 1998
, 1999 only
- Today
- New search...