I have a few questions regarding this code:
; Convert an 16 bit binary value to BCD
;
; This function converts a 16 bit binary value into a 24 bit BCD. It
; works by transferring one bit a time from the source and adding it
; into a BCD value that is being doubled on each iteration. As all the
; arithmetic is being done in BCD the result is a binary to decimal
; conversion. All conversions take 915 clock cycles.
;
; See BINBCD8 for more details of its operation.
;
; Andrew Jacobs, 28-Feb-2004
.ORG $0200
BINBCD16: SED ; Switch to decimal mode
LDA #0 ; Ensure the result is clear
STA BCD+0
STA BCD+1
STA BCD+2
LDX #16 ; The number of source bits
CNVBIT: ASL BIN+0 ; Shift out one bit
ROL BIN+1
LDA BCD+0 ; And add into result
ADC BCD+0
STA BCD+0
LDA BCD+1 ; propagating any carry
ADC BCD+1
STA BCD+1
LDA BCD+2 ; ... thru whole result
ADC BCD+2
STA BCD+2
DEX ; And repeat for next bit
BNE CNVBIT
CLD ; Back to binary
BRK ; All Done.
; A test value to be converted
.ORG $0300
BIN .DW 12345
BCD .DS 3
from this site.
I don't understand what exactly this line does:
ROL BIN+1
Does it perform right shift on the second byte of BIN? If so, what exactly is in this byte?
Also is it possible to write something similar for x86? Is it possible to use BCD in order to print number in decimal with x86 in some elegant way? Or better stick with division by 10? I know something about AAA, AAM instructions but I don't know if they're really useful.
ROL
= rotate left. Yes, that is the second byte. The ASL
+ROL
together shift the 16 bit number in BIN
and BIN+1
left by one bit. The ROL
is used to propagate the MSB of the low byte into the LSB of the high byte while the MSB of the high byte is moved to the carry flag which is used by the ADC
instruction.
Note this code uses packed BCD, so on x86 you'd need to use the DAA not the AAA instruction. Also BCD stuff has been deprecated and are not available in 64 bit mode. Nevertheless, here is equivalent x86 code, with added text conversion and printing. GNU assembler at&t, 32 bit linux:
.globl main
main:
sub $8, %esp
mov $12345, %edx
mov $16, %ecx
repeat:
shl %dx
mov bcd, %al
adc %al, %al
daa
mov %al, bcd
mov bcd+1, %al
adc %al, %al
daa
mov %al, bcd+1
mov bcd+2, %al
adc %al, %al
daa
mov %al, bcd+2
dec %ecx
jnz repeat
# print
lea bcd+2, %esi
lea txt, %edi
call unpack
call unpack
call unpack
push $txt
call puts
call exit
unpack:
mov (%esi), %al
dec %esi
mov %al, %ah
shr $4, %al
and $15, %ah
add $0x3030, %ax
stosw
ret
.lcomm bcd, 3
.lcomm txt, 7
The above is not the recommended way to do generic int-to-string, it's just translation of the 6502 code in the question.