示例#1
0
Word ea()
{
    modRM = fetchByte();
    useMemory = true;
    switch (modRM & 7) {
        case 0: segment = 3; address = bx() + si(); break;
        case 1: segment = 3; address = bx() + di(); break;
        case 2: segment = 2; address = bp() + si(); break;
        case 3: segment = 2; address = bp() + di(); break;
        case 4: segment = 3; address =        si(); break;
        case 5: segment = 3; address =        di(); break;
        case 6: segment = 2; address = bp();        break;
        case 7: segment = 3; address = bx();        break;
    }
    switch (modRM & 0xc0) {
        case 0x00:
            if ((modRM & 0xc7) == 6) {
                segment = 3;
                address = fetchWord();
            }
            break;
        case 0x40: address += signExtend(fetchByte()); break;
        case 0x80: address += fetchWord(); break;
        case 0xc0:
            useMemory = false;
            address = modRM & 7;
    }
    return address;
}
/*Load Register Signed Byte (immediate) Encoding T1

    LDRSB<c> <Rt>,[<Rn>,#<imm12>]

   31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
  | 1  1  1  1  1| 0  0| 1  1  0  0  1|     Rn    |     Rt    |           imm12         |

  where:
            <c><q>        See Standard assembler syntax fields on page A6-7.

            <Rt>          Specifies the destination register.

            <Rn>          Specifies the base register. This register is allowed to be the SP. If this register is the PC, see
                          LDRSB (literal) on page A6-120.

            +/-           Is + or omitted to indicate that the immediate offset is added to the base register value
                          (add == TRUE), or – to indicate that the offset is to be subtracted (add == FALSE). Different
                          instructions are generated for #0 and #-0.

            <imm>         Specifies the immediate offset added to or subtracted from the value of <Rn> to form the
                          address. The range of allowed values is 0-4095 for encoding T1, and 0-255 for encoding T2.
                          For the offset addressing syntax, <imm> can be omitted, meaning an offset of 0.

*/
void LDRSBImmediateT1(uint32_t instruction)
{
  uint32_t Rn = getBits(instruction,19,16);
  uint32_t Rt = getBits(instruction,15,12);
  uint32_t imm12 = getBits(instruction,11,0);
  uint32_t address = coreReg[Rn] +  imm12;

  if(inITBlock())
  {
    if( checkCondition(cond) )
      writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(address, 1), 8) );

    shiftITState();
  }
  else
    writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(address, 1), 8) );

  coreReg[PC] += 4;
}
/*Load Register Signed Halfword (immediate) Encoding T2

    LDRSH<c> <Rt>,[<Rn>,#-<imm8>]
    LDRSH<c> <Rt>,[<Rn>],#+/-<imm8>
    LDRSH<c> <Rt>,[<Rn>,#+/-<imm8>]!

   31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
  | 1  1  1  1  1| 0  0| 1  0  0  1  1|     Rn    |     Rt    | 1| P|U|W|      imm8     |

  where:
            <c><q>        See Standard assembler syntax fields on page A6-7.

            <Rt>          Specifies the destination register.

            <Rn>          Specifies the base register. This register is allowed to be the SP. If this register is the PC, see
                          LDRSH (literal) on page A6-120.

            +/-           Is + or omitted to indicate that the immediate offset is added to the base register value
                          (add == TRUE), or – to indicate that the offset is to be subtracted (add == FALSE). Different
                          instructions are generated for #0 and #-0.

            <imm>         Specifies the immediate offset added to or subtracted from the value of <Rn> to form the
                          address. The range of allowed values is 0-4095 for encoding T1, and 0-255 for encoding T2.
                          For the offset addressing syntax, <imm> can be omitted, meaning an offset of 0.

*/
void LDRSHImmediateT2(uint32_t instruction)
{
  uint32_t imm8 = getBits(instruction, 7, 0);
  uint32_t Rt = getBits(instruction,15,12);
  uint32_t Rn = getBits(instruction,19,16);
  uint32_t W = getBits(instruction,8,8);
  uint32_t U = getBits(instruction,9,9);
  uint32_t P = getBits(instruction,10,10);
  uint32_t address;
  
  if(U == 1)
    address = coreReg[Rn] + imm8;
  else
    address = coreReg[Rn] - imm8;

  int check = isOffPostOrPreIndex(P,W);

  if(check == UNDEFINED || Rt == 0b1111 || Rn == 0b1111)
    ThrowError();

  if(inITBlock())
  {
    if( checkCondition(cond) )
    {
      if(check == OFFINDEX)
        writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(address, 2), 16) );
      else if(check == PREINDEX)
      {
        writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(address, 2), 16) );
        coreReg[Rn] = address;
      }
      else
      {
        writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(coreReg[Rn], 2), 16) );
        coreReg[Rn] = address;
      }
    }

    shiftITState();
  }
  else
  {
    if(check == OFFINDEX)
      writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(address, 2), 16) );
    else if(check == PREINDEX)
    {
      writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(address, 2), 16) );
      coreReg[Rn] = address;
    }
    else
    {
      writeToCoreRegisters(Rt , signExtend( loadByteFromMemory(coreReg[Rn], 2), 16) );
      coreReg[Rn] = address;
    }
  }

  coreReg[PC] += 4;
  
}
示例#4
0
文件: mips.c 项目: matsimon/RA
/* SW */
void mips_sw(Instruction *instruction) {
	InstructionTypeI i = instruction->i;
	storeWord(registers[i.rt], registers[i.rs] + (signed)signExtend(i.immediate));
}
示例#5
0
文件: mips.c 项目: matsimon/RA
/* LW */
void mips_lw(Instruction *instruction) {
	InstructionTypeI i = instruction->i;
	registers[i.rt] = loadWord(registers[i.rs] + (signed)signExtend(i.immediate));
} 
示例#6
0
文件: mips.c 项目: matsimon/RA
/* ADDI */
void mips_addi(Instruction *instruction) {
	InstructionTypeI i = instruction->i;
	registers[i.rt] = (signed)registers[i.rs] + (signed)signExtend(i.immediate);
}
/* VCVT, VCVTR (between floating-point and integer)
    
    Floating-point Convert (between floating-point and integer) converts a value in a register from floating-point to a
    32-bit integer, or from a 32-bit integer to floating-point, and places the result in a second register.
    
    The fixed-point value can be 16-bit or 32-bit. Conversions from fixed-point values take their operand from the
    low-order bits of the source register and ignore any remaining bits. Signed conversions to fixed-point values
    sign-extend the result value to the destination register width. Unsigned conversions to fixed-point values
    zero-extend the result value to the destination register width.
  
    VCVT<c>.<Td>.F32 <Sd>, <Sd>, #<fbits>
    VCVT<c>.F32.<Td> <Sd>, <Sd>, #<fbits>

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9  8  7  6 5 4 3 2 1 0
|1  1  1  0| 1  1  1  0  1| D| 1  1  1 op| 1  U|     Vd    | 1  0 1|sf sx  1 i 0| imm4  |

where :
        <c>, <q>      See Standard assembler syntax fields on page A7-175.
          
        <Td>          The data type for the fixed-point number. It must be one of:
                        S16 Encoded as U = 0, sx = 0.
                        U16 Encoded as U = 1, sx = 0
                        S32 Encoded as U = 0, sx = 1.
                        U32 Encoded as U = 1, sx = 1.
                        
        <Sd>          The destination and operand register, for a single-precision operand.
        
        <Dd>          The destination and operand register, for a double-precision operand.
        
        <fbits>       The number of fraction bits in the fixed-point number:
                        • If <Td> is S16 or U16, <fbits> must be in the range 0-16. (16 - <fbits>) is encoded in [imm4,i]
                        • I f <Td> is S32 or U32, <fbits> must be in the range 1-32. (32 - <fbits>) is encoded in [imm4,i].
*/
void VCVTT2(uint32_t instruction)
{ 
  uint32_t Vd = getBits(instruction,15,12);
  uint32_t imm4 = getBits(instruction,3,0);
  uint32_t sf = getBits(instruction,8,8);
  uint32_t sx = getBits(instruction,7,7);
  uint32_t i = getBits(instruction,5,5);
  uint32_t op = getBits(instruction,18,18);
  uint32_t U = getBits(instruction,16,16);
  uint32_t D = getBits(instruction,22,22);
  uint32_t d = determineRegisterBasedOnSZ(D, Vd, sf);
  uint32_t result;
  
  executeFPUChecking();
  
  bool roundNearest = false;
  bool roundZero = false;
  bool toFixed = (op == 1);
  bool dpOperation = (sf == 1);
  bool unsign = (U == 1);
  uint32_t size = (sx == 0) ? 16 : 32;
  uint32_t fracBits = size - ( (imm4 << 1) | i);

  if(toFixed)
    roundZero = true;
  else
    roundNearest = true;
  
  if(inITBlock())
  {
    if( checkCondition(cond) )
    {
      if(toFixed)
      {
        if(dpOperation)
          ThrowError();
        else
        {
          result = FPToFixed(fpuSinglePrecision[d], size, fracBits, unsign, roundZero, fPSCR);
          if(unsign)
            writeSinglePrecision(d, result);
          else
            writeSinglePrecision(d, signExtend(result, 32) );
        }
      }
      else
      {
        if(dpOperation)
          ThrowError();
        else
          result = FixedToFP( getBits(fpuSinglePrecision[d], (size-1), 0), 32, fracBits, unsign, roundNearest, fPSCR);
        writeSinglePrecision(d, result);
      }
    }
    
    shiftITState();
  }
  else
  {
    if(toFixed)
    {
      if(dpOperation)
        ThrowError();
      else
      {
        result = FPToFixed(fpuSinglePrecision[d], size, fracBits, unsign, roundZero, fPSCR);
        if(unsign)
          writeSinglePrecision(d, result);
        else
          writeSinglePrecision(d, signExtend(result, 32) );
      }
    }
    else
    {
      if(dpOperation)
        ThrowError();
      else
        result = FixedToFP( getBits(fpuSinglePrecision[d], (size-1), 0), 32, fracBits, unsign, roundNearest, fPSCR);
      writeSinglePrecision(d, result);
    }
  }

  coreReg[PC] += 4;  
}
示例#8
0
int main(int argc, char* argv[])
{
    if (argc < 2) {
        printf("Usage: %s <program name>\n", argv[0]);
        exit(0);
    }
    filename = argv[1];
    FILE* fp = fopen(filename, "rb");
    if (fp == 0)
        error("opening");
    ram = (Byte*)malloc(0x10000);
    memset(ram, 0, 0x10000);
    if (ram == 0) {
        fprintf(stderr, "Out of memory\n");
        exit(1);
    }
    if (fseek(fp, 0, SEEK_END) != 0)
        error("seeking");
    length = ftell(fp);
    if (length == -1)
        error("telling");
    if (fseek(fp, 0, SEEK_SET) != 0)
        error("seeking");
    if (length > 0x10000 - 0x100) {
        fprintf(stderr, "%s is too long to be a .com file\n", filename);
        exit(1);
    }
    if (fread(&ram[0x100], length, 1, fp) != 1)
        error("reading");
    fclose(fp);

    Word segment = 0x1000;
    setAX(0x0000);
    setCX(0x00FF);
    setDX(segment);
    registers[3] = 0x0000;
    setSP(0xFFFE);
    registers[5] = 0x091C;
    setSI(0x0100);
    setDI(0xFFFE);
    for (int i = 0; i < 4; ++i)
        registers[8 + i] = segment;

    Byte* byteData = (Byte*)&registers[0];
    int bigEndian = (byteData[2] == 0 ? 1 : 0);
    int byteNumbers[8] = {0, 2, 4, 6, 1, 3, 5, 7};
    for (int i = 0 ; i < 8; ++i)
      byteRegisters[i] = &byteData[byteNumbers[i] ^ bigEndian];

    bool prefix = false;
    for (int i = 0; i < 1000000000; ++i) {
        if (!repeating) {
            if (!prefix) {
                segmentOverride = -1;
                rep = 0;
            }
            prefix = false;
            opcode = fetchByte();
        }
        wordSize = ((opcode & 1) != 0);
        bool sourceIsRM = ((opcode & 2) != 0);
        int operation = (opcode >> 3) & 7;
        bool jump;
        switch (opcode) {
            case 0x00: case 0x01: case 0x02: case 0x03:
            case 0x08: case 0x09: case 0x0a: case 0x0b:
            case 0x10: case 0x11: case 0x12: case 0x13:
            case 0x18: case 0x19: case 0x1a: case 0x1b:
            case 0x20: case 0x21: case 0x22: case 0x23:
            case 0x28: case 0x29: case 0x2a: case 0x2b:
            case 0x30: case 0x31: case 0x32: case 0x33:
            case 0x38: case 0x39: case 0x3a: case 0x3b:  // alu rmv,rmv
                data = readEA();
                if (!sourceIsRM) {
                    destination = data;
                    source = getReg();
                }
                else {
                    destination = getReg();
                    source = data;
                }
                aluOperation = operation;
                doALUOperation();
                if (aluOperation != 7) {
                    if (!sourceIsRM)
                        finishWriteEA(data);
                    else
                        setReg(data);
                }
                break;
            case 0x04: case 0x05: case 0x0c: case 0x0d:
            case 0x14: case 0x15: case 0x1c: case 0x1d:
            case 0x24: case 0x25: case 0x2c: case 0x2d:
            case 0x34: case 0x35: case 0x3c: case 0x3d:  // alu accum,i
                destination = getAccum();
                source = !wordSize ? fetchByte() : fetchWord();
                aluOperation = operation;
                doALUOperation();
                if (aluOperation != 7)
                    setAccum();
                break;
            case 0x06: case 0x0e: case 0x16: case 0x1e:  // PUSH segreg
                push(registers[operation + 8]);
                break;
            case 0x07: case 0x17: case 0x1f:  // POP segreg
                registers[operation + 8] = pop();
                break;
            case 0x26: case 0x2e: case 0x36: case 0x3e:  // segment override
                segmentOverride = operation;
                prefix = true;
                break;
            case 0x27: case 0x2f:  // DA
                if (af() || (al() & 0x0f) > 9) {
                    data = al() + (opcode == 0x27 ? 6 : -6);
                    setAL(data);
                    setAF(true);
                    if ((data & 0x100) != 0)
                        setCF(true);
                }
                setCF(cf() || al() > 0x9f);
                if (cf())
                    setAL(al() + (opcode == 0x27 ? 0x60 : -0x60));
                wordSize = false;
                data = al();
                setPZS();
                break;
            case 0x37: case 0x3f:  // AA
                if (af() || (al() & 0xf) > 9) {
                    setAL(al() + (opcode == 0x37 ? 6 : -6));
                    setAH(ah() + (opcode == 0x37 ? 1 : -1));
                    setCA();
                }
                else
                    clearCA();
                setAL(al() & 0x0f);
                break;
            case 0x40: case 0x41: case 0x42: case 0x43:
            case 0x44: case 0x45: case 0x46: case 0x47:
            case 0x48: case 0x49: case 0x4a: case 0x4b:
            case 0x4c: case 0x4d: case 0x4e: case 0x4f:  // incdec rw
                destination = rw();
                wordSize = true;
                setRW(incdec((opcode & 8) != 0));
                break;
            case 0x50: case 0x51: case 0x52: case 0x53:
            case 0x54: case 0x55: case 0x56: case 0x57:  // PUSH rw
                push(rw());
                break;
            case 0x58: case 0x59: case 0x5a: case 0x5b:
            case 0x5c: case 0x5d: case 0x5e: case 0x5f:  // POP rw
                setRW(pop());
                break;
            case 0x60: case 0x61: case 0x62: case 0x63:
            case 0x64: case 0x65: case 0x66: case 0x67:
            case 0x68: case 0x69: case 0x6a: case 0x6b:
            case 0x6c: case 0x6d: case 0x6e: case 0x6f:
            case 0xc0: case 0xc1: case 0xc8: case 0xc9:  // invalid
            case 0xcc: case 0xf0: case 0xf1: case 0xf4:  // INT 3, LOCK, HLT
            case 0x9b: case 0xce: case 0x0f:  // WAIT, INTO, POP CS
            case 0xd8: case 0xd9: case 0xda: case 0xdb:
            case 0xdc: case 0xdd: case 0xde: case 0xdf:  // escape
            case 0xe4: case 0xe5: case 0xe6: case 0xe7:
            case 0xec: case 0xed: case 0xee: case 0xef:  // IN, OUT
                fprintf(stderr, "Invalid opcode %02x", opcode);
                runtimeError("");
                break;
            case 0x70: case 0x71: case 0x72: case 0x73:
            case 0x74: case 0x75: case 0x76: case 0x77:
            case 0x78: case 0x79: case 0x7a: case 0x7b:
            case 0x7c: case 0x7d: case 0x7e: case 0x7f:  // Jcond cb
                switch (opcode & 0x0e) {
                    case 0x00: jump = of(); break;
                    case 0x02: jump = cf(); break;
                    case 0x04: jump = zf(); break;
                    case 0x06: jump = cf() || zf(); break;
                    case 0x08: jump = sf(); break;
                    case 0x0a: jump = pf(); break;
                    case 0x0c: jump = sf() != of(); break;
                    default:   jump = sf() != of() || zf(); break;
                }
                jumpShort(fetchByte(), jump == ((opcode & 1) == 0));
                break;
            case 0x80: case 0x81: case 0x82: case 0x83:  // alu rmv,iv
                destination = readEA();
                data = fetch(opcode == 0x81);
                if (opcode != 0x83)
                    source = data;
                else
                    source = signExtend(data);
                aluOperation = modRMReg();
                doALUOperation();
                if (aluOperation != 7)
                    finishWriteEA(data);
                break;
            case 0x84: case 0x85:  // TEST rmv,rv
                data = readEA();
                test(data, getReg());
                break;
            case 0x86: case 0x87:  // XCHG rmv,rv
                data = readEA();
                finishWriteEA(getReg());
                setReg(data);
                break;
            case 0x88: case 0x89:  // MOV rmv,rv
                ea();
                finishWriteEA(getReg());
                break;
            case 0x8a: case 0x8b:  // MOV rv,rmv
                setReg(readEA());
                break;
            case 0x8c:  // MOV rmw,segreg
                ea();
                wordSize = 1;
                finishWriteEA(registers[modRMReg() + 8]);
                break;
            case 0x8d:  // LEA
                address = ea();
                if (!useMemory)
                    runtimeError("LEA needs a memory address");
                setReg(address);
                break;
            case 0x8e:  // MOV segreg,rmw
                wordSize = 1;
                data = readEA();
                registers[modRMReg() + 8] = data;
                break;
            case 0x8f:  // POP rmw
                writeEA(pop());
                break;
            case 0x90: case 0x91: case 0x92: case 0x93:
            case 0x94: case 0x95: case 0x96: case 0x97:  // XCHG AX,rw
                data = ax();
                setAX(rw());
                setRW(data);
                break;
            case 0x98:  // CBW
                setAX(signExtend(al()));
                break;
            case 0x99:  // CWD
                setDX((ax() & 0x8000) == 0 ? 0x0000 : 0xffff);
                break;
            case 0x9a:  // CALL cp
                savedIP = fetchWord();
                savedCS = fetchWord();
                farCall();
                break;
            case 0x9c:  // PUSHF
                push((flags & 0x0fd7) | 0xf000);
                break;
            case 0x9d:  // POPF
                flags = pop() | 2;
                break;
            case 0x9e:  // SAHF
                flags = (flags & 0xff02) | ah();
                break;
            case 0x9f:  // LAHF
                setAH(flags & 0xd7);
                break;
            case 0xa0: case 0xa1:  // MOV accum,xv
                data = read(fetchWord());
                setAccum();
                break;
            case 0xa2: case 0xa3:  // MOV xv,accum
                write(getAccum(), fetchWord());
                break;
            case 0xa4: case 0xa5:  // MOVSv
                stoS(lodS());
                doRep();
                break;
            case 0xa6: case 0xa7:  // CMPSv
                lodDIS();
                source = data;
                sub();
                doRep();
                break;
            case 0xa8: case 0xa9:  // TEST accum,iv
                data = fetch(wordSize);
                test(getAccum(), data);
                break;
            case 0xaa: case 0xab:  // STOSv
                stoS(getAccum());
                doRep();
                break;
            case 0xac: case 0xad:  // LODSv
                data = lodS();
                setAccum();
                doRep();
                break;
            case 0xae: case 0xaf:  // SCASv
                lodDIS();
                destination = getAccum();
                source = data;
                sub();
                doRep();
                break;
            case 0xb0: case 0xb1: case 0xb2: case 0xb3:
            case 0xb4: case 0xb5: case 0xb6: case 0xb7:
                setRB(fetchByte());
                break;
            case 0xb8: case 0xb9: case 0xba: case 0xbb:
            case 0xbc: case 0xbd: case 0xbe: case 0xbf:  // MOV rv,iv
                setRW(fetchWord());
                break;
            case 0xc2: case 0xc3: case 0xca: case 0xcb:  // RET
                savedIP = pop();
                savedCS = (opcode & 8) == 0 ? cs() : pop();
                if (!wordSize)
                    setSP(sp() + fetchWord());
                farJump();
                break;
            case 0xc4: case 0xc5:  // LES/LDS
                ea();
                farLoad();
                *modRMRW() = savedIP;
                registers[8 + (!wordSize ? 0 : 3)] = savedCS;
                break;
            case 0xc6: case 0xc7:  // MOV rmv,iv
                ea();
                finishWriteEA(fetch(wordSize));
                break;
            case 0xcd:
                data = fetchByte();
                if (data != 0x21) {
                    fprintf(stderr, "Unknown interrupt 0x%02x", data);
                    runtimeError("");
                }
                switch (ah()) {
                    case 2:
                        printf("%c", dl());
                        break;
                    case 0x4c:
                        printf("*** Bytes: %i\n", length);
		        printf("*** Cycles: %i\n", ios);
                        printf("*** EXIT code %i\n", al());
                        exit(0);
                        break;
                    default:
                        fprintf(stderr, "Unknown DOS call 0x%02x", data);
                        runtimeError("");
                }
                break;
            case 0xcf:
                ip = pop();
                setCS(pop());
                flags = pop() | 2;
                break;
            case 0xd0: case 0xd1: case 0xd2: case 0xd3:  // rot rmv,n
                data = readEA();
                if ((opcode & 2) == 0)
                    source = 1;
                else
                    source = cl();
                while (source != 0) {
                    destination = data;
                    switch (modRMReg()) {
                        case 0:  // ROL
                            data <<= 1;
                            doCF();
                            data |= (cf() ? 1 : 0);
                            setOFRotate();
                            break;
                        case 1:  // ROR
                            setCF((data & 1) != 0);
                            data >>= 1;
                            if (cf())
                                data |= (!wordSize ? 0x80 : 0x8000);
                            setOFRotate();
                            break;
                        case 2:  // RCL
                            data = (data << 1) | (cf() ? 1 : 0);
                            doCF();
                            setOFRotate();
                            break;
                        case 3:  // RCR
                            data >>= 1;
                            if (cf())
                                data |= (!wordSize ? 0x80 : 0x8000);
                            setCF((destination & 1) != 0);
                            setOFRotate();
                            break;
                        case 4:  // SHL
                        case 6:
                            data <<= 1;
                            doCF();
                            setOFRotate();
                            setPZS();
                            break;
                        case 5:  // SHR
                            setCF((data & 1) != 0);
                            data >>= 1;
                            setOFRotate();
                            setAF(true);
                            setPZS();
                            break;
                        case 7:  // SAR
                            setCF((data & 1) != 0);
                            data >>= 1;
                            if (!wordSize)
                                data |= (destination & 0x80);
                            else
                                data |= (destination & 0x8000);
                            setOFRotate();
                            setAF(true);
                            setPZS();
                            break;
                    }
                    --source;
                }
                finishWriteEA(data);
                break;
            case 0xd4:  // AAM
                data = fetchByte();
                if (data == 0)
                    divideOverflow();
                setAH(al() / data);
                setAL(al() % data);
                wordSize = true;
                setPZS();
                break;
            case 0xd5:  // AAD
                data = fetchByte();
                setAL(al() + ah()*data);
                setAH(0);
                setPZS();
                break;
            case 0xd6:  // SALC
                setAL(cf() ? 0xff : 0x00);
                break;
            case 0xd7:  // XLATB
                setAL(readByte(bx() + al()));
                break;
            case 0xe0: case 0xe1: case 0xe2:  // LOOPc cb
                setCX(cx() - 1);
                jump = (cx() != 0);
                switch (opcode) {
                    case 0xe0: if (zf()) jump = false; break;
                    case 0xe1: if (!zf()) jump = false; break;
                }
                jumpShort(fetchByte(), jump);
                break;
            case 0xe3:  // JCXZ cb
                jumpShort(fetchByte(), cx() == 0);
                break;
            case 0xe8:  // CALL cw
                call(ip + fetchWord());
                break;
            case 0xe9:  // JMP cw
                ip += fetchWord();
                break;
            case 0xea:  // JMP cp
                savedIP = fetchWord();
                savedCS = fetchWord();
                farJump();
                break;
            case 0xeb:  // JMP cb
                jumpShort(fetchByte(), true);
                break;
            case 0xf2: case 0xf3:  // REP
                rep = opcode == 0xf2 ? 1 : 2;
                prefix = true;
                break;
            case 0xf5:  // CMC
                flags ^= 1;
                break;
            case 0xf6: case 0xf7:  // math rmv
                data = readEA();
                switch (modRMReg()) {
                    case 0: case 1:  // TEST rmv,iv
                        test(data, fetch(wordSize));
                        break;
                    case 2:  // NOT iv
                        finishWriteEA(~data);
                        break;
                    case 3:  // NEG iv
                        source = data;
                        destination = 0;
                        sub();
                        finishWriteEA(data);
                        break;
                    case 4: case 5:  // MUL rmv, IMUL rmv
                        source = data;
                        destination = getAccum();
                        data = destination;
                        setSF();
                        setPF();
                        data *= source;
                        setAX(data);
                        if (!wordSize) {
                            if (modRMReg() == 4)
                                setCF(ah() != 0);
                            else {
                                if ((source & 0x80) != 0)
                                    setAH(ah() - destination);
                                if ((destination & 0x80) != 0)
                                    setAH(ah() - source);
                                setCF(ah() ==
                                    ((al() & 0x80) == 0 ? 0 : 0xff));
                            }
                        }
                        else {
                            setDX(data >> 16);
                            if (modRMReg() == 4) {
                                data |= dx();
                                setCF(dx() != 0);
                            }
                            else {
                                if ((source & 0x8000) != 0)
                                    setDX(dx() - destination);
                                if ((destination & 0x8000) != 0)
                                    setDX(dx() - source);
                                data |= dx();
                                setCF(dx() ==
                                    ((ax() & 0x8000) == 0 ? 0 : 0xffff));
                            }
                        }
                        setZF();
                        setOF(cf());
                        break;
                    case 6: case 7:  // DIV rmv, IDIV rmv
                        source = data;
                        if (source == 0)
                            divideOverflow();
                        if (!wordSize) {
                            destination = ax();
                            if (modRMReg() == 6) {
                                div();
                                if (data > 0xff)
                                    divideOverflow();
                            }
                            else {
                                destination = ax();
                                if ((destination & 0x8000) != 0)
                                    destination |= 0xffff0000;
                                source = signExtend(source);
                                div();
                                if (data > 0x7f && data < 0xffffff80)
                                    divideOverflow();
                            }
                            setAH(remainder);
                            setAL(data);
                        }
                        else {
                            destination = (dx() << 16) + ax();
                            div();
                            if (modRMReg() == 6) {
                                if (data > 0xffff)
                                    divideOverflow();
                            }
                            else {
                                if (data > 0x7fff && data < 0xffff8000)
                                    divideOverflow();
                            }
                            setDX(remainder);
                            setAX(data);
                        }
                        break;
                }
                break;
            case 0xf8: case 0xf9:  // STC/CLC
                setCF(wordSize);
                break;
            case 0xfa: case 0xfb:  // STI/CLI
                setIF(wordSize);
                break;
            case 0xfc: case 0xfd:  // STD/CLD
                setDF(wordSize);
                break;
            case 0xfe: case 0xff:  // misc
                ea();
                if ((!wordSize && modRMReg() >= 2 && modRMReg() <= 6) ||
                    modRMReg() == 7) {
                    fprintf(stderr, "Invalid instruction %02x %02x", opcode,
                        modRM);
                    runtimeError("");
                }
                switch (modRMReg()) {
                    case 0: case 1:  // incdec rmv
                        destination = readEA2();
                        finishWriteEA(incdec(modRMReg() != 0));
                        break;
                    case 2:  // CALL rmv
                        call(readEA2());
                        break;
                    case 3:  // CALL mp
                        farLoad();
                        farCall();
                        break;
                    case 4:  // JMP rmw
                        ip = readEA2();
                        break;
                    case 5:  // JMP mp
                        farLoad();
                        farJump();
                        break;
                    case 6:  // PUSH rmw
                        push(readEA2());
                        break;
                }
                break;
        }
    }
    runtimeError("Timed out");
}
示例#9
0
void jumpShort(Byte data, bool jump) { if (jump) ip += signExtend(data); }
示例#10
0
bool ArmElfRelocator::relocateOpcode(int type, RelocationData& data)
{
	int t = (data.targetSymbolType == STT_FUNC && data.targetSymbolInfo != 0) ? 1 : 0;
	int p = data.opcodeOffset;
	int s = data.relocationBase;

	switch (type)
	{
	case R_ARM_ABS32:		// (S + A) | T
	case R_ARM_TARGET1:
		data.opcode = (data.opcode + data.relocationBase) | t;
		break;
	case R_ARM_THM_CALL:	// ((S + A) | T) – P
		{
			unsigned short first = data.opcode & 0xFFFF;
			unsigned short second = (data.opcode >> 16) & 0xFFFF;
			int opField = ((first & 0x7FF) << 11) | (second & 0x7FF);
			int a = signExtend(opField << 1,23);
			int value = (s+a) - p;

			first &= ~0x7FF;
			second &= ~0x7FF;

			if (t == 1)
			{
				if (data.relocationBase % 2)
				{
					data.errorMessage = L"Branch target must be halfword aligned";
					return false;
				}
			} else {
				if (arm9 == false)
				{
					data.errorMessage = L"Cannot call ARM function from THUMB code without stub";
					return false;
				}

				if (data.relocationBase % 4)
				{
					data.errorMessage = L"Branch target must be word aligned";
					return false;
				}
				
				second = 0xE800;
			}

			if (abs(value) >= 0x400000)
			{
				data.errorMessage = formatString(L"Branch target %08X out of range",data.relocationBase);
				return false;
			}

			value >>= 1;
			first |= (value >> 11) & 0x7FF;
			second |= value & 0x7FF;
			data.opcode = first | (second << 16);
		}
		break;
	case R_ARM_CALL:		// ((S + A) | T) – P
	case R_ARM_JUMP24:		// ((S + A) | T) – P
		{
			int condField = (data.opcode >> 28) & 0xF;
			int opField = (data.opcode & 0xFFFFFF) << 2;
			data.opcode &= ~0xFFFFFF;

			int a = signExtend(opField,26);
			int value = (s+a) - p;

			if (t == 1)
			{
				if (data.relocationBase % 2)
				{
					data.errorMessage = L"Branch target must be halfword aligned";
					return false;
				}

				if (type == R_ARM_JUMP24)
				{
					data.errorMessage = L"Cannot jump from ARM to THUMB without link";
					return false;
				}

				if (arm9 == false)
				{
					data.errorMessage = L"Cannot call THUMB function from ARM code without stub";
					return false;
				}

				if (condField != 0xE)
				{
					data.errorMessage = L"Cannot convert conditional bl into blx";
					return false;
				}

				data.opcode = 0xFA000000;
				if (value & 2)
					data.opcode |= (1 << 24);
			} else {
				if (data.relocationBase % 4)
				{
					data.errorMessage = L"Branch target must be word aligned";
					return false;
				}
			}
			
			if (abs(value) >= 0x2000000)
			{
				data.errorMessage = formatString(L"Branch target %08X out of range",data.relocationBase);
				return false;
			}

			data.opcode |= (value >> 2) & 0xFFFFFF;
		}
		break;
	default:
		data.errorMessage = formatString(L"Unknown ARM relocation type %d",type);
		return false;
	}

	return true;
}