⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cputhumbcore.pas

📁 一个不出名的GBA模拟器
💻 PAS
📖 第 1 页 / 共 2 页
字号:
//////////////////////////////////////////////////////////////////////
//                                                                  //
// cpuThumbCore.pas: Thumb instruction set decoder and executer     //
//   Decodes and executes Thumb instructions                        //
//                                                                  //
// The contents of this file are subject to the Bottled Light       //
// Public License Version 1.0 (the "License"); you may not use this //
// file except in compliance with the License. You may obtain a     //
// copy of the License at http://www.bottledlight.com/BLPL/         //
//                                                                  //
// Software distributed under the License is distributed on an      //
// "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or   //
// implied. See the License for the specific language governing     //
// rights and limitations under the License.                        //
//                                                                  //
// The Original Code is the Mappy VM Core, released April 1st, 2003 //
// The Initial Developer of the Original Code is Bottled Light,     //
// Inc. Portions created by Bottled Light, Inc. are Copyright       //
// (C) 2001 - 2003 Bottled Light, Inc. All Rights Reserved.         //
//                                                                  //
// Author(s):                                                       //
//   Michael Noland (joat), michael@bottledlight.com                //
//                                                                  //
// Changelog:                                                       //
//   1.0: First public release (April 1st, 2003)                    //
//                                                                  //
// Notes:                                                           //
//   This operates differently to a real ARM7T processor, since     //
//   it directly executes Thumb opcodes.  The ARM7T converts them   //
//   to equivelant ARM instructions at no speed penalty, but that   //
//   would require two complete decodes and a conversion if done    //
//   in software.                                                   //
//                                                                  //
//   There are still a few bugs either here or in the ARM core, as  //
//   evidenced by the glitches in the BIOS display sequence.  It    //
//   *could* be a result of a bug in the graphics code, but it is   //
//   pretty unlikely.                                               //
//                                                                  //
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
unit cpuThumbCore; ///////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//                                                                  //
// CPU - Thumb instruction set decoder:                             //
//   Decodes and executes thumb opcodes                             //
//                                                                  //
// All code contained unless explicitly stated is (C) Copyright     //
// January 8th 2001 to Present by Michael Noland, part of Mappy VM  //
//                                                                  //
//////////////////////////////////////////////////////////////////////
interface ////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

// EmulateThumb() emulates thumb opcodes until one of the following
// conditions is met:
//   the cycle quota is exhausted
//   the CPU switches into ARM mode
//   a breakpoint is encountered
procedure EmulateThumb;

//////////////////////////////////////////////////////////////////////
implementation ///////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

uses
  SysUtils, nexus, AddressSpace, cpuMemory, cpuMisc, cpuARMCore;

//////////////////////////////////////////////////////////////////////

procedure EmulateThumb;
var
  t: uint16;
  rs, rd, c: byte;
  cond: boolean;
  i, test: uint32;
  neg1, neg2, negr: boolean;
  operand1, operand2: uint32;
  shift, shiftType: byte;
begin
  repeat
    if irqPending and not irqDisabled then Exit;

