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
Hyc wrote:
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!
unclouded wrote:
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
BitWise wrote:
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

Code: Select all

	SED
	CMP #$0A
	ADC #$30
	CLD
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.