Page 1 of 1

Advice on bit manipulation

Posted: Mon Mar 27, 2006 11:00 pm
by Kallikak
Hi,

I'm relatively new to 6502 assembly, but since I built a Replica-1 (Apple-1 clone) in January, I've been doing quite a lot. What I need to do at the moment, is to transform a byte of the form "XXXY YYZZ" to "001Z ZXXX", and various similar operations. Now I can obviously do this with various rotates and SEC,CLCs, but it seems to me that there are probably some nice tricks that enable this to be done more elegantly. My primary interest is saving space, since this is part of some code that I want to squeeze into my ROMs - and it's gettin pretty tight! :)

I was hoping for some advice.

Thanks

Ken

Posted: Mon Mar 27, 2006 11:22 pm
by 8BIT
Here is my solution:

Code: Select all

     ; value loaded in A
     LDX  #$04
     STX  temp        ; any zp location
     ROL  A
     ROL  temp
     ROL  A
     ROL  temp
     ROL  A
     ROL  temp
     AND  #$18
     ORA  temp
     ; result in temp
Hope that helps.

Daryl

Posted: Mon Mar 27, 2006 11:47 pm
by Kallikak
Thanks very much - that does help. I think you mean result in A though.

Ken

Posted: Mon Mar 27, 2006 11:52 pm
by 8BIT
Nope, the result will be in temp. If you want result in A, add "LDA temp" to the code.

For other bit manipulations, you just need to figure out the least amount of shifts needed to accomplish your goal. Also, store differnt intermediate values in several zp locations can help save code length.


Daryl

Posted: Tue Mar 28, 2006 12:07 am
by Kallikak
Hmmm, sorry if I'm misunderstanding something (as I said, I'm fairly new to 6502 assembly), but your last two instructions - the AND and ORA won't change temp, only A. So if the result is in temp, you could stop earlier!

I understand what you're doing. You put 00000100 in temp, and then copy the last 3 bits accross via the carry to get 0010 0XXX. Then the AND makes A just 000Y Y000, and ORA with temp will make A 001Y YXXX - temp will be unchanged.

At any rate, I wasn't using a temp location, and that was making it harder and more verbose.

Posted: Tue Mar 28, 2006 12:15 am
by 8BIT
OOps! You were right, the result is in A. I'm sorry for confusing the issue.
And your interpretation was 100% correct.

Daryl

Posted: Tue Mar 28, 2006 12:41 am
by Thowllly
Unless I'm misunderstanding something, would'nt this be faster and smaller?

Code: Select all

cmp #$80
rol a
cmp #$80
rol a
cmp #$80
rol a
and #$1f
ora #$20

Posted: Tue Mar 28, 2006 1:02 am
by Kallikak
Looks like it. :-)

This is a good way for me to learn I think. :-)

Posted: Tue Mar 28, 2006 1:34 am
by 8BIT
Thowllly wrote:
Unless I'm misunderstanding something, would'nt this be faster and smaller?

Code: Select all

cmp #$80
rol a
cmp #$80
rol a
cmp #$80
rol a
and #$1f
ora #$20
Great job. I've never imagined it that way... you learn something new everyday... thanks !!!

Daryl

Posted: Tue Mar 28, 2006 5:23 am
by bogax
Thowllly wrote:
Unless I'm misunderstanding something, would'nt this be faster and smaller?

Code: Select all

cmp #$80
rol a
cmp #$80
rol a
cmp #$80
rol a
and #$1f
ora #$20
How 'bout

Code: Select all

cmp #$80
rol A
cmp #$80
rol A
asl A
and #$1F
adc #$20

Posted: Tue Mar 28, 2006 6:05 am
by bogax
bogax wrote:
Thowllly wrote:
Unless I'm misunderstanding something, would'nt this be faster and smaller?

Code: Select all

cmp #$80
rol a
cmp #$80
rol a
cmp #$80
rol a
and #$1f
ora #$20
How 'bout

Code: Select all

cmp #$80
rol A
cmp #$80
rol A
asl A
and #$1F
adc #$20

or this even (check me :) )

Code: Select all

asl A
adc #$80
rol A
asl A
and #$1F
adc #$20

Posted: Wed Mar 29, 2006 7:04 am
by blargg
Most entertaining thread ever. I don't think I'll ever enjoy assembly programming on any other processor as much as on the 6502. What fun. Here's my analysis of the last solution posted (extra bit in comments is the carry bit):

Code: Select all

; In           Out
; XXXY YYZZ -> 001Z ZXXX
; ABCD EFGH    001G HABC

            ; 0 ABCD EFGH
asl A       ; A BCDE FGH0
adc #$80    ; B ?CDE FGHA
rol A       ; ? CDEF GHAB
asl A       ; C DEFG HAB0
and #$1F    ; C 000G HAB0
adc #$20    ; 0 001G HABC

Posted: Wed Mar 29, 2006 7:10 am
by Thowllly
After my first post I had a thought; the last ORA could also have been a EOR, and if A is loaded right before my code it can be shortened to:

Code: Select all

lda $xx ;compare to 0 puts the first x in c, only inverted.

rol a
cmp #$80 
rol a 
cmp #$80 
rol a 
and #$1f 
eor #$30 ;also invert the first x again
But with the last instruction tied up in both setting the 1 bit and inverting that x, I would never have thought of your idea
bogax wrote:
How 'bout

Code: Select all

cmp #$80
rol A
cmp #$80
rol A
asl A
and #$1F
adc #$20
Thats very clever!
bogax wrote:
or this even (check me :) )

Code: Select all

asl A
adc #$80
rol A
asl A
and #$1F
adc #$20
While this is just brilliant! :shock:

Posted: Wed Mar 29, 2006 10:53 am
by Kallikak
blargg wrote:
Most entertaining thread ever. I don't think I'll ever enjoy assembly programming on any other processor as much as on the 6502. What fun.
I've certainly enjoyed it, and learnt a lot - which was of course the idea. I'm writing an assembler to use with my Apple-1 replica, and the problem comes from some changes I've made to the Apple 1 disassembler so it shares some of my assemblers routines and data to save space. My assembler is single pass, uses standard syntax, and allows symbols and simple expressions (but no macros). To be able to fit in ROM, the assembler, disassembler, and a small command shell have to fit into 3800 bytes. I've finished the coding now and am just testing and fixing bugs. I currently have 80 bytes to spare! :)

Posted: Wed Mar 29, 2006 5:47 pm
by kc5tja
blargg wrote:

Code: Select all

; In           Out
; XXXY YYZZ -> 001Z ZXXX
; ABCD EFGH    001G HABC

            ; 0 ABCD EFGH
asl A       ; A BCDE FGH0
adc #$80    ; B ?CDE FGHA
rol A       ; ? CDEF GHAB
asl A       ; C DEFG HAB0
and #$1F    ; C 000G HAB0
adc #$20    ; 0 001G HABC
Ahh, I see it now. It took several HOURS of staring at this to see it. :)