Page 1 of 1
Conversion to bin explanation
Posted: Fri Dec 30, 2016 6:42 pm
by Hyc
Hello.
My exercise is to understand how this program works. I have some concept how it works but I think my knowledge is not sufficient to explain it properly. I use xasm compiler, did 'Easy 6502 by skilldrick' and have some books but it's not enough. Comments are mine.
Thanks in advance for any ideas.
Code: Select all
opt f-g-h+l+o+
;F - fill the space between memory areas with $FF /255
;G - Atari 5200 mode for hardware register abbreviations
;H - generate Atari executable headers
;L - write to the listing
;O - write to the object file
;U - warn of unused labels
org $1000 ;ORG - change value of the origin counter
start equ *
lda <text ;load the hex value low/high byte of a 16-bit word constant.
; czyli laduje 00?
sta $80 /store value of a register in memory location 80
lda >text ;high byte
sta $81
ldy #0
lda #$a5 // load value A5 H 165 DEC 10100101 B
jsr binary ; jump to subroutine
lda <text
ldx >text
jsr $ff80 ;65 408
brk
binary sta byte
ldx #7
bitslp lda #'0'
asl byte ;ASL (Arithmetic Shift Left)
bcc pr ;BCC (Branch on Carry Clear)
lda #'1'
pr sta ($80),y ;the zero page address is dereferenced, and the Y register is added to the resulting address.
iny
dex
bpl bitslp ;BPL (Branch on PLus)
rts ; return from subroutine
byte dta b(0)
org $2000
text equ *
dta b(0),b(0),b(0),b(0)
dta b(0),b(0),b(0),b(0)
dta b(10) ; '\n'
dta b(0)
org $2E0
dta a(start)
end of file
Re: Conversion to bin explanation
Posted: Fri Dec 30, 2016 6:56 pm
by BitWise
The 'binary' subroutine converts the value in A on entry into a string of '0' and '1' characters in the memory area pointed to by $80/$81.
The start code initialises the pointer and loads a test value then calls binary to convert it. The value is stored in 'byte'. An arithmetic shift left is used to extract the most significant bit into the carry flag. It loads a '0' into A before shifting and changes it to a '1' if the carry is set after the shift. X is used to count 8 iterations of the loop. Y is used to index the indirect address in $80/81. When the conversion completes a ROM routine (at $ff80) is used to display the string.
The code could be better. Y is initialised by the caller rather than in the subroutine. The generated string is not terminated so the subsequent print could do something strange.
You could simplify the conversion from:
Code: Select all
bitslp lda #'0'
asl byte ;ASL (Arithmetic Shift Left)
bcc pr ;BCC (Branch on Carry Clear)
lda #'1'
to
Code: Select all
bitslp lda #('0'>>1)
asl byte ;ASL (Arithmetic Shift Left)
rol a
Re: Conversion to bin explanation
Posted: Sat Dec 31, 2016 6:49 am
by Hobbit1972
By changing direction (starting with bit 0 instead bit 7) of you can save an index register and some cycles & space:
Code: Select all
start equ *
lda <text ;load the hex value low/high byte of a 16-bit word constant.
sta $80 ;store value of a register in memory location 80
lda >text ;high byte
sta $81
lda #$a5 // load value A5 H 165 DEC 10100101 B
jsr binary ; jump to subroutine
lda <text
ldx >text
jsr $ff80 ;65 408
brk
binary sta byte
ldy #7 ;************
bitslp lda #('0'>>1)
lsr byte ;shift right-most bit into carry********
rol a ;shift carry into a, result is either '0'=$30 or '1'=$31
sta ($80),y ;store the byte into the buffer that $80 points to
dey;********
bpl bitslp ;BPL (Branch on PLus)
rts ; return from subroutine
Re: Conversion to bin explanation
Posted: Sat Dec 31, 2016 7:10 am
by Hobbit1972
If the routine is used for screen output only, then it can be done like that without tampering x/y:
Code: Select all
binary
sec
rol ;shift the msb out into carry while shifting in an extra index bit
loop pha ;save the value on stack
lda #"0">>1
rol
jsr CHROUT;print character on screen
pla ;restore value
asl ;shift msb out into carry
bne loop ;if msb was the extra index bit, a is now zero, otherwise continue loop
;by this way all 8 bits of a are processed even if a=0
rts
Re: Conversion to bin explanation
Posted: Sat Dec 31, 2016 2:09 pm
by Hyc
Thank you very much for an in-depth analysis of my problem. I programmed in high level languages a bit and change the way of thinking is really difficult for me. Now I have to, based on this program, display the hex 8-bit number. I know the relationship between binary and hex numeral system.
Is a good way to count ones and zeros in a loop and display the appropriate hex number? Any other idea doesn't come to my mind.
I have seen examples on the internet but were written in a completely different way. I expect that the task is trivial
Thanks.
Re: Conversion to bin explanation
Posted: Sat Dec 31, 2016 2:20 pm
by BitWise
I expect that the task is trivial
It is
Code: Select all
1196 ; Display the value in A as two hexadecimal digits.
1197
1198 TxHex2:
1199 00:0596: 48 pha ; Save the original byte
1200 00:0597: 4A lsr a ; Shift down hi nybble
1201 00:0598: 4A lsr a
1202 00:0599: 4A lsr a
1203 00:059A: 4A lsr a
1204 00:059B: 20 xx xx jsr UartHex ; Display
1205 00:059E: 68 pla ; Recover data byte
1206
1207 ; Display the LSB of the value in A as a hexadecimal digit using decimal
1208 ; arithmetic to do the conversion.
1209
1210 UartHex:
1211 00:059F: 20 xx xx jsr HexToAscii ; Convert to ASCII
1212 00:05A2: 4C xx xx jmp UartTx ; And display
1213
1214 ; Convert a LSB of the value in A to a hexadecimal digit using decimal
1215 ; arithmetic.
1216
1217 HexToAscii:
1218 00:05A5: 29 0F and #$0f ; Strip out lo nybble
1219 00:05A7: F8 sed ; Convert to ASCII
1220 00:05A8: 18 clc
1221 00:05A9: 69 90 adc #$90
1222 00:05AB: 69 40 adc #$40
1223 00:05AD: D8 cld
1224 00:05AE: 60 rts ; Done
Re: Conversion to bin explanation
Posted: Sun Jan 01, 2017 6:53 am
by unclouded
Thanks for showing that HexToAscii routine Andrew! It's 4 bytes shorter than my naive implementation:
Code: Select all
; .write_hex4
f15a [ 29 0f ] and #$0f
f15c [ c9 0a ] cmp #$0a
f15e [ 18 ] clc
f15f [ 10 04 ] bpl +4 ($f165)
f161 [ 69 30 ] adc #$30
f163 [ 10 02 ] bpl +2 ($f167)
f165 [ 69 57 ] adc #$57
f167 [ 4c 0d f0 ] jmp $f00d ; .write_char
; .write_hex4_andrew
f16a [ 29 0f ] and #$0f
f16c [ f8 ] sed
f16d [ 18 ] clc
f16e [ 69 90 ] adc #$90
f170 [ 69 40 ] adc #$40
f172 [ d8 ] cld
f173 [ 4c 0d f0 ] jmp $f00d ; .write_char
Is the decimal flag cleared upon interrupt or should I be clearing it in my interrupt handlers?
Re: Conversion to bin explanation
Posted: Sun Jan 01, 2017 7:35 am
by Hobbit1972
Happy New Year to everyone!
Is the decimal flag cleared upon interrupt or should I be clearing it in my interrupt handlers?
NMOS doesn't clear decimal flag on IRQ/NMI/BRK/Reset - if you use ADC/SBC in ISR you should clear it there. CMOS has corrected this "feature".
http://www.6502.org/tutorials/decimal_mode.html#5
Re: Conversion to bin explanation
Posted: Sun Jan 01, 2017 7:38 am
by Hobbit1972
Hyc, did you have a look here:
http://www.6502.org/tutorials/ - the tutorials of this site
http://codebase64.org/doku.php?id=base:6502_6510_coding - this site might be useful, too (overall it's target is Commodore 64, but this section is 65xx-coding in general).
Re: Conversion to bin explanation
Posted: Sun Jan 01, 2017 9:24 am
by BitWise
A more traditional approach to converting a nybble would be
Code: Select all
ora #$30
cmp #$3a
bcc *+4
adc #$06
Re: Conversion to bin explanation
Posted: Sun Jan 01, 2017 10:26 am
by Arlet
A more traditional approach to converting a nybble would be [...]
And better too, because you can actually understand what's happening.
Re: Conversion to bin explanation
Posted: Sun Jan 01, 2017 11:53 am
by Hobbit1972
The traditional way to convert a hex nibble
Code: Select all
ora #"0"
cmp #"9"+1
bcc done ;skip next op if no further adjustment is needed
adc #"A"-"9"-2 ;one less because of carry is set
done
takes 8 bytes and 8 or 9 cycles - an alternative would be:
Code: Select all
CMP #$0A
BCC SKIP
ADC #$66 ; Add $67 (the carry is set), convert $0A to $0F --> $71 to $76
SKIP EOR #$30 ; Convert $00 to $09, $71 to $76 --> $30 to $39, $41 to $46
The way unclouded posted
Code: Select all
sed ;enter BCD mode
clc
ADC #$90 ;Produce $90-$99 (C=0) or $00-$05 (C=1)
ADC #$40 ;Produce $30-$39 or $41-$46
CLD ;Leave BCD mode
takes 7 bytes and 10 cycles.
Smaller and faster would be
with 6 bytes, 8 cycles. It relies on 6502's treatment of illegal BCD numbers.
Even faster but a lot longer by using a table
Code: Select all
tax
lda hextab,x
....
hextab .asc "01234567890ABCDEF"
with 19 bytes and 6 cycles. Or 7 if table is not properly aligned and crosses page boundary.
Re: Conversion to bin explanation
Posted: Sun Jan 01, 2017 12:03 pm
by Arlet
Keep in mind that on the 65C02 the ADC instruction takes an additional cycle in decimal mode.