Jump to content
IGNORED

FastBasic bit rotation


Recommended Posts

I found the need to do some bit rotation in FastBasic and figured it would be better just to write a small bit of assembler code.  I thought I'd post it here incase anyone found it useful.

 

data rotate() byte = $68,$68,$A8,$18,$68,$AA,$68,$2A,$48,$8A,$2A,$48,$88,$C0,$00,$D0,$F2,$68,$AA,$68,$60
r=adr(rotate)

result=usr(r,88,2)

 

First number in the USR statement is the number you want to bit-rotate, the second number is the number of left rotations you want (I didn't do right rotation 'cause I didn't need it)

 

So this will do the follow to the bytes:

 

00000000 01011000

00000001 01100000

 

Although I wrote it to pre shift some graphics it could also be used for doubling a number (each rotate will double the initial number) and it's faster than normal mulitplication

 

eg.

a=usr(r,b,3)

 

will double a number 3 times (b*2*2*2) which equates to:

 

a=b*8

 

Disclaimer:  I'm not great at assember, so use at your own risk :)

 

 

 

 

 

 

  • Like 4
Link to comment
Share on other sites

3 hours ago, Preppie said:

I found the need to do some bit rotation in FastBasic and figured it would be better just to write a small bit of assembler code.  I thought I'd post it here incase anyone found it useful.

 


data rotate() byte = $68,$68,$A8,$18,$68,$AA,$68,$2A,$48,$8A,$2A,$48,$88,$C0,$00,$D0,$F2,$68,$AA,$68,$60
r=adr(rotate)

result=usr(r,88,2)

 

...

 

Disclaimer:  I'm not great at assember, so use at your own risk :)

 

 

 

 

 

 

Thanks for sharing!

 

Just for completeness' sake, it would be great if you could add the assembler code as well (yes I know, I can disassemble the above and am just a lazy boy).

Link to comment
Share on other sites

Hi Preppie!

3 hours ago, Preppie said:

I found the need to do some bit rotation in FastBasic and figured it would be better just to write a small bit of assembler code.  I thought I'd post it here incase anyone found it useful.

 


data rotate() byte = $68,$68,$A8,$18,$68,$AA,$68,$2A,$48,$8A,$2A,$48,$88,$C0,$00,$D0,$F2,$68,$AA,$68,$60
r=adr(rotate)

result=usr(r,88,2)

 

First number in the USR statement is the number you want to bit-rotate, the second number is the number of left rotations you want (I didn't do right rotation 'cause I didn't need it)

 

So this will do the follow to the bytes:

 

00000000 01011000

00000001 01100000

 

Although I wrote it to pre shift some graphics it could also be used for doubling a number (each rotate will double the initial number) and it's faster than normal mulitplication

 

eg.

a=usr(r,b,3)

 

will double a number 3 times (b*2*2*2) which equates to:

 

a=b*8

 

Disclaimer:  I'm not great at assember, so use at your own risk :)

It is a good example of a useful assembler routine.

 

It can be optimized a bit, your current code is this:

  PLA
  PLA
  TAY
loop:
  CLC
  PLA
  TAX
  PLA
  ROL
  PHA
  TXA
  ROL
  PHA
  DEY
  CPY #0
  BNE loop
  PLA
  TAX
  PLA
  RTS

 

Some comments:

  • The "CPY #0" can be omitted, as the DEY exits with the correct Z flag value.
  • The "CLC" at the start of the loop is not needed if you replace "ROL" by "ASL" ( ASL is the same as CLC+ROL )
  • You don't need to push and pop into the stack for each iteration, it is better to simply use a ZP location. The location $E0 (FR1) is a good candidate, as it is used by the floating point package but it is free to use during an USR routine.

This is the resulting code:

  PLA
  PLA
  TAY
  PLA
  STA $E0
  PLA
loop:
  ASL
  ROL $E0
  DEY
  BNE loop
  LDX $E0
  RTS

And the FastBasic program:

data rotate() byte = $68, $68, $a8, $68, $85, $d4, $68, $0a, $26, $d4, $88, $d0, $fa, $a6, $d4, $60
r=adr(rotate)

result=usr(r,88,2)

Have Fun!

 

 

  • Like 2
Link to comment
Share on other sites

5 hours ago, dmsc said:

This is the resulting code:


  PLA
  PLA
  TAY
  PLA
  STA $E0
  PLA
loop:
  ASL
  ROL $E0
  DEY
  BNE loop
  LDX $E0
  RTS

And the FastBasic program:


data rotate() byte = $68, $68, $a8, $68, $85, $d4, $68, $0a, $26, $d4, $88, $d0, $fa, $a6, $d4, $60
r=adr(rotate)

result=usr(r,88,2)

Have Fun!

You use $E0 in the assembler and then $D4 in the FastBasic listing.  Looking at memory map I think $d4 is used to pass the result back to basic, which is fine, but I decided to also pass the results back in HI/LO byte format and so $d4/$d5 would get overwritten, so I swaped back to $e0/$e1.

 

I've just added a STA $E1 so that now you can peek($E0) for the HI byte of the result and Peek($E1) for the LO byte.  Makes it a bit easier than manipulating the FastBasic integer if you want the individual bytes. 

 

data rotate() byte = $68,$68,$a8,$68,$85,$e0,$68,$0a,$26,$e0,$88,$d0,$fa,$85,$e1,$a6,$e0,$60
r=adr(rotate)

edit, forgot to add the code.

Edited by Preppie
Link to comment
Share on other sites

Should be noted - it's actually doing bit shifting, not rotation.  Rotate would introduce but 15's value into bit 0 of the number.

 

Optimizations in this case save a bit of memory and typing, given it's a USR routine a few cycles saved won't matter much.

 

There's tricks you can do with rotation to more easily "rotate without carry" if you wanted to do that - though for graphics work you generally don't want to retain shifted out bits.

  • Like 1
Link to comment
Share on other sites

Hi!

6 hours ago, Preppie said:

You use $E0 in the assembler and then $D4 in the FastBasic listing.  Looking at memory map I think $d4 is used to pass the result back to basic, which is fine, but I decided to also pass the results back in HI/LO byte format and so $d4/$d5 would get overwritten, so I swaped back to $e0/$e1.

 

I've just added a STA $E1 so that now you can peek($E0) for the HI byte of the result and Peek($E1) for the LO byte.  Makes it a bit easier than manipulating the FastBasic integer if you want the individual bytes. 


data rotate() byte = $68,$68,$a8,$68,$85,$e0,$68,$0a,$26,$e0,$88,$d0,$fa,$85,$e1,$a6,$e0,$60
r=adr(rotate)

 

You are right, I changed the code but forgot to assemble again. Thanks for the fix.

 

FastBasic uses locations $D4 to $DF (FR0) only in the floating-point version, to keep intermediate results of floating point calculations, so it is better to not use that locations if you plan to mix assembly code with floating point math - for example with "A% = 0.1 + USR(R)", the 0.1 would be stored in FR0.

 

Have Fun!

  • Like 1
Link to comment
Share on other sites

  • 6 months later...

Hi to all.

For rotation I'd propose this set of routines.

Maybe cld at the start (d8) is not required but I insert this by default.

 

DATA ROL16() B. = $d8,$68,$68,$a8,$68,$85,$cc,$68,$18,$2a,$26,$cc,$88,$d0,$fa,$a6,$cc,$60
DATA ROL8() B. = $d8,$68,$68,$a8,$68,$68,$18,$2a,$88,$d0,$fc,$a2,$00,$60
DATA ROR16() B. = $d8,$68,$68,$a8,$68,$85,$cc,$68,$18,$66,$cc,$6a,$88,$d0,$fa,$a6,$cc,$60
DATA ROR8() B. = $d8,$68,$68,$a8,$68,$68,$18,$6a,$88,$d0,$fc,$a2,$00,$60

; Rotation left (16 bit)
; 1st arg: number
; 2nd arg: number of rotations
  cld
  pla
  pla
  tay
  pla
  sta $cc
  pla
  clc
loop:
  rol A
  rol $cc
  dey
  bne loop
  ldx $cc
  rts

; Rotation Left (8 bit)
; 1st arg: number
; 2nd arg: number of rotations
  cld
  pla
  pla
  tay
  pla
  pla
  clc
loop:
  rol A
  dey
  bne loop
  ldx #0
  rts

; Rotation Right (16 bit)
; 1st arg: number
; 2nd arg: number of rotations
  cld
  pla
  pla
  tay
  pla
  sta $cc
  pla
  clc
loop:
  ror $cc
  ror A
  dey
  bne loop
  ldx $cc
  rts

; Rotation Right (8 bit)
; 1st arg: number
; 2nd arg: number of rotations
  cld
  pla
  pla
  tay
  pla
  pla
  clc
loop:
  ror A
  dey
  bne loop
  ldx #0
  rts

 

Link to comment
Share on other sites

Might be more useful to preserve all bits.  I.e, 1100 1010 ROR 4 giving 1010 1100.  Your routine would give 0100 1100.

 

Simple to add.  Just do a pre-shift of the low bit for ROR and high bit for ROL to pre-load the carry flag.

 

For ROL16, change:

  pla
  sta $cc
  pla
  clc

to:

  pla
  sta $cc
  rol
  pla

For ROL8:

  pla
  pla
  clc

becomes:

  pla
  pla
  pha
  rol
  pla

 

I'll leave the other direction as an exercise for the reader.  ?

 

 

Link to comment
Share on other sites

2 hours ago, StickJock said:

Might be more useful to preserve all bits.  I.e, 1100 1010 ROR 4 giving 1010 1100.  Your routine would give 0100 1100.

Reasonable idea, thanks! The only difference is that I'd avoid using stack when unused registers are available, to save cycles a bit

 

DATA CROL16() B. = $d8,$68,$68,$a8,$68,$85,$cc,$2a,$68,$2a,$26,$cc,$88,$d0,$fa,$a6,$cc,$60
DATA CROL8() B. = $d8,$68,$68,$a8,$68,$68,$aa,$0a,$8a,$2a,$88,$d0,$fc,$a2,$00,$60
DATA CROR16() B. = $d8,$68,$68,$a8,$68,$85,$cc,$68,$aa,$6a,$8a,$66,$cc,$6a,$88,$d0,$fa,$a6,$cc,$60
DATA CROR8() B. = $d8,$68,$68,$a8,$68,$68,$aa,$6a,$8a,$6a,$88,$d0,$fc,$a2,$00,$60

; Complete rotation left (16 bit)
; 1st arg: number
; 2nd arg: number of rotations
  cld
  pla
  pla
  tay
  pla
  sta $cc
  rol
  pla
loop:
  rol A
  rol $cc
  dey
  bne loop
  ldx $cc
  rts

; Complete Rotation Left (8 bit)
; 1st arg: number
; 2nd arg: number of rotations
  cld
  pla
  pla
  tay
  pla
  pla
  tax
  asl
  txa
loop:
  rol A
  dey
  bne loop
  ldx #0
  rts

; Complete Rotation Right (16 bit)
; 1st arg: number
; 2nd arg: number of rotations
  cld
  pla
  pla
  tay
  pla
  sta $cc
  pla
  tax
  ror
  txa
loop:
  ror $cc
  ror A
  dey
  bne loop
  ldx $cc
  rts

; Complete Rotation Right (8 bit)
; 1st arg: number
; 2nd arg: number of rotations
  cld
  pla
  pla
  tay
  pla
  pla
  tax
  ror
  txa
loop:
  ror A
  dey
  bne loop
  ldx #0
  rts

 

Edited by rpocc
Link to comment
Share on other sites

10 minutes ago, StickJock said:

Good call on using X instead of the stack to save 3 cycles.

 

You do have a bug in your new code, though.  ROL16 is clearing the carry just before the loop.


  pla
  clc
loop:

Oops, my bad! Fixed right in the post. btw just checked the decimal mode subject. That leading $d8 can actually be omitted since there's no sbc/adc

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...