;
-; Ullrich von Bassewitz, 05.08.1998
+; Ullrich von Bassewitz, 2004-06-30
;
-; CC65 runtime: right shift support for ints
+; CC65 runtime: right shift support for unsigneds
+;
+; Note: The standard declares a shift count that is negative or >= the
+; bitcount of the shifted type for undefined behaviour.
+;
+; Note^2: The compiler knowns about the register/zero page usage of this
+; function, so you need to change the compiler source if you change it!
;
-; --------------------------------------------------------------------
-; signed shift
-
- .export tosasra0, tosasrax
- .import popsreg, return0
- .importzp sreg
-
-tosasra0:
- ldx #0
-tosasrax:
- jsr popsreg ; get TOS into sreg
- cpx #0
- bne TooLarge
- cmp #16
- bcs TooLarge
-
- cmp #8 ; Shift count greater 8?
- beq L4 ; Jump if exactly 8
- bcc L2 ; Jump if no
-
-; Shift count is greater 8. Do the first 8 bits the fast way
-
- ldy #0
- ldx sreg+1
- stx sreg
- bpl L1
- dey ; Create correct sign bits
-L1: sty sreg+1
- sec
- sbc #8
-
-; Shift count less than 8 if we come here
-
-L2: tay ; Shift count --> Y
- beq Zero ; Done if shift count zero
-
- lda sreg ; get low byte for faster shift
- ldx sreg+1 ; get high byte
-
-; Do the actual shift
-
-L3: cpx #$80 ; get bit 7 into carry
- ror sreg+1
- ror a
- dey
- bne L3
-
-; Done with shift
-
- ldx sreg+1
- rts
-
-; Shift count == 8
-
-L4: lda sreg+1 ; X is zero
- bpl *+3
- dex ; X == 0xFF
- rts
-
-; Shift count was zero
-
-Zero: lda sreg
- ldx sreg+1
- rts
-
-; Shift count too large, result is zero
-
-TooLarge:
- jmp return0
-
-
-; --------------------------------------------------------------------
-; unsigned shift
-
- .export tosshra0, tosshrax
+ .export tosshrax
+ .import popax
+ .importzp tmp1
-tosshra0:
- ldx #0
tosshrax:
- jsr popsreg ; get TOS into sreg
- cpx #0
- bne TooLarge
- cmp #16
- bcs TooLarge
+ and #$0F ; Bring the shift count into a valid range
+ sta tmp1 ; Save it
- cmp #8 ; Shift count greater 8?
- beq L8 ; Jump if exactly 8
- bcc L6 ; Jump if no
+ jsr popax ; Get the left hand operand
-; Shift count is greater 8. Do the first 8 bits the fast way
+ ldy tmp1 ; Get shift count
+ beq L9 ; Bail out if shift count zero
- sbc #8 ; Carry already set
- ldy sreg+1
- sty sreg
- stx sreg+1 ; High byte = 0
+ cpy #8 ; Shift count 8 or greater?
+ bcc L3 ; Jump if not
-; Shift count less than 8 if we come here
+; Shift count is greater 7. The carry is set when we enter here.
-L6: tay ; Shift count --> Y
- beq Zero ; Done if shift count zero
+ tya
+ sbc #8
+ tay ; Adjust shift count
+ txa
+ ldx #$00 ; Shift by 8 bits
+ beq L2 ; Branch always
+L1: lsr a
+L2: dey
+ bpl L1
+ rts
- lda sreg ; get low byte for faster shift
+; Shift count is less than 8. Do the actual shift.
-; Do the actual shift
-
-L7: lsr sreg+1
- ror a
- dey
- bne L7
+L3: stx tmp1 ; Save high byte of lhs
+L4: lsr tmp1
+ ror a
+ dey
+ bne L4
; Done with shift
- ldx sreg+1
- rts
-
-; Shift count == 8
-
-L8: lda sreg+1 ; X is zero
- rts
+ ldx tmp1
+L9: rts