ref: d63cc467d8ada50ed63177ccbfe117dbfd8fd020
parent: 359955ee4b5bb5548653d1a89a877d554b48551d
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon May 1 16:22:23 EDT 2017
5e: fix special bitshift and rotations
--- a/sys/src/cmd/5e/arm.c
+++ b/sys/src/cmd/5e/arm.c
@@ -35,29 +35,60 @@
}
static u32int
-doshift(u32int instr)
+doshift(u32int instr, u8int *carry)
{
ulong amount, val;
-
- if((instr & (1<<4)) && (instr & (1<<7)))
- invalid(instr);
-
- if(instr & (1<<4))
- amount = P->R[(instr >> 8) & 15];
- else
- amount = (instr >> 7) & 31;
+
val = P->R[instr & 15];
+ if(instr & (1<<4)) {
+ if(instr & (1<<7))
+ invalid(instr);
+ amount = P->R[(instr >> 8) & 15] & 0xFF;
+ if(amount == 0)
+ return val;
+ } else {
+ amount = (instr >> 7) & 31;
+ if(amount == 0 && (instr & (3<<5)) != 0)
+ amount = 32;
+ }
switch((instr >> 5) & 3) {
- case 0:
- return val << amount;
+ default:
+ if(amount == 0)
+ return val;
+ if(amount < 32) {
+ *carry = (val >> (32 - amount)) & 1;
+ return val << amount;
+ }
+ *carry = val & 1;
+ return 0;
case 1:
- return val >> amount;
+ if(amount < 32){
+ *carry = (val >> (amount - 1)) & 1;
+ return val >> amount;
+ }
+ *carry = val >> 31;
+ return 0;
case 2:
- return ((long) val) >> amount;
+ if(amount < 32){
+ *carry = (val >> (amount - 1)) & 1;
+ return ((long) val) >> amount;
+ }
+ if((long)val < 0){
+ *carry = 1;
+ return -1;
+ }
+ *carry = 0;
+ return 0;
case 3:
- return (val >> amount) | (val << (32 - amount));
+ amount &= 31;
+ if(amount){
+ *carry = (val >> (amount - 1)) & 1;
+ return (val >> amount) | (val << (32 - amount));
+ }
+ amount = *carry & 1;
+ *carry = val & 1;
+ return (val>>1) | (amount<<31);
}
- return 0;
}
static void
@@ -70,9 +101,10 @@
Segment *seg;
if(instr & fI) {
+ u8int carry = 0;
if(instr & (1<<4))
invalid(instr);
- offset = doshift(instr);
+ offset = doshift(instr, &carry);
} else
offset = instr & ((1<<12) - 1);
if(!(instr & fU))
@@ -165,6 +197,7 @@
res2 = (u64int)a - b + *carry - 1;
res1 = res2;
if(((a ^ b) & (1<<31)) && !((b ^ res1) & (1<<31))) *overflow = 1;
+ else *overflow = 0;
if(res2 & 0x100000000LL) *carry = 0;
else *carry = 1;
} else {
@@ -171,6 +204,7 @@
res2 = (u64int)a + b + *carry;
res1 = res2;
if(!((a ^ b) & (1<<31)) && ((b ^ res1) & (1<<31))) *overflow = 1;
+ else *overflow = 0;
if(res2 & 0x100000000LL) *carry = 1;
else *carry = 0;
}
@@ -192,30 +226,31 @@
}
if(Rd == P->R + 15 && (instr & fS))
invalid(instr);
+
+ carry = (P->CPSR & flC) != 0;
+ overflow = (P->CPSR & flV) != 0;
+
if(instr & fI) {
operand = instr & 0xFF;
shift = ((instr >> 8) & 15) << 1;
- operand = (operand >> shift) | (operand << (32 - shift));
+ if(shift){
+ operand = (operand >> shift) | (operand << (32 - shift));
+ carry = operand >> 31;
+ }
} else
- operand = doshift(instr);
+ operand = doshift(instr, &carry);
+
op = (instr >> 21) & 15;
- carry = 0;
if(op >= 8 && op <= 11 && !(instr & fS))
sysfatal("no PSR transfers plz");
- if(op >= 5 && op < 8) {
- if(P->CPSR & flC)
- carry = 1;
- } else {
- if(op != 4 && op != 5 && op != 11)
- carry = 1;
- }
- overflow = 0;
+ if(op >= 5 && op < 8)
+ carry = (P->CPSR & flC) != 0;
switch(op) {
case 0: case 8: result = Rn & operand; break;
case 1: case 9: result = Rn ^ operand; break;
- case 2: case 6: case 10: result = add(Rn, operand, 1, &carry, &overflow); break;
- case 3: case 7: result = add(operand, Rn, 1, &carry, &overflow); break;
- case 4: case 5: case 11: result = add(operand, Rn, 0, &carry, &overflow); break;
+ case 2: case 10: carry = 1; case 6: result = add(Rn, operand, 1, &carry, &overflow); break;
+ case 3: carry = 1; case 7: result = add(operand, Rn, 1, &carry, &overflow); break;
+ case 4: case 11: carry = 0; case 5: result = add(operand, Rn, 0, &carry, &overflow); break;
case 12: result = Rn | operand; break;
case 13: result = operand; break;
case 14: result = Rn & ~operand; break;
@@ -228,7 +263,7 @@
P->CPSR |= flZ;
if(result & (1<<31))
P->CPSR |= flN;
- if(carry && op > 1 && op < 12)
+ if(carry)
P->CPSR |= flC;
if(overflow)
P->CPSR |= flV;