Xinu7/src/lib/libeis/ashc.s
/
/ PDP-11 ARITHMETIC SHIFT COMBINED ROUTINE
/
/ This routine will arithmetically shift a 32-bit number up to 31 bits left
/ or 32 bits right. It also sets condition codes properly upon exit in the
/ location psw.
/
/ DEFINITION:
/ Arithmetic Shift DO 073RSS
/ Combined
/ Operation: tmp <- R,Rv1
/ tmp <- tmp shifted NN bits
/ R <- tmp<31:16>
/ Rv1 <- tmp<15:0>
/ The double word R,Rv1 is shifted NN places to the right
/ or left, where NN= (src)<5:0>
/ Condition N: set if result < 0
/ Codes: Z: set if result = 0
/ V: set if sign bit changes during the shift
/ C: loaded with high-order bit when left shift;
/ loaded with low-order bit when right shift
/ (loaded with the last bit shifted out of the 32-bit
/ operand)
/ Description: ... The contents of the specified register R, and the register
/ Rv1 are treated as a single 32-bit operand and are shifted by
/ the number of bits specified by the count field (bits <5:0> of
/ the source operand) and the registers are replaced by the re-
/ sult. First, bits <31:16> of the result are stored in register
/ R. Then, bits <15:0> of the result are stored in register Rv1.
/ A negative count signifies a right shift. A positive count
/ signifies a left shift. A zero count implies no shift, but
/ condition codes are affected. Condition codes are always set
/ on the 32-bit result.
/ Note: 1) The sign bit of register R is replicated in shifts to the
/ right. The least significant bit is filled with zero in shifts
/ to the left. The C bit stores the last bit shifted out. 2) In-
/ teger overflow occurs on a left shift if any bit shifted into
/ the sign position differs from the initial sign of the regis-
/ ter.
/
/ (copied from MICROCOMPUTERS AND MEMORIES, c. 1981 by Digital Equipment
/ Corporation; pp. 89 - 90)
/
/ ALGORITHM:
/ The following C version is meant to be a guide ONLY; the code below is
/ a hand-compilation of this program (essentially). (The given version
/ ignores C parameter passing conventions.)
/
/ ashc(n, s, psw)
/ long n; /* number to be shifted */
/ int s; /* number of shifts */
/ int psw; /* processor status word */
/ {
/ int origs; /* original shift count */
/ int scnt; /* sign bit count */
/
/ psw &= ~017; /* initialize */
/ s &= ~077;
/ scnt = 0;
/ /* do the shifting */
/ if (s == 0) /* no shift */
/ psw |= 01;
/ else if (s > 31){ /* negative shift */
/ origs = s = 64 - s;
/ while(s-- > 0){
/ n >>= 1; /* remember, we do have this */
/ scnt += (n < 0);
/ }
/ "if C bit set, psw |= 01";
/ }
/ else{ /* positive shift */
/ origs = s;
/ while(s-- > 0){
/ n <<= 1; /* remember, we do have this */
/ scnt += (n < 0);
/ }
/ "if C bit set, psw |= 01";
/ }
/ /* set V bit */
/ if (scnt != 0 && scnt != origs)
/ psw |= 02;
/ /* set sign */
/ if (n < 0) psw |= 010;
/ else if (n == 0) psw |= 04;
/ }
/
/ CALLING SEQUENCE:
/ code to simulate the instruction "ash A,r0":
/ mfps -(sp) / get psw
/ mov A,-(sp) / push shift count onto the stack
/ mov r0,-(sp) / push high word onto the stack
/ mov r1,-(sp) / push low word onto the stack
/ jsr pc,cshft2 / call the simulation routine
/ mov (sp)+,r1 / save the low word
/ mov (sp)+,r0 / save the high word
/ tst (sp)+ / pop garbage word
/ mtps (sp)+ / put in the new psw
/
/ WARNING:
/ THIS ROUTINE DOES NOT FOLLOW THE CALLING CONVENTIONS OF C. DO NOT CALL THIS
/ USING THE USUAL C CONVENTIONS; USE THE CALLING SEQUENCE GIVEN ABOVE.
/
/ ASSUMPTIONS:
/ the stack must be set up correctly
/ the routine must be called via "jsr pc,cshft2" since it uses "rts pc"
/ to return
/
/ AUTHOR:
/ Matt Bishop
/ Department of Computer Sciences
/ Purdue University
/ West Lafayette, IN 47907
/
/ Version 1, October 30, 1981
/
/
/ CONSTANTS
lr=sp / linkage register
/ stack allocation ... parameter variables
/ position on stack after r0 - r5 are pushed
sinpsw=24 / psw (on entry)
sotpsw=24 / psw (on exit)
sshift=22 / number of bits to be shifted (on entry)
snumbr=20 / high word of number to be shifted (on entry); result (on exit)
snumb2=16 / low word of number to be shifted (on entry); result (on exit)
/ register allocation
rshift=r0 / number of bits remaining to be shifted
rnumbr=r1 / high word of number being shifted
rnumb2=r2 / low word of number being shifted
rsign=r3 / sum of sign bits of previous shifts
rpsw=r4 / psw
rtemp=r5 / used to save number of bits to be shifted
/
/*** declare the routine name to be global so anyone can use it
.globl cshft2
.text
cshft2:
/*** push the registers onto the stack
mov r0,-(lr)
mov r1,-(lr)
mov r2,-(lr)
mov r3,-(lr)
mov r4,-(lr)
mov r5,-(lr)
/*** set up registers and initialize condition codes
mov sinpsw(lr),rpsw / get psw
bic $17,rpsw / clear its condition codes
clr rsign / no sign bits yet
mov snumbr(lr),rnumbr / get number to be shifted
mov snumb2(lr),rnumb2
mov sshift(lr),rtemp / get the shift count
bic $177700,rtemp
beq setsgn / if 0, done
cmp rtemp,$31. / treat as 2's complement 6-bit number
ble possrt / if <= 31, shift left that many bits
mov $64.,rshift / if > 31, treat as negative; subtract
sub rtemp,rshift / from 64 to get number of bits to be
mov rshift,rtemp / shifted right; save count
/*** negative (right) shift
neglop: asr rnumbr / shift 1 bit right; note sign will never
ror rnumb2 / change as the sign bit is replicated
sob rshift,neglop / go back unless done
br setc / set C bit properly
/*** positive (left) shift
possrt: mov rtemp,rshift / save original shift count
poslop: asl rnumb2 / shift 1 bit left
rol rnumbr
bpl poslnd / add sign bit to rsign
inc rsign
poslnd: sob rshift,poslop / go back unless done
setc: bcc setv / last bit shifted a 1
bis $1,rpsw / if so, set C bit
/*** set V bit correctly
setv: tst rsign / now for the V bit; no sign change if
beq setsgn / rnumbr was always positive (rsign
cmp rsign,rtemp / == 0) or always negative (rsign
beq setsgn / == original shift count); else,
bis $2,rpsw / sign bit changed
/*** set the sign bits correctly
setsgn: tst rnumbr / get the right condition codes
blt setn / of the result
bgt out / adios, amigo!
tst rnumb2 / test low word if high word is 0
bne out / cannot be negative
bis $4,rpsw / if zero, set the Z bit
br out / au revoir, mon ami!
setn: bis $10,rpsw / if negative, set the N bit
/*** restore the registers after saving results
out: mov rnumbr,snumbr(lr) / save result
mov rnumb2,snumb2(lr)
mov rpsw,sotpsw(lr) / save psw
mov (lr)+,r5 / restore registers
mov (lr)+,r4
mov (lr)+,r3
mov (lr)+,r2
mov (lr)+,r1
mov (lr)+,r0
rts pc / do svidanya, tovarishch!
.data