Page 1 of 1

Convert a byte as hex string (to display on screen)

Posted: Fri Aug 04, 2017 7:41 pm
by Symoon
One thing I always thought would be boring to do in assembler, is having to convert a byte value to display it on screen.
For instance, A contains the value #60. If you directly put it on screen, on the Oric you'll get the ASCII char for "(c)".
But how to display "60" instead, which will require two bytes ? ("6" and "0").

I got the answer very quickly thanks to the forum at 6502.org, which had this topic and an incredible solution I'm copying/pasting here with a little extra (and sad) information about its author...

Code: Select all

;  A = entry value

  sed        ;2  @2
  tax        ;2  @4
  and #$0F   ;2  @6
  cmp #9+1   ;2  @8
  adc #$30   ;2  @10
  tay        ;2  @12
  txa        ;2  @14
  lsr        ;2  @16
  lsr        ;2  @18
  lsr        ;2  @20
  lsr        ;2  @22
  cmp #9+1   ;2  @24
  adc #$30   ;2  @26
  cld        ;2  @28

;  A = MSN ASCII char
;  Y = LSN ASCII char
28 cycles, 19 bytes. The code comes from Lee Davison code shorts website. This site disappeared but can still be found on Wayback Machine, along with some other sites trying to put back its content online.
Lee passed away peacefully in his sleep on September 21, 2013. Being a Sunday coder in 6502, I had never heared of him, but he seems to have a well deserved good reputation, which the efficiency of the above code can confirm.

Thanks to this code I can display values while an Oric program is loading. Priceless.

Re: Convert a byte as hex string (to display on screen)

Posted: Sun Aug 06, 2017 1:50 pm
by Chema
Indeed it is a nice piece of code!

I never manage to make the correct comparisons or use of the decimal mode for these things. :)

By the way you can also use a 16-byte table (4 bit value - ascii code) and even save a few more cycles. No need for comparisons nor additions. Not sure about total cycles (need to move things to x or y and do a table access for each code) ... can't check now, but maybe worth to try :)

Re: Convert a byte as hex string (to display on screen)

Posted: Sun Aug 06, 2017 9:54 pm
by Silicebit.
Chema wrote: Sun Aug 06, 2017 1:50 pm Indeed it is a nice piece of code!

I never manage to make the correct comparisons or use of the decimal mode for these things. :)

By the way you can also use a 16-byte table (4 bit value - ascii code) and even save a few more cycles. No need for comparisons nor additions. Not sure about total cycles (need to move things to x or y and do a table access for each code) ... can't check now, but maybe worth to try :)

An example. :-)

Code: Select all

; A = entry value
;
PHA
LSR
LSR
LSR
LSR
TAY
LDX table,Y
JSR $CCFB ;Routine ROM print Atmos
PLA
AND #$0F
TAY
LDX table,Y
JSR $CCFB ;Routine ROM print Atmos
RTS
;
table .byte 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 ; 0 1 2 3 4 5 6 7 8 9 A B C D E F

Re: Convert a byte as hex string (to display on screen)

Posted: Sun Aug 06, 2017 11:45 pm
by Silicebit.
Other more simple routine. :-)

Code: Select all

; A = entry value
;
TAX
LSR
LSR
LSR
LSR
TAY
TXA
LDX table,Y
AND #$0F
TAY
LDA table,Y
RTS
;
table .byte 30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 ; 0 1 2 3 4 5 6 7 8 9 A B C D E F
;
; X = MSN ASCII char
; A = LSN ASCII char

Re: Convert a byte as hex string (to display on screen)

Posted: Mon Aug 07, 2017 6:00 am
by Symoon
Nice!
If I'm counting right, the table solution (the latest one, being closer to the 1st routine posted) is two cycles faster ;)
For 32 bytes (I'm not counting the RTS) against 19 though. But it all depends on what has to be optimised, the speed gain has a cost :)

Re: Convert a byte as hex string (to display on screen)

Posted: Mon Aug 07, 2017 7:03 am
by Dbug
Be careful when playing with the decimal mode: That can have surprising effect on an interrupt routine that can trigger between the calls to SED and CLD.

Re: Convert a byte as hex string (to display on screen)

Posted: Mon Aug 07, 2017 9:04 am
by Symoon
Dbug wrote: Mon Aug 07, 2017 7:03 am Be careful when playing with the decimal mode: That can have surprising effect on an interrupt routine that can trigger between the calls to SED and CLD.
Do you mean ideally the author should have disabled the interrupts first? (In my case, as I'm operating while a program is loading, there are no interrupts... So it should be fine, but I didn't think about that risk).

Re: Convert a byte as hex string (to display on screen)

Posted: Mon Aug 07, 2017 12:15 pm
by Chema
And change
JSR $CCFB ;Routine ROM print Atmos
RTS

With
jmp $ccfb

to scratch a few more cycles :)

Re: Convert a byte as hex string (to display on screen)

Posted: Mon Aug 07, 2017 12:36 pm
by Symoon
Chema wrote: Mon Aug 07, 2017 12:15 pm And change
JSR $CCFB ;Routine ROM print Atmos
RTS

With
jmp $ccfb

to scratch a few more cycles :)
In my little program, I am actually directly printing myself the bytes at the desired screen address. Managing it myself saved lots of cycles - especially when, trying to count the ROM routine cost, I had the feeling it was calling itself! Guess I was wrong somewhere ;)
Of course this leads to other problems (like, when the program ends, "Ready" being printed over some of what the program may have displayed ;) )

Re: Convert a byte as hex string (to display on screen)

Posted: Mon Aug 07, 2017 4:50 pm
by Dbug
Symoon wrote: Mon Aug 07, 2017 9:04 am
Dbug wrote: Mon Aug 07, 2017 7:03 am Be careful when playing with the decimal mode: That can have surprising effect on an interrupt routine that can trigger between the calls to SED and CLD.
Do you mean ideally the author should have disabled the interrupts first? (In my case, as I'm operating while a program is loading, there are no interrupts... So it should be fine, but I didn't think about that risk).
Not necessarily, but basically you have to remember that most of the code on the machine assumes that some flags are set-up in a certain way, and only perform the minimum necessary for the operations to be completed correctly. If any of this code is called with a totally different set of parameters, it can misbehave.
That could be any ROM routine you call in between, or an IRQ triggering.