{$IFDEF SIGNATURES}
    // Add a thumb signature to the address of the current opcode
    operand2 := regs[R15]-2;
    if operand2 >= $08000000 then begin
      operand2 := (operand2 shr 1) and $FFFFFF;
      sigs[operand2] := sigs[operand2] or THUMB_READ;
    end;
{$ENDIF}

    // Grab an opcode from the pipeline and read in a new opcode
    t := regs[PIPELINE_0];
    regs[PIPELINE_0] := regs[PIPELINE_1];              // at currentAddress + L
    Inc(regs[R15], 2);
    regs[PIPELINE_1] := memReadHalfwordUnc(regs[R15]); // at currentAddress + 2L

    // Do a coarse search based on the top 8 bits of each opcode
    c := t shr 8;
    case c of
      $00..$07: begin
        // Format 1: Move shifted register, [lsl Rd, Rs, #Offset5]
        test := BarrelShifter(regs[(t shr 3) and 7], LSL, (t shr 6) and 31);
        carry := barrelCarry;
        negative := test shr 31 <> 0;
        zero := test = 0;
        regs[t and 7] := test;
      end;

      $08..$0F: begin
        // Format 1: Move shifted register, [lsr Rd, Rs, #Offset5]
        test := BarrelShifter(regs[(t shr 3) and 7], LSR, (t shr 6) and 31);
        carry := barrelCarry;
        negative := test shr 31 <> 0;
        zero := test = 0;
        regs[t and 7] := test;
      end;

      $10..$17: begin
        // Format 1: Move shifted register, [asr Rd, Rs, #Offset5]
        test := BarrelShifter(regs[(t shr 3) and 7], ASR, (t shr 6) and 31);
        carry := barrelCarry;
        negative := test shr 31 <> 0;
        zero := test = 0;
        regs[t and 7] := test;
      end;

      $18..$19: begin
        // Format 2: add, [add Rd, Rs, Rn]
        operand1 := regs[(t shr 3) and 7];
        operand2 := regs[(t shr 6) and 7];
        test := operand1 + operand2;

        neg1 := operand1 shr 31 <> 0;
        neg2 := operand2 shr 31 <> 0;
        negative := test shr 31 <> 0;
        overflow := (neg1 = neg2) and (neg1 <> negative);
        carry := (neg1 and neg2) or ((neg1 or neg2) and not negative);
        zero := test = 0;

        regs[t and 7] := test;
      end;

      $1A..$1B: begin
        // Format 2: subtract, [sub Rd, Rs, Rn]
        operand1 := regs[(t shr 3) and 7];
        operand2 := regs[(t shr 6) and 7];
        test := operand1 - operand2;

        neg1 := operand1 shr 31 <> 0;
        neg2 := operand2 shr 31 <> 0;
        negative := test shr 31 <> 0;
        overflow := (neg1 and not neg2 and not negative) or (not neg1 and neg2 and negative);
        carry := (neg1 and not neg2) or (neg1 and not negative) or (not neg2 and not negative);
        zero := test = 0;

        regs[t and 7] := test;
      end;

      $1C..$1D: begin
        // Format 2: add, [add Rd, Rs, #Offset3]
        operand1 := regs[(t shr 3) and 7];
        test := operand1 + (t shr 6) and 7;

        neg1 := operand1 shr 31 <> 0;
        negative := test shr 31 <> 0;
        overflow := negative and not neg1;
        carry := neg1 and not negative;
        zero := test = 0;

        regs[t and 7] := test;
      end;

      $1E..$1F: begin
        // Format 2: subtract, [sub Rd, Rs, #Offset3]
        operand1 := regs[(t shr 3) and 7];
        test := operand1 - (t shr 6) and 7;

        neg1 := operand1 shr 31 <> 0;
        negative := test shr 31 <> 0;
        overflow := neg1 and not negative;
        carry := neg1 or not negative;
        zero := test = 0;

        regs[t and 7] := test;
      end;

      $20..$27: begin
        // Format 3: move immediate, [mov Rd, #Offset8]
        test := t and $FF;
        negative := test shr 31 <> 0;
        zero := test = 0;
        regs[c and 7] := test;
      end;

      $28..$2F: begin
        // Format 3: compare immediate, [cmp Rd, #Offset8]
        operand1 := regs[c and 7];
        test := operand1 - t and $FF;

        neg1 := operand1 shr 31 <> 0;
        negative := test shr 31 <> 0;
        overflow := neg1 and not negative;
        carry := neg1 or not negative;

        zero := test = 0;
      end;

      $30..$37: begin
        // Format 3: add immediate, [add Rd, #Offset8]
        operand1 := regs[c and 7];
        test := operand1 + t and $FF;

        neg1 := operand1 shr 31 <> 0;
        negative := test shr 31 <> 0;
        overflow := negative and not neg1;
        carry := neg1 and not negative;
        zero := test = 0;

        regs[c and 7] := test;
      end;

      $38..$3F: begin
        // Format 3: subtract immediate, [sub Rd, #Offset8]
        operand1 := regs[c and 7];
        test := operand1 - t and $FF;

        neg1 := operand1 shr 31 <> 0;
        negative := test shr 31 = $1;
        overflow := neg1 and not negative;
        carry := neg1 or not negative;
        negative := test shr 31 <> 0;
        zero := test = 0;

        regs[c and 7] := test;
      end;

      $40..$43: begin
        // Format 4: ALU Operations
        case (t shr 6) and $F of
          $0: begin
            // and Rd, Rs
            if (t = $4000) and (regs[0] = $c0ded00d) then DebugTrap;
            test := regs[t and 7] and regs[(t shr 3) and 7];
            regs[t and 7] := test;
          end;
          $1: begin
            // eor Rd, Rs
            test := regs[t and 7] xor regs[(t shr 3) and 7];
            regs[t and 7] := test;
          end;
          $2: begin
            // lsl Rd, Rs
            shift := regs[(t shr 3) and 7] and $FF;

            if shift = 0 then
              test := regs[t and 7]
            else if shift > 31 then begin
              test := 0;
              carry := (shift = 32) and (regs[t and 7] and (1 shl 0) <> 0);
            end else begin
              test := BarrelShifter(regs[t and 7], LSL, shift);
              carry := barrelCarry;
            end;

            regs[t and 7] := test;
          end;
          $3: begin
            // lsr Rd, Rs
            shift := regs[(t shr 3) and 7] and $FF;

            if shift = 0 then
              test := regs[t and 7]
            else if shift > 31 then begin
              test := 0;
              carry := (shift = 32) and (regs[t and 7] shr 31 <> 0);
            end else begin
              test := BarrelShifter(regs[t and 7], LSR, shift);
              carry := barrelCarry;
            end;

            regs[t and 7] := test;
          end;
          $4: begin
            // asr Rd, Rs
            shift := regs[(t shr 3) and 7] and $FF;

            test := regs[t and 7];
            if shift <> 0 then begin
              test := BarrelShifter(test, ASR, shift);
              carry := barrelCarry;
              regs[t and 7] := test;
            end;
          end;
          $5: begin
            // adc Rd, Rs
            operand1 := regs[t and 7];
            operand2 := regs[(t shr 3) and 7];
            test := operand1 + operand2;
            if carry then Inc(test);
            regs[t and 7] := test;
            neg1 := operand1 shr 31 <> 0;
            neg2 := operand2 shr 31 <> 0;
            negr := test shr 31 <> 0;
            overflow := (neg1 = neg2) and (neg1 <> negr);
            carry := (neg1 and neg2) or ((neg1 or neg2) and not negr);
          end;
          $6: begin
            // sbc Rd, Rs
            operand1 := regs[t and 7];
            operand2 := regs[(t shr 3) and 7];
            test := operand1 - operand2;
            if not carry then Dec(test);
            regs[t and 7] := test;
            neg1 := operand1 shr 31 <> 0;
            neg2 := operand2 shr 31 <> 0;
            negr := test shr 31 <> 0;
            carry := (neg1 and not neg2) or (neg1 and not negr) or (not neg2 and not negr);
            overflow := (neg1 and not neg2 and not negr) or (not neg1 and neg2 and negr);
          end;
          $7: begin
            // ror Rd, Rs
            test := BarrelShifter(regs[t and 7], ROR, regs[(t shr 3) and 7]);
            regs[t and 7] := test;
            carry := barrelCarry;
          end;
          $8: begin
            // tst Rd, Rs
            test := regs[t and 7] and regs[(t shr 3) and 7];
          end;
          $9: begin
            // neg Rd, Rs
            operand1 := regs[(t shr 3) and 7];
            test := -operand1;
            regs[t and 7] := test;
            overflow := (test shr 31 <> 0) and (operand1 shr 31 <> 0);
            carry := not overflow;
          end;
          $A: begin
            // cmp Rd, Rs
            operand1 := regs[t and 7];
            operand2 := regs[(t shr 3) and 7];
            test := operand1 - operand2;
            neg1 := operand1 shr 31 <> 0;
            neg2 := operand2 shr 31 <> 0;
            negr := test shr 31 <> 0;
            carry := (neg1 and not neg2) or (neg1 and not negr) or (not neg2 and not negr);
            overflow := (neg1 and not neg2 and not negr) or (not neg1 and neg2 and negr);
          end;
          $B: begin
            // cmn Rd, Rs
            operand1 := regs[t and 7];
            operand2 := regs[(t shr 3) and 7];
            test := operand1 + operand2;
            neg1 := operand1 shr 31 <> 0;
            neg2 := operand2 shr 31 <> 0;
            negr := test shr 31 <> 0;
            overflow := (neg1 = neg2) and (neg1 <> negr);
            carry := (neg1 and neg2) or ((neg1 or neg2) and not negr);
          end;
          $C: begin
            // orr Rd, Rs
            test := regs[t and 7] or regs[(t shr 3) and 7];
            regs[t and 7] := test;
          end;
          $D: begin
            // mul Rd, Rs
            // Instruction cycle times
            //  MUL takes 1S + mI and MLA 1S + (m+1)I cycles to execute
            //  m is the number of 8 bit multiplier array cycles required to complete the
            //  multiply, which is controlled by the value of the multiplier operand
            //  specified by Rs. Its possible values are as follows:
            //  1 if bits [32:8] of the multiplier operand are all zero or all one.
            //  2 if bits [32:16] of the multiplier operand are all zero or all one.
            //  3 if bits [32:24] of the multiplier operand are all zero or all one.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -