Preppie Posted October 6, 2019 Share Posted October 6, 2019 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 4 Quote Link to comment Share on other sites More sharing options...
+slx Posted October 6, 2019 Share Posted October 6, 2019 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). Quote Link to comment Share on other sites More sharing options...
Preppie Posted October 6, 2019 Author Share Posted October 6, 2019 ok, here it is: 20 PLA 30 PLA 40 TAY 45 AGN CLC 50 PLA 60 TAX 70 PLA 100 ROL A 110 PHA 120 TXA 130 ROL A 140 PHA 150 DEY 155 CPY #0 160 BNE AGN 170 PLA 180 TAX 190 PLA 200 RTS Quote Link to comment Share on other sites More sharing options...
dmsc Posted October 6, 2019 Share Posted October 6, 2019 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! 2 Quote Link to comment Share on other sites More sharing options...
Preppie Posted October 6, 2019 Author Share Posted October 6, 2019 The real reason I post these bits of code is to get a free lesson from DMSC 3 4 Quote Link to comment Share on other sites More sharing options...
Preppie Posted October 6, 2019 Author Share Posted October 6, 2019 (edited) 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 October 6, 2019 by Preppie Quote Link to comment Share on other sites More sharing options...
Rybags Posted October 6, 2019 Share Posted October 6, 2019 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. 1 Quote Link to comment Share on other sites More sharing options...
dmsc Posted October 7, 2019 Share Posted October 7, 2019 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! 1 Quote Link to comment Share on other sites More sharing options...
777ismyname Posted October 11, 2019 Share Posted October 11, 2019 Thank you, preppie! Quote Link to comment Share on other sites More sharing options...
rpocc Posted April 27, 2020 Share Posted April 27, 2020 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 Quote Link to comment Share on other sites More sharing options...
StickJock Posted April 27, 2020 Share Posted April 27, 2020 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. ? Quote Link to comment Share on other sites More sharing options...
rpocc Posted April 27, 2020 Share Posted April 27, 2020 (edited) 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 April 27, 2020 by rpocc Quote Link to comment Share on other sites More sharing options...
StickJock Posted April 27, 2020 Share Posted April 27, 2020 (edited) 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: Edited April 27, 2020 by StickJock Quote Link to comment Share on other sites More sharing options...
rpocc Posted April 27, 2020 Share Posted April 27, 2020 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 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.