6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Apr 28, 2024 2:07 pm

All times are UTC




Post new topic Reply to topic  [ 13 posts ] 
Author Message
PostPosted: Fri Dec 30, 2016 6:42 pm 
Offline

Joined: Fri Dec 30, 2016 6:27 pm
Posts: 2
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:
 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


Top
 Profile  
Reply with quote  
PostPosted: Fri Dec 30, 2016 6:56 pm 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
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:
bitslp          lda #'0'
                asl byte ;ASL (Arithmetic Shift Left)
                bcc pr   ;BCC (Branch on Carry Clear)
                lda #'1'
to
Code:
bitslp          lda #('0'>>1)
                asl byte ;ASL (Arithmetic Shift Left)
                rol a

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
PostPosted: Sat Dec 31, 2016 6:49 am 
Offline
User avatar

Joined: Tue Feb 10, 2015 5:27 pm
Posts: 80
Location: Germany
By changing direction (starting with bit 0 instead bit 7) of you can save an index register and some cycles & space:

Code:
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


Top
 Profile  
Reply with quote  
PostPosted: Sat Dec 31, 2016 7:10 am 
Offline
User avatar

Joined: Tue Feb 10, 2015 5:27 pm
Posts: 80
Location: Germany
If the routine is used for screen output only, then it can be done like that without tampering x/y:

Code:
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


Top
 Profile  
Reply with quote  
PostPosted: Sat Dec 31, 2016 2:09 pm 
Offline

Joined: Fri Dec 30, 2016 6:27 pm
Posts: 2
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.


Top
 Profile  
Reply with quote  
PostPosted: Sat Dec 31, 2016 2:20 pm 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
Hyc wrote:
I expect that the task is trivial

It is
Code:
  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

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 01, 2017 6:53 am 
Offline

Joined: Tue Feb 24, 2015 11:07 pm
Posts: 81
Thanks for showing that HexToAscii routine Andrew! It's 4 bytes shorter than my naive implementation:
Code:
  ; .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?


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 01, 2017 7:35 am 
Offline
User avatar

Joined: Tue Feb 10, 2015 5:27 pm
Posts: 80
Location: Germany
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


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 01, 2017 7:38 am 
Offline
User avatar

Joined: Tue Feb 10, 2015 5:27 pm
Posts: 80
Location: Germany
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).


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 01, 2017 9:24 am 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
A more traditional approach to converting a nybble would be
Code:
ora  #$30
cmp  #$3a
bcc *+4
adc  #$06

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 01, 2017 10:26 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
BitWise wrote:
A more traditional approach to converting a nybble would be [...]

And better too, because you can actually understand what's happening.


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 01, 2017 11:53 am 
Offline
User avatar

Joined: Tue Feb 10, 2015 5:27 pm
Posts: 80
Location: Germany
The traditional way to convert a hex nibble
Code:
   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:
       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:
   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:
   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:
   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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 01, 2017 12:03 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
Keep in mind that on the 65C02 the ADC instruction takes an additional cycle in decimal mode.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 13 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 8 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: