Advice on bit manipulation

Programming the 6502 microprocessor and its relatives in assembly and other languages.
Post Reply
Kallikak
Posts: 13
Joined: 27 Mar 2006
Location: Sydney

Advice on bit manipulation

Post 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
User avatar
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Post 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
Kallikak
Posts: 13
Joined: 27 Mar 2006
Location: Sydney

Post by Kallikak »

Thanks very much - that does help. I think you mean result in A though.

Ken
User avatar
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Post 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
Kallikak
Posts: 13
Joined: 27 Mar 2006
Location: Sydney

Post 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.
User avatar
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Post 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
Thowllly
Posts: 51
Joined: 22 Oct 2003
Location: Norway

Post 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
Kallikak
Posts: 13
Joined: 27 Mar 2006
Location: Sydney

Post by Kallikak »

Looks like it. :-)

This is a good way for me to learn I think. :-)
User avatar
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Post 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
bogax
Posts: 250
Joined: 18 Nov 2003

Post 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
bogax
Posts: 250
Joined: 18 Nov 2003

Post 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
blargg
Posts: 42
Joined: 30 Dec 2003
Contact:

Post 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
Thowllly
Posts: 51
Joined: 22 Oct 2003
Location: Norway

Post 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:
Kallikak
Posts: 13
Joined: 27 Mar 2006
Location: Sydney

Post 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! :)
kc5tja
Posts: 1706
Joined: 04 Jan 2003

Post 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. :)
Post Reply