unit frmMainunt;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ComCtrls, ToolWin, Menus, ImgList, AtariDis, SPUnit, frmDebuggerUnt,
  ExtCtrls, StdCtrls, DXDraws, DXClass, DXInput, DXSounds, HandTIA, DirectX,
  DIB, ZipMstr, ActnList, OpenIL, TB2Item, TB2Dock, TB2Toolbar, TB2MRU;

Const
  MaxScan : Integer = 250;
  PadMax      = 800;
  SetLocDelay = 5;
  Read_Delay  = 12500;
  sample_freq   : Word = 31400;

  { TIA write registers }

  VSYNC   = 0;
  VBLANK  = 1;
  WSYNC   = 2;
  RSYNC   = 3;
  NUSIZ0  = 4;
  NUSIZ1  = 5;
  COLUP0  = 6;
  COLUP1  = 7;
  COLUPF  = 8;
  COLUBK  = 9;
  CTRLPF  = $0A;
  REFP0   = $0B;
  REFP1   = $0C;
  PF0     = $0D;
  PF1     = $0E;
  PF2     = $0F;
  RESP0   = $10;
  RESP1   = $11;
  RESM0   = $12;
  RESM1   = $13;
  RESBL   = $14;
  AUDC0   = $15;
  AUDC1   = $16;
  AUDF0   = $17;
  AUDF1   = $18;
  AUDV0   = $19;
  AUDV1   = $1A;
  GRP0    = $1B;
  GRP1    = $1C;
  ENAM0   = $1D;
  ENAM1   = $1E;
  ENABL   = $1F;
  HMP0    = $20;
  HMP1    = $21;
  HMM0    = $22;
  HMM1    = $23;
  HMBL    = $24;
  VDELP0  = $25;
  VDELP1  = $26;
  VDELBL  = $27;
  RESMP0  = $28;
  RESMP1  = $29;
  HMOVE   = $2A;
  HMCLR   = $2B;
  CXCLR   = $2C;
  SWCHA1  = $280;
  SWACNT1 = $281;
  SWCHB1  = $282;
  SWBCNT1 = $283;
  INTTIM1 = $284;
  INTTIM3 = $285;
  TIM1T1  = $294;
  TIM2T1  = $295;
  TIM3T1  = $296;
  TIM4T1  = $297;
  SWCHA2  = $380;
  SWACNT2 = $381;
  SWCHB2  = $382;
  SWBCNT2 = $383;
  INTTIM2 = $384;
  TIM1T2  = $394;
  TIM2T2  = $395;
  TIM3T2  = $396;
  TIM4T2  = $397;

  { TIA read registers }

  INPUT0  = $8;
  INPUT1  = $9;
  INPUT2  = $A;
  INPUT3  = $B;
  INPUT4  = $C;
  INPUT5  = $D;

  Player0Set  = 2;
  Player1Set  = 4;
  Missile0Set = 8;
  Missile1Set = 16;
  BallSet     = 32;

  MissileSize  : Packed Array[0..3] Of Byte = (1,2,4,8);
  PlayerSize   : Packed Array[0..7] Of LongInt = (7,23,39,39,71,15,71,31);
  PlayerSizeD  : Packed Array[0..7] Of LongInt = (13,29,45,45,77,22,77,38);
  _PlayerSize  : Packed Array[0..7] Of LongInt = (8,8,8,8,8,16,8,32);

  PlayerZone1  : Packed Array[0..7] Of LongInt = ( 3, 3, 3, 3, 3, 4, 3, 4);
  PlayerInc1   : Packed Array[0..7] Of LongInt = ( 0, 2,18, 2,50, 0,18, 0);
  PlayerZone2  : Packed Array[0..7] Of LongInt = ( 0, 4, 4, 4, 4, 0, 4, 0);
  PlayerInc2   : Packed Array[0..7] Of LongInt = ( 0, 0, 0, 2, 0, 0,18, 0);

  MissileZone1 : Packed Array[0..7] Of LongInt = ( 3, 3, 3, 3, 3, 3, 3, 3);
  MissileInc1  : Packed Array[0..7] Of LongInt = ( 0, 2,18, 2,50, 0,18, 0);
  MissileZone2 : Packed Array[0..7] Of LongInt = ( 0, 4, 4, 4, 4, 0, 4, 0);
  MissileInc2  : Packed Array[0..7] Of LongInt = ( 0, 0, 0, 2, 0, 0,18, 0);

  M0BugMove    : Packed Array[0..3] Of LongInt = (15,15,16,14);

  Add1A        : Packed Array[0..7] Of LongInt = (8,272,544,-528,  320,16,-1056,32);

  MissileAdd1  : Packed Array[0..7] Of LongInt = (8,16,32,16,64,16,32,32);

  PFDelay      : Packed Array[0..3] Of Byte = (5,2,3,4);

  TIA_And      : Packed Array[0..$7F] Of Byte =
   ($00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F,
    $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$1F,
    $20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2A,$2B,$2C,$2D,$2E,$2F,
    $30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3A,$3B,$3C,$3D,$3E,$3F,
    $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F,
    $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D,$1E,$1F,
    $20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2A,$2B,$2C,$2D,$2E,$2F,
    $30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3A,$3B,$3C,$3D,$3E,$3F);

  SP1 : Packed Array[0..7] Of Word = ($1000,$0000,$1000,$0000,$1000,$0800,$1000,$0800);
  SP2 : Packed Array[0..7] Of Word = ($1800,$1800,$0000,$1000,$1800,$1800,$0800,$1000);

type
  TfrmMain = class(TDXForm)
    ImageList1: TImageList;
    dlgSave: TSaveDialog;
    dlgOpen: TOpenDialog;
    DXDraw1: TDXDraw;
    DXSound1: TDXSound;
    ImageList2: TImageList;
    DXInput1: TDXInput2;
    Image1: TImage;
    ZipMaster1: TZipMaster;
    ActionList1: TActionList;
    acOpen: TAction;
    acPreferences: TAction;
    acProfileSettings: TAction;
    acUseDebugger: TAction;
    acRebuildGameProfile: TAction;
    acDisassemble: TAction;
    acSaveScreenshot: TAction;
    acLoadSavedGame: TAction;
    acSaveGame: TAction;
    acExit: TAction;
    acStartEmulation: TAction;
    acStopEmulation: TAction;
    acResetEmulation: TAction;
    acControllerJoystick: TAction;
    acControllerPaddle: TAction;
    acControllerKeyboard: TAction;
    acControllerIndy500: TAction;
    acControllerVTP: TAction;
    acControllerBoosterGrip: TAction;
    acConfigureInterfaces: TAction;
    acEnableMouse: TAction;
    acEnableKeyboard: TAction;
    acEnableController: TAction;
    acVideoFullScreen: TAction;
    acVideoTVScreen: TAction;
    acVideo320x200: TAction;
    acVideo320x204: TAction;
    acVideo320x215: TAction;
    acVideo320x250: TAction;
    acVideo320x305: TAction;
    acVideoZoom1x: TAction;
    acVideoZoom2x: TAction;
    acVideoZoom3x: TAction;
    acVideoZoom4x: TAction;
    acVideoZoomFull: TAction;
    acVideoRecordToAVI: TAction;
    acHelpAbout: TAction;
    acNetPlay: TAction;
    acShowManual: TAction;
    acDifficulty1: TAction;
    acDifficulty2: TAction;
    TBDock1: TTBDock;
    TBToolbar1: TTBToolbar;
    mnuFile: TTBSubmenuItem;
    Open1: TTBItem;
    Preferences1: TTBItem;
    mnuProfile: TTBItem;
    Usedebugger1: TTBItem;
    Rebuildgameprofile1: TTBItem;
    mnuDisassemble: TTBItem;
    mnuScreenShot: TTBItem;
    mnuLoadGame: TTBItem;
    mnuSaveGame: TTBItem;
    Exit1: TTBItem;
    mnuEmulation: TTBSubmenuItem;
    mnuStart: TTBItem;
    mnuStop: TTBItem;
    Reset1: TTBItem;
    mnuController: TTBSubmenuItem;
    Joystick1: TTBItem;
    Paddle1: TTBItem;
    Keyboard1: TTBItem;
    Indy5001: TTBItem;
    VideoTouchPad1: TTBItem;
    BoosterGrip1: TTBItem;
    mnuInterfaces: TTBSubmenuItem;
    Configure1: TTBItem;
    Enable1: TTBSubmenuItem;
    Mouse1: TTBItem;
    Keyboard2: TTBItem;
    Controller2: TTBItem;
    mnuVideo: TTBSubmenuItem;
    mnuFullScreen: TTBItem;
    mnuTVScreen: TTBItem;
    mnuMode: TTBSubmenuItem;
    mnu320x200: TTBItem;
    mnu320x204: TTBItem;
    mnu320x215: TTBItem;
    mnu320x250: TTBItem;
    mnu320x305: TTBItem;
    mnuZoom: TTBSubmenuItem;
    mnuZoom1x: TTBItem;
    mnuZoom2x: TTBItem;
    mnuZoom3x: TTBItem;
    mnuZoom4x: TTBItem;
    mnuZoomFull: TTBItem;
    mnuRecordAVI: TTBItem;
    mnuHelp: TTBSubmenuItem;
    mnuAbout: TTBItem;
    TBDock2: TTBDock;
    TBToolbar2: TTBToolbar;
    TBItem1: TTBItem;
    TBItem2: TTBItem;
    TBItem3: TTBItem;
    TBSeparatorItem1: TTBSeparatorItem;
    TBItem4: TTBItem;
    TBItem5: TTBItem;
    TBItem6: TTBItem;
    TBSeparatorItem2: TTBSeparatorItem;
    TBItem9: TTBItem;
    TBItem10: TTBItem;
    TBItem11: TTBItem;
    TBItem12: TTBItem;
    TBToolbar3: TTBToolbar;
    ActionList2: TActionList;
    acSelect: TAction;
    acReset: TAction;
    acColorBW: TAction;
    acNTSCPal: TAction;
    TBItem13: TTBItem;
    TBItem14: TTBItem;
    TBItem15: TTBItem;
    TBItem16: TTBItem;
    TBItem17: TTBItem;
    TBItem18: TTBItem;
    TBSeparatorItem3: TTBSeparatorItem;
    TBItem7: TTBItem;
    TBSeparatorItem4: TTBSeparatorItem;
    TBSeparatorItem5: TTBSeparatorItem;
    TBSeparatorItem6: TTBSeparatorItem;
    TBMRUListItem1: TTBMRUListItem;
    MRUList: TTBMRUList;
    procedure FormShow(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure DXSound1Initialize(Sender: TObject);
    procedure DXSound1Finalize(Sender: TObject);
    procedure CoolBar1Resize(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormResize(Sender: TObject);
    procedure acOpenExecute(Sender: TObject);
    procedure acPreferencesExecute(Sender: TObject);
    procedure acProfileSettingsExecute(Sender: TObject);
    procedure acUseDebuggerExecute(Sender: TObject);
    procedure acRebuildGameProfileExecute(Sender: TObject);
    procedure acDisassembleExecute(Sender: TObject);
    procedure acSaveScreenshotExecute(Sender: TObject);
    procedure acLoadSavedGameExecute(Sender: TObject);
    procedure acSaveGameExecute(Sender: TObject);
    procedure acExitExecute(Sender: TObject);
    procedure acStartEmulationExecute(Sender: TObject);
    procedure acStopEmulationExecute(Sender: TObject);
    procedure acResetEmulationExecute(Sender: TObject);
    procedure acControllerJoystickExecute(Sender: TObject);
    procedure acControllerPaddleExecute(Sender: TObject);
    procedure acControllerKeyboardExecute(Sender: TObject);
    procedure acControllerIndy500Execute(Sender: TObject);
    procedure acControllerVTPExecute(Sender: TObject);
    procedure acControllerBoosterGripExecute(Sender: TObject);
    procedure acConfigureInterfacesExecute(Sender: TObject);
    procedure acEnableMouseExecute(Sender: TObject);
    procedure acEnableKeyboardExecute(Sender: TObject);
    procedure acEnableControllerExecute(Sender: TObject);
    procedure acVideoFullScreenExecute(Sender: TObject);
    procedure acVideoTVScreenExecute(Sender: TObject);
    procedure acVideo320x200Execute(Sender: TObject);
    procedure acVideo320x204Execute(Sender: TObject);
    procedure acVideo320x215Execute(Sender: TObject);
    procedure acVideo320x250Execute(Sender: TObject);
    procedure acVideo320x305Execute(Sender: TObject);
    procedure acVideoZoom1xExecute(Sender: TObject);
    procedure acVideoZoom2xExecute(Sender: TObject);
    procedure acVideoZoom4xExecute(Sender: TObject);
    procedure acVideoZoom3xExecute(Sender: TObject);
    procedure acVideoZoomFullExecute(Sender: TObject);
    procedure acVideoRecordToAVIExecute(Sender: TObject);
    procedure acHelpAboutExecute(Sender: TObject);
    procedure acNetPlayExecute(Sender: TObject);
    procedure acShowManualExecute(Sender: TObject);
    procedure acDifficulty1Execute(Sender: TObject);
    procedure acDifficulty2Execute(Sender: TObject);
    procedure acSelectExecute(Sender: TObject);
    procedure acResetExecute(Sender: TObject);
    procedure acColorBWExecute(Sender: TObject);
    procedure acNTSCPalExecute(Sender: TObject);
    procedure TBDock2Resize(Sender: TObject);
    procedure TBDock1Resize(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure MRUListClick(Sender: TObject; const Filename: String);
  private
    { Private declarations }
    SWidth        : Integer;
    SHeight       : Integer;
    Zoom          : Integer;
    Secondary     : TDirectSoundBuffer;
    Showed        : Boolean;
    Procedure SaveStatus;
    Procedure RestoreStatus;
    Procedure SetImageSizes(Starting: Boolean);
    Procedure UpdateDebugger;
    Procedure DeactivateApp(Sender: TObject);
  public
    { Public declarations }
    ShowCrosshair : Boolean;
    UseDirectDraw : Boolean;
    DDFullScreen  : Boolean;
    TVScreen      : Boolean;
    DoubleUp      : Boolean;
    LastFSWidth   : Integer;
    LastFSHeight  : Integer;
    Pos200        : Integer;
    Pos204        : Integer;
    Pos215        : Integer;
    Pos250        : Integer;
    Pos305        : Integer;
    ROMFileName   : String;
    FPS           : Double;
    Frames        : Integer;
    BaseTime      : LongInt;
    Procedure Display;
    Procedure UpdateButtonStatuses;
    Procedure LoadGame(FileName,ZipFileName,Title: String);
    Procedure LoadGameFromAnywhere(FileName: String);
    Function  EnterFullScreenMode: Boolean;
    Procedure ExitFullScreenMode;
  end;

var
  frmMain     : TfrmMain;
  Pal         : TPalette;

Procedure Emulate;

implementation

{$R *.DFM}

Uses MMSystem,frmMenuUnt,Profile,AtariControls,frmPrefsUnt,TIASound,
     Equation,HexWrite, Wave, frmTIARefUnt, frmExpRefUnt,
     frmAboutUnt, frmProfileSettingsUnt, JPEG, frmAltMenuUnt, WriteAVI,
     frmConfigureUnt,frmKailleraUnt, frmManualUnt, INIFiles;

Type
  _TBitmapInfo = Packed Record
    B : TBitmapInfo;
    bmiColors: Packed Array[0..255] Of TRGBQuad;
  end;
  _TLogPalette = Packed Record
    T : TLogPalette;
    P : Packed Array[0..255] Of TPaletteEntry;
  End;

Var
  PF2Wave             : Integer;
//  SoundQueue          : Packed Array[0..1025] Of Byte;
  SoundQueue_In       : Word;
  SoundQueue_Out      : Word;
  SoundQueue_Num      : Word;
  BufPlaying          : Byte;
//  SmallSoundBuf       : Packed Array[0..259] Of Byte;
  Time0               : Double;
  TimeErr             : Double;
  DebugLoad           : Boolean;
  Div3                : Packed Array[0..228] Of Byte;


  PaletteChange       : Boolean;
  ResetChange         : Boolean;
  SelectChange        : Boolean;
  ColorOrBWChange     : Boolean;
  Difficulty1Change   : Boolean;
  Difficulty2Change   : Boolean;
  AutoCenter          : Boolean;
  AutoCenterChange    : Boolean;
  Handle_IO_Set       : Boolean;
  Handle_IO_Set_After : Boolean;
  Handle_IO_Set_Latch : Boolean;
  Handle_IO_Loc       : Packed Array[0..TIM4T2] Of LongInt;
  Handle_IO_Loc_After : Packed Array[0..CXCLR] Of LongInt;
  Handle_IO_Loc_Latch : Packed Array[0..CXCLR] Of LongInt;
  TIA_Delay           : Packed Array[0..CXCLR] Of Word;
//  BCD_A               : Byte;
//  BCD_Add             : Byte;
//  BCD_Flags           : Byte;
  ExtraAdd            : Packed Array[-68..160] Of ShortInt;
  ControlFrame        : Integer;
  Locations           : Packed Array[0..255] Of LongInt;
  ExpError            : Boolean;
  BufToFill           : Byte;
  BI                  : _TBitmapInfo;
  BI1                 : _TBitmapInfo;
  PI                  : _TLogPalette;
  I                   : Integer;
  LocalBufSize        : LongInt;
  UseMMX              : Boolean;
  Menu                : TMainMenu;
  Emulating           : Integer;
  AVIFile             : TAVIFile;

Procedure CheckAVIStream;
Begin
  If AVIFile.Opened Then AVIFile.WriteFrame(ScnPtr,False);
End; { CheckAVIStream }

Procedure QueueLatch(Latch: Byte; Value,Scan,Count: SmallInt); Pascal;
Begin
  Asm
    PUSHAD
    PUSHF
    MOV   AL,BYTE PTR Latch
    MOV   DX,WORD PTR Value
    MOV   BX,WORD PTR Scan
    MOV   CX,WORD PTR Count
    SUB   ESI,ESI
    CMP   WORD PTR Game.TIA_Latch_Queue,LatchQueueSize
    JGE   @LocalGetOut
    MOV   SI,WORD PTR Game.TIA_Latch_Queue
    INC   WORD PTR Game.TIA_Latch_Queue
    MOV   BYTE PTR Game.TIA_Latch_Reg[ESI],AL
    ADD   SI,SI
    MOV   WORD PTR Game.TIA_Latch_Value[ESI],DX
    MOV   WORD PTR Game.TIA_Latch_Scan[ESI],BX
    MOV   WORD PTR Game.TIA_Latch_Count[ESI],CX
    SUB   EBX,EBX
    MOV   BL,AL
    INC   BYTE PTR Game.TIA_Latch_RegCount[EBX]
@LocalGetOut:
    POPF
    POPAD
  End; { Asm }
End; { QueueLatch }
(*
Procedure FillPf2Buf(Count: LongInt);
Const
  Smooth = 15;
  Fudge  = 1.0;

Var
  I         : LongInt;
  Amp       : Byte;
  LenRatio  : Single;
  Changed   : Boolean;
  Mult      : Array[1..3] Of Single;

Begin

  { First see if any Pitfall II sound values have changed for the three }
  { channels.  If anything has changed, the sound parameters have to be }
  { recalculated.  The code below is actually comparing four bytes at a }
  { time, but the fourth byte is always left at zero, so it doesn't     }
  { matter.                                                             }

  Changed := False;
  Asm
    MOV   EAX,DWORD PTR Old_WaveLen
    CMP   EAX,DWORD PTR WaveLen
    JNE   @L1

    MOV   EAX,DWORD PTR Old_Pulse
    CMP   EAX,DWORD PTR Pulse
    JNE   @L1

    MOV   EAX,DWORD PTR Old_Phase
    CMP   EAX,DWORD PTR Phase
    JNE   @L1

    MOV   EAX,DWORD PTR Old_Signal
    CMP   EAX,DWORD PTR Signal
    JNE   @L1

    JMP   @L2
@L1:
    MOV   BYTE PTR Changed,1
@L2:
  End; { Asm }

  If Changed Then
  Begin

    { The mutipliers below are fudge factors to equalize the ratio between }
    { the Pitfall II's internal sample rate and the normal Atari rate of   }
    { 31.4 kHz.                                                            }

    Mult[1] := 1.75;
    Mult[2] := 1.75;
    Mult[3] := 1.75;

    { Account for the fact that the PC's playback rate (normally 44.1kHz, }
    { but can be otherwise) differs from the Atari's playback rate of     }
    { 31.4kHz.                                                            }

    LenRatio := Playback_Freq / 31400;

    For I := 1 To 3 Do
    Begin
      _WaveLen[I] := WaveLen[I] * Mult[I] * LenRatio;
      _Pulse[I]   := Pulse[I]   * Mult[I] * LenRatio;
      If _WaveLen[I] > 0 Then
      Begin
        If _Pulse[I] >= _WaveLen[I] Then
         _Pulse[I] := _Pulse[I] - Trunc(_Pulse[I] / _WaveLen[I]) * _WaveLen[I];
        If _Wave[I] >= _WaveLen[I] Then
         _Wave[I] := _Wave[I] - Trunc(_Wave[I] / _WaveLen[I]) * _WaveLen[I];
      End
      Else _Wave[I] := 0;
      _Wave[I] := _Wave[I] - 1;
      Rem_Wave[I] := 0;
    End; { For I }

    Asm
      MOV   EAX,DWORD PTR WaveLen
      MOV   ECX,DWORD PTR Pulse
      MOV   EDX,DWORD PTR Phase

      MOV   DWORD PTR Old_WaveLen,EAX
      MOV   DWORD PTR Old_Pulse,ECX
      MOV   DWORD PTR Old_Phase,EDX

      MOV   EAX,DWORD PTR Signal
      MOV   ECX,DWORD PTR SPWave

      MOV   DWORD PTR Old_Signal,EAX
      MOV   DWORD PTR Old_Wave,ECX
    End; { Asm }
  End;
  For I := 0 To Count - 1 Do
  Begin
    Inc(Pf2Wave);

    _Wave[1] := _Wave[1] + 1;
    _Wave[2] := _Wave[2] + 1;
    _Wave[3] := _Wave[3] + 1;

    If _Wave[1] + Rem_Wave[1] >= _WaveLen[1] Then
    Begin
      Rem_Wave[1] := _Wave[1] + Rem_Wave[1] - _WaveLen[1];
      _Wave[1]    := 0;
    End;
    If _Wave[2] + Rem_Wave[2] >= _WaveLen[2] Then
    Begin
      Rem_Wave[2] := _Wave[2] + Rem_Wave[2] - _WaveLen[2];
      _Wave[2]    := 0;
    End;
    If _Wave[3] + Rem_Wave[3] >= _WaveLen[3] Then
    Begin
      Rem_Wave[3] := _Wave[3] + Rem_Wave[3] - _WaveLen[3];
      _Wave[3]    := 0;
    End;

    Amp := 0;

    { DSP to simulate RF modulation and demodulation.  Results in "muddy" }
    { sound.                                                              }

    If Config.Pitfall2DSP Then
    Begin
      Case Signal[1] Of
        1: Amp := $20;
        3: If _Wave[1] + Rem_Wave[1] <= _Pulse[1] Then
           Begin
             Amp := $20;
             If _Wave[1] + Rem_Wave[1] <= Smooth
              Then Dec(Amp,Round(Smooth - (_Wave[1] + Rem_Wave[1])))
              Else If _Wave[1] + Rem_Wave[1] > _Pulse[1] - Smooth
                    Then Dec(Amp,Round((_Wave[1] + Rem_Wave[1]) - (_Pulse[1] - Smooth)));
           End;
      End; { Case }

      Case Signal[2] Of
        1: Inc(Amp,$28);
        3: If _Wave[2] + Rem_Wave[2] <= _Pulse[2] Then
           Begin
             Inc(Amp,$28);
             If _Wave[2] + Rem_Wave[2] <= Smooth
              Then Dec(Amp,Round(Smooth - (_Wave[2] + Rem_Wave[2])))
              Else If _Wave[2] + Rem_Wave[2] > _Pulse[2] - Smooth
                    Then Dec(Amp,Round((_Wave[2] + Rem_Wave[2]) - (_Pulse[2] - Smooth)));
           End;
      End; { Case }

      Case Signal[3] Of
        1: Inc(Amp,$30);
        3: If _Wave[3] + Rem_Wave[3] <= _Pulse[3] Then
           Begin
             Inc(Amp,$30);
             If _Wave[3] + Rem_Wave[3] <= Smooth
              Then Dec(Amp,Round(Smooth - (_Wave[3] + Rem_Wave[3])))
              Else If _Wave[3] + Rem_Wave[3] > _Pulse[3] - Smooth
                    Then Dec(Amp,Round((_Wave[3] + Rem_Wave[3]) - (_Pulse[3] - Smooth)));
           End;
      End; { Case }
    End
    Else
    Begin
      Case Signal[1] Of
        1: Amp := $20;
        3: If _Wave[1] + Rem_Wave[1] <= _Pulse[1] Then Amp := $20;
      End; { Case }

      Case Signal[2] Of
        1: Inc(Amp,$28);
        3: If _Wave[2] + Rem_Wave[2] <= _Pulse[2] Then Inc(Amp,$28);
      End; { Case }

      Case Signal[3] Of
        1: Inc(Amp,$30);
        3: If _Wave[3] + Rem_Wave[3] <= _Pulse[3] Then Inc(Amp,$30);
      End; { Case }
    End;
    Pf2Buf[I] := Amp;
  End; { For I }
End; { FillPf2Buf }
*)

Procedure FillPf2Buf(Count: LongInt);
Const
  Smooth = 15;
  Fudge  = 1.0;

Var
  I,J       : LongInt;
  Amp       : Byte;
  LenRatio  : Single;
  Changed   : Array[1..3] Of Boolean;
  Mult      : Array[1..3] Of Single;

Begin

  { First see if any Pitfall II sound values have changed for the three }
  { channels.  If anything has changed, the sound parameters have to be }
  { recalculated.  The code below is actually comparing four bytes at a }
  { time, but the fourth byte is always left at zero, so it doesn't     }
  { matter.                                                             }

  For I := 1 To 3 Do
  Begin
    Changed[I] := (WaveLen[I] <> Old_WaveLen[I]) Or
                  (Pulse[I]   <> Old_Pulse[I])   Or
                  (Phase[I]   <> Old_Phase[I])   Or
                  (Signal[I]  <> Old_Signal[I]);
  End; { For I }
(*
  Changed := False;
  Asm
    MOV   EAX,DWORD PTR Old_WaveLen
    CMP   EAX,DWORD PTR WaveLen
    JNE   @L1

    MOV   EAX,DWORD PTR Old_Pulse
    CMP   EAX,DWORD PTR Pulse
    JNE   @L1

    MOV   EAX,DWORD PTR Old_Phase
    CMP   EAX,DWORD PTR Phase
    JNE   @L1

    MOV   EAX,DWORD PTR Old_Signal
    CMP   EAX,DWORD PTR Signal
    JNE   @L1

    JMP   @L2
@L1:
    MOV   BYTE PTR Changed,1
@L2:
  End; { Asm }
  If Changed Then
*)
  If Changed[1] Or Changed[2] Or Changed[3] Then
  Begin

    { The mutipliers below are fudge factors to equalize the ratio between }
    { the Pitfall II's internal sample rate and the normal Atari rate of   }
    { 31.4 kHz.                                                            }

    Mult[1] := 1.75;
    Mult[2] := 1.75;
    Mult[3] := 1.75;

    { Account for the fact that the PC's playback rate (normally 44.1kHz, }
    { but can be otherwise) differs from the Atari's playback rate of     }
    { 31.4kHz.                                                            }

    LenRatio := Playback_Freq / 31400;

    For I := 1 To 3 Do
    Begin
      If Changed[I] Then
      Begin
        _WaveLen[I] := WaveLen[I] * Mult[I] * LenRatio;
        _Pulse[I]   := Pulse[I]   * Mult[I] * LenRatio;
        If _WaveLen[I] > 0 Then
        Begin
          If _Pulse[I] >= _WaveLen[I] Then _Pulse[I] := _Pulse[I] - Trunc(_Pulse[I] / _WaveLen[I]) * _WaveLen[I];
          If _Wave[I]  >= _WaveLen[I] Then _Wave[I]  := _Wave[I]  - Trunc(_Wave[I] / _WaveLen[I])  * _WaveLen[I];
        End
        Else _Wave[I] := 0;
        _Wave[I] := _Wave[I] - 1;
        Rem_Wave[I] := 0;
      End;
    End; { For I }

    Asm
      MOV   EAX,DWORD PTR WaveLen
      MOV   ECX,DWORD PTR Pulse
      MOV   EDX,DWORD PTR Phase

      MOV   DWORD PTR Old_WaveLen,EAX
      MOV   DWORD PTR Old_Pulse,ECX
      MOV   DWORD PTR Old_Phase,EDX

      MOV   EAX,DWORD PTR Signal
      MOV   ECX,DWORD PTR SPWave

      MOV   DWORD PTR Old_Signal,EAX
      MOV   DWORD PTR Old_Wave,ECX
    End; { Asm }
  End;
  For I := 0 To Count - 1 Do
  Begin
    Inc(Pf2Wave);

    For J := 1 To 3 Do
    Begin
      _Wave[J] := _Wave[J] + 1;
      If _Wave[J] + Rem_Wave[J] >= _WaveLen[J] Then
      Begin
        Rem_Wave[J] := _Wave[J] + Rem_Wave[J] - _WaveLen[J];
        _Wave[J]    := 0;
      End;
    End; { For J }

    Amp := 0;

    { DSP to simulate RF modulation and demodulation.  Results in "muddy" sound. }

    If Config.Pitfall2DSP Then
    Begin
      Case Signal[1] Of
        1: Amp := $20;
        3: If _Wave[1] + Rem_Wave[1] <= _Pulse[1] Then
           Begin
             Amp := $20;
             If _Wave[1] + Rem_Wave[1] <= Smooth
              Then Dec(Amp,Round(Smooth - (_Wave[1] + Rem_Wave[1])))
              Else If _Wave[1] + Rem_Wave[1] > _Pulse[1] - Smooth
                    Then Dec(Amp,Round((_Wave[1] + Rem_Wave[1]) - (_Pulse[1] - Smooth)));
           End;
      End; { Case }

      Case Signal[2] Of
        1: Inc(Amp,$28);
        3: If _Wave[2] + Rem_Wave[2] <= _Pulse[2] Then
           Begin
             Inc(Amp,$28);
             If _Wave[2] + Rem_Wave[2] <= Smooth
              Then Dec(Amp,Round(Smooth - (_Wave[2] + Rem_Wave[2])))
              Else If _Wave[2] + Rem_Wave[2] > _Pulse[2] - Smooth
                    Then Dec(Amp,Round((_Wave[2] + Rem_Wave[2]) - (_Pulse[2] - Smooth)));
           End;
      End; { Case }

      Case Signal[3] Of
        1: Inc(Amp,$30);
        3: If _Wave[3] + Rem_Wave[3] <= _Pulse[3] Then
           Begin
             Inc(Amp,$30);
             If _Wave[3] + Rem_Wave[3] <= Smooth
              Then Dec(Amp,Round(Smooth - (_Wave[3] + Rem_Wave[3])))
              Else If _Wave[3] + Rem_Wave[3] > _Pulse[3] - Smooth
                    Then Dec(Amp,Round((_Wave[3] + Rem_Wave[3]) - (_Pulse[3] - Smooth)));
           End;
      End; { Case }
    End
    Else
    Begin
      Case Signal[1] Of
        1: Amp := $20;
        3: If _Wave[1] + Rem_Wave[1] <= _Pulse[1] Then Amp := $20;
      End; { Case }

      Case Signal[2] Of
        1: Inc(Amp,$28);
        3: If _Wave[2] + Rem_Wave[2] <= _Pulse[2] Then Inc(Amp,$28);
      End; { Case }

      Case Signal[3] Of
        1: Inc(Amp,$30);
        3: If _Wave[3] + Rem_Wave[3] <= _Pulse[3] Then Inc(Amp,$30);
      End; { Case }
    End;
    Pf2Buf[I] := Amp;
  End; { For I }
End; { FillPf2Buf }

Procedure QueueSoundSample;
Const FillAmount = 4;
Begin
  Inc(SoundQueue_Num,FillAmount);
  If Game.Cart = ctPitfall2 Then FillPf2Buf(FillAmount);
  ProcessSound(@(SoundQueue[SoundQueue_In]),FillAmount);
  SoundQueue_In := (SoundQueue_In + FillAmount) And 1023;
End; { QueueSoundSample }

Procedure FillBuffer;
Var
  Queued   : Integer;
  Position : Integer;
  WriteCrs : Integer;
  Amount   : Integer;
  I,J,K    : Integer;

Begin
  If Config.DoSound Then
  Begin

    // Get the current buffer position

    frmMain.Secondary.IBuffer.GetCurrentPosition(DWORD(Position),DWORD(WriteCrs));
    Amount := WriteCrs - Position;
    If Amount < 0 Then Inc(Amount,SndBufSize);
    Amount := SndBufSize - Amount;

    If OldPos < 0 Then I := 2048 Else
    Begin
      If (OldPos < Position) And (OldPos < LastWrite) Then J := OldPos + SndBufSize Else J := OldPos;
      If WriteCrs < LastWrite Then K := WriteCrs + SndBufSize Else K := WriteCrs;
      I := WriteCrs - LastWrite;
      If I < 0 Then Inc(I,SndBufSize);

      I := K + I + 384 - J;

      If I < -128 Then I := 2;   // Don't let it get too far ahead
      If I < 0 Then I := 128;    // Introduce some slack
    End;

    If Amount >= I Then
    Begin
      Amount := I;

      // Retrieve from the sound queue first

      Queued := 0;
      While (SoundQueue_Num > 0) And (Queued < Amount) Do
      Begin
        WorkSoundBuf[Queued] := SoundQueue[SoundQueue_Out];
        Inc(Queued);
        SoundQueue_Out := (SoundQueue_Out + 1) And 1023;
        Dec(SoundQueue_Num);
      End; // While

      // Generate any remaining needed sound data

      If Queued < Amount Then ProcessSound(@WorkSoundBuf[Queued],Amount - Queued);

      // Lock the DirectSound buffer

      frmMain.Secondary.Lock(OldPos,Amount,SoundBufPtr,SoundBufSize,SoundBufPtr2,SoundBufSize2,0);

      // Move the data into the buffer

      If Amount > SoundBufSize
       Then I := SoundBufSize
       Else I := Amount;
      Move(WorkSoundBuf[0],SoundBufPtr^,I);
      If Amount > SoundBufSize Then
      Begin
        If Amount - I > SoundBufSize2
         Then J := SoundBufSize2
         Else J := Amount - I;
        Move(WorkSoundBuf[I],SoundBufPtr2^,J);
      End;

      // Unlock the DirectSound buffer

      frmMain.Secondary.Unlock(SoundBufPtr,SoundBufSize,SoundBufPtr2,SoundBufSize2);

      // Save the new position

      OldPos    := (OldPos + Amount) Mod SndBufSize;
      LastWrite := WriteCrs;
    End;
  End;
End; { FillBuffer }
(*
Procedure FillBuffer;
Var
  Queued   : Integer;
  Position : Integer;
  WriteCrs : Integer;
  Amount   : Integer;
  I,J      : Integer;

Begin
  If Config.DoSound Then
  Begin

    // Get the current buffer position

    frmMain.Secondary.IBuffer.GetCurrentPosition(DWORD(Position),DWORD(WriteCrs));
    Amount := Position - WriteCrs;
    If Amount < 0 Then Inc(Amount,SndBufSize);

    // We don't want to update the buffers too often, for speed purposes (the DOS
    // version also updates every 128 bytes)

    If Amount >= 128 Then
    Begin

      // Retrieve from the sound queue first

      Queued := 0;
      While (SoundQueue_Num > 0) And (Queued < Amount) Do
      Begin
        WorkSoundBuf[Queued] := SoundQueue[SoundQueue_Out];
        Inc(Queued);
        SoundQueue_Out := (SoundQueue_Out + 1) And 1023;
        Dec(SoundQueue_Num);
      End; // While

      // Generate any remaining needed sound data

      If Queued < Amount Then ProcessSound(@WorkSoundBuf[Queued],Amount - Queued);

      // Lock the DirectSound buffer

      frmMain.Secondary.Lock(OldPos,Amount,SoundBufPtr,SoundBufSize,SoundBufPtr2,SoundBufSize2,0);

      // Move the data into the buffer

      If Amount > SoundBufSize
       Then I := SoundBufSize
       Else I := Amount;
      Move(WorkSoundBuf[0],SoundBufPtr^,I);
      If Amount > SoundBufSize Then
      Begin
        If Amount - I > SoundBufSize2
         Then J := SoundBufSize2
         Else J := Amount - I;
        Move(WorkSoundBuf[I],SoundBufPtr2^,J);
      End;

      // Unlock the DirectSound buffer

      frmMain.Secondary.Unlock(SoundBufPtr,SoundBufSize,SoundBufPtr2,SoundBufSize2);

      // Save the new position

      OldPos := (OldPos + Amount) Mod SndBufSize;
    End;
  End;
End; { FillBuffer }
*)
(*
Procedure FillBuffer;
Type BPtr = ^Byte;
Var
  Queued   : Word;
  P        : Integer;
  Position : Integer;
  WriteCrs : Integer;
  Amount   : Integer;

Begin
  If Config.DoSound Then
  Begin

    // Get the current buffer position

    frmMain.Secondary.IBuffer.GetCurrentPosition(DWORD(Position),DWORD(WriteCrs));

    WriteCrs := OldPos;

    Amount := Position - WriteCrs;
    If Amount < 0 Then Inc(Amount,SndBufSize);

    // We don't want to update the buffers too often, for speed purposes (the DOS
    // version also updates every 128 bytes)

    If Amount >= 128 Then
    Begin

      // Lock the DirectSound buffer

      frmMain.Secondary.Lock(WriteCrs,Amount,SoundBufPtr,SoundBufSize,SoundBufPtr2,SoundBufSize2,0);

      // Retrieve from the sound queue first

      Queued := 0;
      P      := 0;
      While (SoundQueue_Num > 0) And (Queued < Amount) Do
      Begin
        If P < SoundBufSize
         Then BPtr(LongInt(SoundBufPtr)  + P)^                := SoundQueue[SoundQueue_Out]
         Else BPtr(LongInt(SoundBufPtr2) + P - SoundBufSize)^ := SoundQueue[SoundQueue_Out];
        Inc(P);
        Inc(Queued);
        SoundQueue_Out := (SoundQueue_Out + 1) And 1023;
        Dec(SoundQueue_Num);
      End; { While }

      // Generate any remaining needed sound data

      If Queued < Amount Then
      Begin
        If Game.Cart = ctPitfall2 Then FillPf2Buf(Amount - Queued);
        If P < SoundBufSize Then
        Begin
          If SoundBufSize2 > 0
           Then ProcessSound(Pointer(LongInt(SoundBufPtr) + P),SoundBufSize - Queued)
           Else ProcessSound(Pointer(LongInt(SoundBufPtr) + P),Amount - Queued);
        End;
        If SoundBufSize2 > 0 Then
        Begin
          If P >= SoundBufSize
           Then ProcessSound(Pointer(LongInt(SoundBufPtr2) + P - SoundBufSize),SoundBufSize2 - (P - SoundBufSize))
           Else ProcessSound(Pointer(LongInt(SoundBufPtr2)),SoundBufSize2);
        End;
      End;

      // Unlock the DirectSound buffer

      frmMain.Secondary.Unlock(SoundBufPtr,SoundBufSize,SoundBufPtr2,SoundBufSize2);

      // Save the new position

      OldPos := Position;
    End;
  End;
End; { FillBuffer }
*)
Procedure SetVoice(Chan,Voc: Word); Pascal;
Begin
  If Config.DoSound Then
  Begin
    Game.FMVoc[Chan] := Voc And $F;
    If AUDC[Chan] <> Game.FMVoc[Chan] Then
    Begin
      Update_TIA_Sound(AUDC0 + Chan,Game.FMVoc[Chan]);
    End;
  End;
End; { SetVoice }

Procedure SetFrequency(Chan,Freq: Word); Pascal;
Begin
  If Config.DoSound Then
  Begin
    Game.FMFreq[Chan] := Freq And $1F;
    If AUDF[Chan] <> Game.FMFreq[Chan] Then
    Begin
      Update_TIA_Sound(AUDF0 + Chan,Game.FMFreq[Chan]);
    End;
  End;
End; { SetFrequency }

Procedure SetVolume(Chan,Scale: Word); Pascal;
Begin
  If Config.DoSound Then
  Begin
    Game.FMRealScale[Chan] := Scale And $F;
    If (AUDV[Chan] Shr 3) <> Game.FMRealScale[Chan] Then
    Begin
      Update_TIA_Sound(AUDV0 + Chan,Game.FMRealScale[Chan]);
    End;
  End;
End; { SetVolume }

Procedure ResetClock;
Begin
  Time0            := GetTickCount;
  frmMain.BaseTime := Trunc(Time0);
  frmMain.Frames   := 0;
  frmMain.FPS      := 0;
End; { ResetClock }

Function CreateFile(Var F: File; St: String): Boolean;
Var
  Error    : Boolean;
  Continue : Boolean;

Begin
  Error   := False;
  If St = '' Then Error := True;

  Continue := True;
  If (Not Error) And FileExists(St) Then
  Begin
    Continue := (Application.MessageBox('File already exists. Overwrite?','Warning',
     MB_YESNO + MB_ICONQUESTION) = IDYES);
  End;
  If Error Then Continue := False;

  If Continue Then
  Begin
    Assign(F,St);
    {$I-}
    ReWrite(F,1);
    {$I+}
    If IOResult <> 0 Then Error := True;
    If Error Then
    Begin
      If St <> '' Then
      Begin
        ShowMessage('Error creating file.');
      End;
      CreateFile := False;
    End
    Else CreateFile := True;
  End
  Else CreateFile := False;
End; { CreateFile }

Function CanOpenFile(Width,Height: Word; St: String): Boolean;
Var Error: Boolean;
Begin
  Error   := False;
  If St = '' Then Error := True;
  If Not FileExists(St) Then Error := True;
  If Error Then
  Begin
    If St <> '' Then ShowMessage('Error opeing file.');
    CanOpenFile := False;
  End
  Else CanOpenFile := True;
End; { CanOpenFile }

Procedure TfrmMain.SaveStatus;
Var
  F     : File;
  Save  : TSave;
  St    : String;

Begin
  dlgSave.Filter := '';
  If dlgSave.Execute Then
  Begin
    St := dlgSave.FileName;
    If St <> '' Then
    Begin
      If CreateFile(F,St) Then
      Begin
        Move(Game,Save,SizeOf(Game));

      { --------------------- From SPUnit ------------------------ }

        Save.SPBank              := SPBank;
        Save.SPSearch            := SPSearch;
        Save.SPBoot              := SPBoot;

        Move(WaveLen,Save.WaveLen,SizeOf(WaveLen));
        Move(Pulse,Save.Pulse,SizeOf(Pulse));
        Move(Phase,Save.Phase,SizeOf(Phase));
        Move(Signal,Save.Signal,SizeOf(Signal));
        Move(SPWave,Save.Wave,SizeOf(SPWave));

        BlockWrite(F,Save,SizeOf(Save));
        BlockWrite(F,AtariSeg,SizeOf(AtariSeg));
        If Game.Cart = ctMNetwork
         Then BlockWrite(F,ROMBackup,Game.ROMSize + 2048)
         Else BlockWrite(F,ROMBackup,Game.ROMSize);
        SaveSPP2Status(F);
        CloseFile(F);
      End;
    End;
  End;
  ResetClock;
End; { TfrmMain.SaveStatus }

Procedure TfrmMain.RestoreStatus;
Var
  F     : File;
  Save  : TSave;
  St    : String;

Begin
  If dlgOpen.Execute Then
  Begin
    St := dlgOpen.FileName;
    If St <> '' Then
    Begin
      If CanOpenFile(Config.MaxCols,Game.MaxRows,St) Then
      Begin
        AssignFile(F,St);
        Reset(F,1);
        BlockRead(F,Save,SizeOf(Save));
        BlockRead(F,AtariSeg,SizeOf(AtariSeg));
        If Save.Cart = ctMNetwork
         Then BlockRead(F,ROMBackup,Save.ROMSize + 2048)
         Else BlockRead(F,ROMBackup,Save.ROMSize);
        RestoreSPP2Status(F);
        CloseFile(F);

        Move(Save,Game,SizeOf(Game));

      { --------------------- From SPUnit ------------------------ }

        SPBank              := Save.SPBank;
        SPSearch            := Save.SPSearch;
        SPBoot              := Save.SPBoot;

        Move(Save.WaveLen,WaveLen,SizeOf(WaveLen));
        Move(Save.Pulse,Pulse,SizeOf(Pulse));
        Move(Save.Phase,Phase,SizeOf(Phase));
        Move(Save.Signal,Signal,SizeOf(Signal));
        Move(Save.Wave,SPWave,SizeOf(SPWave));

        If Config.DoSound Then
        Begin
          SetVolume(0,Game.FMRealScale[0]);
          SetFrequency(0,Game.FMFreq[0]);
          SetVoice(0,Game.FMVoc[0]);
          SetVolume(1,Game.FMRealScale[1]);
          SetFrequency(1,Game.FMFreq[1]);
          SetVoice(1,Game.FMVoc[1]);
        End;
      End;
    End;
  End;
  ResetClock;
End; { TfrmMain.RestoreStatus }

Procedure CheckCMKeyboard;
Begin
  Asm
    PUSHAD
    MOV   WORD PTR CMInputLatch,08080h
    MOV   DWORD PTR CMPorts[0],00808000h
    MOV   AL,BYTE PTR AtariSeg[SWCHA1]
    OR    AL,0Ch
    AND   AL,7Fh
    MOV   BL,BYTE PTR Keys[DIK_LSHIFT]
    OR    BL,BYTE PTR Keys[DIK_RSHIFT]
    TEST  BL,0FFh
    JZ    @CMnoShift
    MOV   BYTE PTR CMPorts[3],80h
  @CMnoShift:
    MOV   BL,BYTE PTR Keys[DIK_LCONTROL]
    OR    BL,BYTE PTR Keys[DIK_RCONTROL]
    TEST  BL,0FFh
    JZ    @CMNoFunc
    MOV   BYTE PTR CMPorts[0],80h
  @CMnoFunc:
  @CM00:
    CMP   BYTE PTR CMColumn,0
    JNE   @CM10
    TEST  BYTE PTR Keys[DIK_7],0FFh
    JZ    @CM01
    MOV   BYTE PTR CMInputLatch[0],0
  @CM01:
    TEST  BYTE PTR Keys[DIK_U],0FFh
    JZ    @CM02
    AND   AL,0FBh
  @CM02:
    TEST  BYTE PTR Keys[DIK_J],0FFh
    JZ    @CM03
    MOV   BYTE PTR CMInputLatch[1],0
  @CM03:
    TEST  BYTE PTR Keys[DIK_M],0FFh
    JZ    @CM10
    AND   AL,0F7h
    JMP   @CMend
  @CM10:
    CMP   BYTE PTR CMColumn,1
    JNE   @CM20
    TEST  BYTE PTR Keys[DIK_6],0FFh
    JZ    @CM11
    MOV   BYTE PTR CMInputLatch[0],0
  @CM11:
    TEST  BYTE PTR Keys[DIK_Y],0FFh
    JZ    @CM12
    AND   AL,0FBh
  @CM12:
    TEST  BYTE PTR Keys[DIK_H],0FFh
    JZ    @CM13
    MOV   BYTE PTR CMInputLatch[1],0
  @CM13:
    TEST  BYTE PTR Keys[DIK_N],0FFh
    JZ    @CM20
    AND   AL,0F7h
    JMP   @CMend
  @CM20:
    CMP   BYTE PTR CMColumn,2
    JNE   @CM30
    TEST  BYTE PTR Keys[DIK_8],0FFh
    JZ    @CM21
    MOV   BYTE PTR CMInputLatch[0],0
  @CM21:
    TEST  BYTE PTR Keys[DIK_I],0FFh
    JZ    @CM22
    AND   AL,0FBh
  @CM22:
    TEST  BYTE PTR Keys[DIK_K],0FFh
    JZ    @CM23
    MOV   BYTE PTR CMInputLatch[1],0
  @CM23:
    TEST  BYTE PTR Keys[DIK_COMMA],0FFh
    JZ    @CM30
    AND   AL,0F7h
    JMP   @CMend
  @CM30:
    CMP   BYTE PTR CMColumn,3
    JNE   @CM40
    TEST  BYTE PTR Keys[DIK_2],0FFh
    JZ    @CM31
    MOV   BYTE PTR CMInputLatch[0],0
  @CM31:
    TEST  BYTE PTR Keys[DIK_W],0FFh
    JZ    @CM32
    AND   AL,0FBh
  @CM32:
    TEST  BYTE PTR Keys[DIK_S],0FFh
    JZ    @CM33
    MOV   BYTE PTR CMInputLatch[1],0
  @CM33:
    TEST  BYTE PTR Keys[DIK_X],0FFh
    JZ    @CM40
    AND   AL,0F7h
    JMP   @CMend
  @CM40:
    CMP   BYTE PTR CMColumn,4
    JNE   @CM50
    TEST  BYTE PTR Keys[DIK_3],0FFh
    JZ    @CM41
    MOV   BYTE PTR CMInputLatch[0],0
  @CM41:
    TEST  BYTE PTR Keys[DIK_E],0FFh
    JZ    @CM42
    AND   AL,0FBh
  @CM42:
    TEST  BYTE PTR Keys[DIK_D],0FFh
    JZ    @CM43
    MOV   BYTE PTR CMInputLatch[1],0
  @CM43:
    TEST  BYTE PTR Keys[DIK_C],0FFh
    JZ    @CM50
    AND   AL,0F7h
    JMP   @CMend
  @CM50:
    CMP   BYTE PTR CMColumn,5
    JNE   @CM60
    TEST  BYTE PTR Keys[DIK_0],0FFh
    JZ    @CM51
    MOV   BYTE PTR CMInputLatch[0],0
  @CM51:
    TEST  BYTE PTR Keys[DIK_P],0FFh
    JZ    @CM52
    AND   AL,0FBh
  @CM52:
    TEST  BYTE PTR Keys[DIK_COLON],0FFh
    JZ    @CM53
    MOV   BYTE PTR CMInputLatch[1],0
  @CM53:
    TEST  BYTE PTR Keys[DIK_SLASH],0FFh
    JZ    @CM60
    AND   AL,0F7h
    JMP   @CMend
  @CM60:
    CMP   BYTE PTR CMColumn,6
    JNE   @CM70
    TEST  BYTE PTR Keys[DIK_9],0FFh
    JZ    @CM61
    MOV   BYTE PTR CMInputLatch[0],0
  @CM61:
    TEST  BYTE PTR Keys[DIK_O],0FFh
    JZ    @CM62
    AND   AL,0FBh
  @CM62:
    TEST  BYTE PTR Keys[DIK_L],0FFh
    JZ    @CM63
    MOV   BYTE PTR CMInputLatch[1],0
  @CM63:
    TEST  BYTE PTR Keys[DIK_PERIOD],0FFh
    JZ    @CM70
    AND   AL,0F7h
    JMP   @CMend
  @CM70:
    CMP   BYTE PTR CMColumn,7
    JNE   @CM80
    TEST  BYTE PTR Keys[DIK_5],0FFh
    JZ    @CM71
    MOV   BYTE PTR CMInputLatch[0],0
  @CM71:
    TEST  BYTE PTR Keys[DIK_T],0FFh
    JZ    @CM72
    AND   AL,0FBh
  @CM72:
    TEST  BYTE PTR Keys[DIK_G],0FFh
    JZ    @CM73
    MOV   BYTE PTR CMInputLatch[1],0
  @CM73:
    TEST  BYTE PTR Keys[DIK_B],0FFh
    JZ    @CM80
    AND   AL,0F7h
    JMP   @CMend
  @CM80:
    CMP   BYTE PTR CMColumn,8
    JNE   @CM90
    TEST  BYTE PTR Keys[DIK_1],0FFh
    JZ    @CM81
    MOV   BYTE PTR CMInputLatch[0],0
  @CM81:
    TEST  BYTE PTR Keys[DIK_Q],0FFh
    JZ    @CM82
    AND   AL,0FBh
  @CM82:
    TEST  BYTE PTR Keys[DIK_A],0FFh
    JZ    @CM83
    MOV   BYTE PTR CMInputLatch[1],0
  @CM83:
    TEST  BYTE PTR Keys[DIK_Z],0FFh
    JZ    @CM90
    AND   AL,0F7h
    JMP   @CMend
  @CM90:
    CMP   BYTE PTR CMColumn,9
    JNE   @CMend
    TEST  BYTE PTR Keys[DIK_4],0FFh
    JZ    @CM91
    MOV   BYTE PTR CMInputLatch[0],0
  @CM91:
    TEST  BYTE PTR Keys[DIK_R],0FFh
    JZ    @CM92
    AND   AL,0FBh
  @CM92:
    TEST  BYTE PTR Keys[DIK_F],0FFh
    JZ    @CM93
    MOV   BYTE PTR CMInputLatch[1],0
  @CM93:
    TEST  BYTE PTR Keys[DIK_V],0FFh
    JZ    @CMend
    AND   AL,0F7h
  @CMend:
    MOV   BYTE PTR AtariSeg[SWCHA1],AL
    POPAD
  End;
  Game.Input_Byte[INPUT0] := CMPorts[0];
  Game.Input_Byte[INPUT1] := CMPorts[1];
  Game.Input_Byte[INPUT2] := CMPorts[2];
  Game.Input_Byte[INPUT3] := CMPorts[3];
  Game.Input_Byte[INPUT4] := CMInputLatch[0];
  Game.Input_Byte[INPUT5] := CMInputLatch[1];
End; { CheckCMKeyboard }

Procedure SwitchBank; Assembler;
Asm
  PUSHAD
  PUSH  ESI

  MOV   BYTE PTR DebugLoad,0

  { Save the current bank to simulate RAM if necessary }

  CMP   BYTE PTR Game.Cart,ctMNetwork
  JNE   @NoCopyBack

  CMP   BYTE PTR Game.BankSwitch[EBX],0DCh
  JAE   @NoCopyBack
  CMP   BYTE PTR Game.BankSwitch[EBX],0D8h
  JAE   @CopyBack256
  CMP   BYTE PTR Game.CurrentBank,7
  JNE   @NoCopyBack

  MOV   ESI,1000h
  MOV   ECX,256
  MOV   EAX,4000h

  JMP   @NotCopying256

@CopyBack256:
  MOV   ECX,64
  SUB   EAX,EAX
  MOV   AH,BYTE PTR Game.MNetworkRAM
  SUB   AH,8
  SUB   AL,AL
  ADD   EAX,4400h
  MOV   ESI,1800h
  ADD   ESI,OFFSET AtariSeg
@NotCopying256:
  MOV   EDI,OFFSET ROMBackup
  ADD   EDI,EAX
  CLD
  REP   MOVSD
  JMP   @NoCopyBack

@NoCopyBack:

  { Find out which bank we're switching to }

  MOV   DL,CL                             { Save accumulator }
  MOV   ECX,EAX                           { Save X and Y }
  MOV   WORD PTR Game.BankStart,1000h
  MOV   AL,BYTE PTR Game.BankSwitch[EBX]
  CMP   AL,29
  JBE   @OneToFour

  { 30/31 means toggle between banks 1 and 2 }

  CMP   AL,0E0h
  JAE   @ParkerBros

  CMP   AL,0D0h
  JAE   @MNetwork

  CMP   AL,0CBh
  JAE   @Pitfall2

  CMP   AL,0A0h
  JAE   @Compumate

  CMP   AL,90h
  JAE   @CommaVid

  CMP   AL,80h
  JAE   @MegaBoy

  CMP   AL,070h
  JAE   @Starpath

  CMP   AL,060h
  JE    @TigerVision

  CMP   AL,040h
  JAE   @SuperChip
  CMP   AL,20h
  JAE   @CBS

  XOR   BYTE PTR Game.BankSwitch[EBX],1
  SUB   AL,30
  SHL   AL,2
  XOR   AL,4

  INC   AL
  JMP   @OneToFour

  { Handle Compumate }

@Compumate:
  CMP   AL,0A0h
  JE    @CMSwitch
  TEST  BYTE PTR CMRAMState,10h
  JZ    @CMRAM
  MOVZX ESI,WORD PTR CMROMBank
  MOV   AL,BYTE PTR ROMBackup[EBX + ESI - 1000h]
  MOV   BYTE PTR AtariSeg[EBX],AL
  JMP   @LocalGetOut
@CMRAM:
  TEST  BYTE PTR CMRAMState,20h
  JZ    @NoCMWrite
  MOV   AL,BYTE PTR AtariSeg[EBX]
  MOV   BYTE PTR CMRAM[EBX - 1800h],AL
@NoCMWrite:
  MOV   AL,BYTE PTR CMRAM[EBX - 1800h]
  MOV   BYTE PTR AtariSeg[EBX],AL
  JMP   @LocalGetOut

  { Handle Compumate bankswitching }

@CMSwitch:
  TEST  BYTE PTR WriteOp,0FFh
  JZ    @LocalGetOut

  MOV   AL,BYTE PTR AtariSeg[SWCHA1]
  MOV   AH,BYTE PTR CMSWCHA
  MOV   CL,BYTE PTR AtariSeg[SWACNT1]
  MOV   CH,CL
  NOT   CL

  AND   AH,CL
  AND   AL,CH
  OR    AL,AH

  MOV   BYTE PTR AtariSeg[SWCHA1],AL
  MOV   BYTE PTR CMSWCHA,AL
  TEST  AL,20h
  JZ    @NoResetKeyCount
  MOV   BYTE PTR CMColumn,0
@NoResetKeyCount:
  TEST  AL,40h
  JZ    @NoIncreaseKeyCount
  INC   BYTE PTR CMColumn
  CMP   BYTE PTR CMColumn,10
  JNE   @NoIncreaseKeyCount
  MOV   BYTE PTR CMColumn,0
@NoIncreaseKeyCount:
  MOV   BYTE PTR CMRAMState,AL
  AND   EAX,3
  SHL   EAX,12
  MOV   WORD PTR CMROMBank,AX

  { Copy in the ROM area }

  MOV   ESI,OFFSET ROMBackup
  ADD   ESI,EAX
  MOV   ECX,400h
  TEST  BYTE PTR CMRAMState,10h
  JNZ   @NoCMRAM
  SHR   ECX,1
@NoCMRAM:
  MOV   EDI,1000h
  ADD   EDI,OFFSET AtariSeg
  CLD
  REP   MOVSD

  { Copy in the RAM area, if it is enabled }

  TEST  BYTE PTR CMRAMState,10h
  JNZ   @NoCMRAM2
  MOV   ECX,200h
  MOV   ESI,OFFSET CMRAM
  REP   MOVSD
@NoCMRAM2:
  MOV   BYTE PTR DebugLoad,1
  MOV   BYTE PTR WriteOp,0
  CALL  CheckCMKeyboard
  JMP   @LocalGetOut

  { Handle 32-in-1 MegaBoy }

@MegaBoy:
  INC   BYTE PTR Game.MegaBoyNum
  AND   BYTE PTR Game.MegaBoyNum,0Fh
  CMP   BYTE PTR Game.MegaBoyNum,0Fh
  JNE   @NotMBLast
  MOV   ECX,3FCh
  MOV   EDI,1000h
  ADD   EDI,OFFSET AtariSeg
  CLD
  SUB   EAX,EAX
  MOV   AL,BYTE PTR Game.MegaBoyNum
  SHL   EAX,12
  MOV   ESI,OFFSET ROMBackup
  ADD   ESI,EAX
  REP   MOVSD
  MOV   ESI,OFFSET Game.MegaBoy
  MOV   ECX,4
  REP   MOVSD

  JMP   @LocalGetOut
@NotMBLast:
  MOV   ECX,400h
  MOV   EDI,1000h
  ADD   EDI,OFFSET AtariSeg
  CLD
  SUB   EAX,EAX
  MOV   AL,BYTE PTR Game.MegaBoyNum
  SHL   EAX,12
  MOV   ESI,OFFSET ROMBackup
  ADD   ESI,EAX
  REP   MOVSD
  JMP   @LocalGetOut

  { Handle Starpath Supercharger }

@Starpath:
{
  SUB   EDI,OFFSET AtariSeg
  PUSH  EDI
  ADD   EDI,OFFSET AtariSeg

  PUSH  EBX
}
{
  PUSH  DWORD PTR Game.TIA_Count
  PUSH  DWORD PTR Game.TIA_Scan
}

  PUSH  EBX
  TEST  BYTE PTR Debugger,0FFh
  JZ    @NoDebugA1
  MOVZX EBX,WORD PTR Game.OldStart
  CMP   EBX,1000h
  JL    @NoDebugA1
  MOV   CL,BYTE PTR Game.OldByte
  MOV   BYTE PTR AtariSeg[EBX],CL
@NoDebugA1:
  POP   EBX

  PUSHAD
  MOV   EAX,EDI
  SUB   EAX,OFFSET AtariSeg
  MOV   EDX,EBX

  CALL  HandleStarpath

  POPAD


  MOV   CL,BYTE PTR SPBank

  MOV   BYTE PTR Game.SPBankNum,CL

  TEST  BYTE PTR Debugger,0FFh
  JZ    @NoDebugA

  MOVZX EBX,WORD PTR Game.OldStart
  CMP   EBX,1000h
  JL    @NoDebugA
  MOV   CL,BYTE PTR AtariSeg[EBX]
  MOV   BYTE PTR Game.OldByte,CL
  MOV   BYTE PTR AtariSeg[EBX],BreakInstruction
@NoDebugA:
  POP   ESI
  JMP   @NoDebug

  { Handle TigerVision games }

@TigerVision:
  MOV   AL,BYTE PTR AtariSeg[003Fh]
  CMP   AL,BYTE PTR Game.TigerLimit
  JBE   @TigerLimitOk
  MOV   AL,BYTE PTR Game.TigerLimit
@TigerLimitOk:
  MOV   BYTE PTR Game.CurrentBank,AL
  AND   EAX,0FFh
  SHL   EAX,11
  MOV   EDI,1000h
  ADD   EDI,OFFSET AtariSeg
  MOV   ECX,512
  MOV   BYTE PTR DebugLoad,1
  MOV   ESI,OFFSET ROMBackup
  ADD   ESI,EAX
  CLD
  REP   MOVSD
  JMP   @LocalGetOut

  { Handle Pitfall II }

@Pitfall2:

  CMP   AL,0CDh
  JB    @PF2Copy

  PUSHAD

  AND   EAX,0FFh
  AND   EDX,0FFh

  PUSH  EAX
  PUSH  EBX
  PUSH  ECX
  PUSH  EDX
  SUB   EDI,OFFSET AtariSeg
  PUSH  EDI
  CALL  HandlePitfall2

  POPAD

  POP   ESI
  JMP   @NoDebug
@PF2Copy:

  MOV   ESI,80h
  CMP   AL,0CCh
  JNE   @PF2C1
  MOV   ESI,1080h
@PF2C1:
  MOV   EDI,1080h
  ADD   EDI,OFFSET AtariSeg
  MOV   ECX,1E0h
  ADD   ESI,OFFSET ROMBackup
  CLD
  REP   MOVSD
  ADD   ESI,80h
  ADD   EDI,80h
  MOV   ECX,1E0h
  REP   MOVSD

  MOV   BYTE PTR DebugLoad,1
  JMP   @LocalGetOut
  POP   ESI
  JMP   @NoDebug

  // Handle CommaVid RAM cart

@CommaVid:

  { Copy RAM write area to the read area }

  MOV   AL,BYTE PTR AtariSeg[EBX]
  MOV   BYTE PTR AtariSeg[EBX - 400h],AL
  JMP   @LocalGetOut

  { Handle 16K Atari super chip }

@SuperChip:

  CMP   AL,5Fh
  JB    @SwitchSC

  { Copy RAM write area to the read area }

  MOV   AL,BYTE PTR AtariSeg[EBX]
  MOV   BYTE PTR AtariSeg[EBX + 80h],AL
  JMP   @LocalGetOut

  { Switch the bank, but don't copy over the RAM area }

@SwitchSC:
  SUB   AL,040h
  MOV   BYTE PTR Game.CurrentBank,AL
  AND   EAX,0FFh
  SHL   EAX,12
  MOVZX EDI,WORD PTR Game.BankStart
  ADD   EDI,(OFFSET AtariSeg)+100h
  MOVZX ECX,WORD PTR Game.BankSize
  MOV   BYTE PTR DebugLoad,1
  MOV   ESI,(OFFSET ROMBackup)+100h
  ADD   ESI,EAX
  CLD
  REP   MOVSD
  JMP   @LocalGetOut

  { Handle Parker Brothers special bank switching }

@ParkerBros:
  SUB   AL,0E0h
  MOV   BL,AL
  AND   AL,7
  INC   AL
  AND   EBX,18h
  SHL   EBX,7
  ADD   EBX,1000h
  MOV   WORD PTR Game.BankStart,BX
  JMP   @OneToFour

  { Handle M-Network bank switching }

@MNetwork:
  SUB   AL,0D0h
  CMP   AL,0Ch
  JAE   @NoSaveBankNum
  MOV   BYTE PTR Game.CurrentBank,AL
@NoSaveBankNum:

  CMP   AL,7
  JB    @LoadROM
  CMP   AL,0Ch
  JNE   @Not1kWrite
  CMP   BYTE PTR Game.CurrentBank,7
  JNE   @LocalGetOut
  MOV   AL,BYTE PTR AtariSeg[EBX]
  MOV   BYTE PTR AtariSeg[EBX + 1024],AL
  JMP   @LocalGetOut
@Not1kWrite:
  CMP   AL,0Dh
  JNE   @Not256Write
  MOV   AL,BYTE PTR AtariSeg[EBX]
  MOV   BYTE PTR AtariSeg[EBX + 256],AL
  JMP   @LocalGetOut
@Not256Write:
  MOV   ECX,256
  MOV   EDX,4000h
  MOV   EDI,1000h
  CMP   AL,8
  JB    @Not256
  MOV   BYTE PTR Game.MNetworkRAM,AL
  SHR   ECX,2
  MOV   DH,AL
  SUB   DH,8
  SUB   DL,DL
  ADD   EDX,4400h
  MOV   EDI,1800h
@Not256:
  ADD   EDI,OFFSET AtariSeg

  { Load a 1k/256-byte RAM bank }

  MOV   ESI,OFFSET ROMBackup
  ADD   ESI,EDX
  CLD
  PUSH  ESI
  PUSH  ECX
  REP   MOVSD
  POP   ECX
  POP   ESI
  REP   MOVSD
  JMP   @LocalGetOut
@LoadROM:
  AND   EAX,0FFh
  SHL   EAX,11
  MOV   EDI,1000h
  ADD   EDI,OFFSET AtariSeg
  MOV   ECX,512
  MOV   BYTE PTR DebugLoad,1
  MOV   ESI,OFFSET ROMBackup
  ADD   ESI,EAX
  CLD
  REP   MOVSD
  JMP   @LocalGetOut

  { Handle CBS RAM-Plus bank switching }

@CBS:
  CMP   AL,30h
  JB    @Switch

  { Copy RAM write area to the read area }

  MOV   AL,BYTE PTR AtariSeg[EBX]
  MOV   BYTE PTR AtariSeg[EBX + 100h],AL
  JMP   @LocalGetOut

  { Switch the bank, but don't copy over the RAM area }

@Switch:
  SUB   AL,020h
  DEC   AL
  MOV   BYTE PTR Game.CurrentBank,AL
  AND   EAX,0FFh
  SHL   EAX,10
  MOVZX EDI,WORD PTR Game.BankStart
  ADD   EDI,200h
  ADD   EDI,OFFSET AtariSeg
  MOVZX ECX,WORD PTR Game.BankSize
  MOV   BYTE PTR DebugLoad,1
  MOV   ESI,OFFSET ROMBackup
  ADD   ESI,EAX
  ADD   ESI,200h
  CLD
  REP   MOVSD
  JMP   @LocalGetOut

  { Copy in the new bank }

@OneToFour:
  DEC   AL
  MOV   BYTE PTR Game.CurrentBank,AL
  AND   EAX,0FFh
  SHL   EAX,10
  MOVZX EDI,WORD PTR Game.BankStart
  ADD   EDI,OFFSET AtariSeg
  MOVZX ECX,WORD PTR Game.BankSize

  CMP   BYTE PTR Game.Cart,ctPitfall2
  JNE   @NotP2
  MOV   ECX,01E0h
  ADD   EAX,80h
  ADD   EDI,80h

  MOV   BYTE PTR DebugLoad,1
  MOV   ESI,OFFSET ROMBackup
  ADD   ESI,EAX
  CLD
  REP   MOVSD

  MOV   ECX,01E0h
  ADD   EDI,80h
  ADD   EAX,800h

  MOV   ESI,OFFSET ROMBackup
  ADD   ESI,EAX
  CLD
  REP   MOVSD

  JMP   @LocalGetOut
@NotP2:
  MOV   BYTE PTR DebugLoad,1
  MOV   ESI,OFFSET ROMBackup
  ADD   ESI,EAX
  CLD
  REP   MOVSD
@LocalGetOut:
  POP   ESI
  TEST  BYTE PTR Debugger,0FFh
  JZ    @NoDebug
  MOVZX EBX,WORD PTR Game.OldStart
  CMP   EBX,1000h
  JL    @NoDebug
  CMP   BYTE PTR Game.Cart,ctTigerVision
  JNE   @CheckMNetwork
  CMP   EBX,1800h
  JAE   @NoDebug
  JMP   @DoDebug
@CheckMNetwork:
  CMP   BYTE PTR Game.Cart,ctMNetwork
  JNE   @CheckParkerBros
  CMP   EBX,1800h
  JAE   @NoDebug
@CheckParkerBros:
  CMP   BYTE PTR Game.Cart,ctParkerBros
  JNE   @DoDebug
  CMP   BX,WORD PTR Game.BankStart
  JL    @NoDebug
  MOVZX EAX,WORD PTR Game.BankStart
  ADD   EAX,1024
  CMP   EBX,EAX
  JGE   @NoDebug
@DoDebug:
  TEST  BYTE PTR DebugLoad,0FFh
  JZ    @NoDebug
  MOV   AL,BYTE PTR AtariSeg[EBX]
  MOV   BYTE PTR Game.OldByte,AL
  MOV   BYTE PTR AtariSeg[EBX],BreakInstruction
@NoDebug:
  POPAD
End; { SwitchBank }

Procedure CheckKBController; Assembler;
Asm
  PUSHAD
  CMP   BYTE PTR Game.Controller,crKeyboard
  JE    @CheckKB
  CMP   BYTE PTR Game.Controller,crVTP
  JE    @CheckKB
  JMP   @LocalGetOut
@CheckKB:

  MOV   BL,BYTE PTR AtariSeg[SWCHA1]
  MOV   EAX,1001h
  MOV   ECX,4
  MOV   BH,BYTE PTR AtariSeg[VBLANK]
@KeyLoop1:
  TEST  BL,AL
  JNZ   @NoTest

  CMP   BYTE PTR Game.Controller,crVTP
  JE    @Row4

  TEST  BYTE PTR Game.KeyColumn[0],AH
  JZ    @Off1
  TEST  BH,80h
  JNZ   @Off1
  AND   BYTE PTR Game.Input_Byte[INPUT0],7Fh
  JMP   @Row2
@Off1:
  OR    BYTE PTR Game.Input_Byte[INPUT0],80h
@Row2:

  TEST  BYTE PTR Game.KeyColumn[1],AH
  JZ    @Off2
  TEST  BH,80h
  JNZ   @Off2
  AND   BYTE PTR Game.Input_Byte[INPUT1],7Fh
  JMP   @Row3
@Off2:
  OR    BYTE PTR Game.Input_Byte[INPUT1],80h
@Row3:

  TEST  BYTE PTR Game.KeyColumn[2],AH
  JZ    @Off3
  AND   BYTE PTR Game.Input_Byte[INPUT4],7Fh
  JMP   @Row4
@Off3:
  OR    BYTE PTR Game.Input_Byte[INPUT4],80h
@Row4:

  TEST  BYTE PTR Game.KeyColumn[0],AL
  JZ    @Off4
  TEST  BH,80h
  JNZ   @Off4
  AND   BYTE PTR Game.Input_Byte[INPUT2],7Fh
  JMP   @Row5
@Off4:
  OR    BYTE PTR Game.Input_Byte[INPUT2],80h
@Row5:

  TEST  BYTE PTR Game.KeyColumn[1],AL
  JZ    @Off5
  TEST  BH,80h
  JNZ   @Off5
  AND   BYTE PTR Game.Input_Byte[INPUT3],7Fh
  JMP   @Row6
@Off5:
  OR    BYTE PTR Game.Input_Byte[INPUT3],80h
@Row6:

  TEST  BYTE PTR Game.KeyColumn[2],AL
  JZ    @Off6
  AND   BYTE PTR Game.Input_Byte[INPUT5],7Fh
  JMP   @NoTest
@Off6:
  OR    BYTE PTR Game.Input_Byte[INPUT5],80h

@NoTest:
  ADD    AL,AL
  ADD    AH,AH
  DEC    ECX
  JNZ    @KeyLoop1
@LocalGetOut:
  POPAD
End; { CheckKBController }

Procedure Handle_Timer; Assembler;
Asm
  PUSHAD
  MOV    EAX,DWORD PTR Game.TimerElapsed  { EAX = # of elapsed clock cycles }
  SUB    EBX,EBX
  ADD    EAX,DWORD PTR Game.TimerX
  MOV    EBX,68                           { Include this instruction }
  ADD    BX,WORD PTR Game.TIA_Count
  MOVZX  EBX,BYTE PTR Div3[EBX]
  ADD    EBX,DWORD PTR Game.AddCycle
  ADD    EAX,EBX

 { ------------------------ }

  MOV    ECX,DWORD PTR Game.TimerShift
  MOV    EDX,EAX

  MOV    EBX,DWORD PTR Game.OrigTimer
  SHL    EBX,CL
  SUB    EBX,EDX
  JS     @Depleted
  SAR    EBX,CL
  MOV    BYTE PTR AtariSeg[INTTIM1],BL
  MOV    BYTE PTR AtariSeg[INTTIM2],BL
  MOV    BYTE PTR AtariSeg[INTTIM3],0
  JMP    @LocalGetOut
@Depleted:
  MOV    BYTE PTR AtariSeg[INTTIM3],80h
@NoTimerInterrupt:
  SAR    EBX,CL

  { If we're at s/l. MaxScan and the timer has been depleted, then  }
  { the emulator must have not been able to resolve the timer.  Set }
  { the timer to make sure that zero is periodically returned when  }
  { the timer is depleted.                                          }

  MOV    EDX,DWORD PTR MaxScan
  CMP    WORD PTR Game.TIA_Scan,DX
  JNE    @NoFixTimer
  DEC    BYTE PTR Game.FixTimer
@NoFixTimer:

  CMP    BYTE PTR Game.FixTimer,1
  JNZ    @NotFixed
  MOVZX  EBX,BYTE PTR Game.FixTimerNum
  SUB    BYTE PTR Game.FixTimerNum,7
@NotFixed:
  MOV    BYTE PTR AtariSeg[INTTIM1],BL
  MOV    BYTE PTR AtariSeg[INTTIM2],BL

  MOV    EDX,EBX
  INC    EDX
  INC    EDX
  SUB    EAX,EAX
  CMP    EDX,EAX
  JGE    @LocalGetOut
  MOV    BYTE PTR Game.TimerDone,1
@LocalGetOut:
  POPAD
End; { Handle_Timer }

Procedure NewPalette;
Var I,J: Integer;
Begin
  If Game.Palette = 0 Then J := 0 Else J := 128;

  BI.bmiColors[0].rgbBlue     := Pal[J].B;
  BI.bmiColors[0].rgbGreen    := Pal[J].G;
  BI.bmiColors[0].rgbRed      := Pal[J].R;
  BI.bmiColors[0].rgbReserved := 0;
  For I := 0 To 126 Do
  Begin
    BI.bmiColors[I * 2 + 1].rgbBlue     := Pal[I + 1 + J].B;
    BI.bmiColors[I * 2 + 1].rgbGreen    := Pal[I + 1 + J].G;
    BI.bmiColors[I * 2 + 1].rgbRed      := Pal[I + 1 + J].R;
    BI.bmiColors[I * 2 + 1].rgbReserved := 0;
    BI.bmiColors[I * 2 + 2].rgbBlue     := Pal[I + 1 + J].B;
    BI.bmiColors[I * 2 + 2].rgbGreen    := Pal[I + 1 + J].G;
    BI.bmiColors[I * 2 + 2].rgbRed      := Pal[I + 1 + J].R;
    BI.bmiColors[I * 2 + 2].rgbReserved := 0;
  End; { For I }
  BI.B.bmiHeader.biSize          := SizeOf(TBitmapInfoHeader);
  BI.B.bmiHeader.biWidth         := ScnBufWidth;
  BI.B.bmiHeader.biHeight        := ScnBufHeight;
  BI.B.bmiHeader.biPlanes        := 1;
  BI.B.bmiHeader.biBitCount      := 8;
  BI.B.bmiHeader.biCompression   := BI_RGB;
  BI.B.bmiHeader.biSizeImage     := 0;
  BI.B.bmiHeader.biXPelsPerMeter := 2048;
  BI.B.bmiHeader.biYPelsPerMeter := 2048;
  BI.B.bmiHeader.biClrUsed       := 0;
  BI.B.bmiHeader.biClrImportant  := 0;

  BI1 := BI;
  BI1.B.bmiHeader.biWidth         := 2 * ScnBufWidth;

  PI.T.palVersion    := $300;
  PI.T.palNumEntries := 256;
  For I := 0 To 127 Do
  Begin
    PI.P[I * 2 + 0].peRed   := Pal[I + J].R;
    PI.P[I * 2 + 0].peGreen := Pal[I + J].G;
    PI.P[I * 2 + 0].peBlue  := Pal[I + J].B;
    PI.P[I * 2 + 0].peFlags := 0;
    PI.P[I * 2 + 1].peRed   := Pal[I + J].R;
    PI.P[I * 2 + 1].peGreen := Pal[I + J].G;
    PI.P[I * 2 + 1].peBlue  := Pal[I + J].B;
    PI.P[I * 2 + 1].peFlags := 0;
  End; { For I }

  If frmMain.UseDirectDraw Then
  Begin
    For I := 0 To 255 Do
    Begin
      frmMain.DXDraw1.ColorTable[I].rgbRed         := Pal[(I Shr 1) + J].R;
      frmMain.DXDraw1.ColorTable[I].rgbGreen       := Pal[(I Shr 1) + J].G;
      frmMain.DXDraw1.ColorTable[I].rgbBlue        := Pal[(I Shr 1) + J].B;
      frmMain.DXDraw1.ColorTable[I].rgbReserved    := 0;
      frmMain.DXDraw1.DefColorTable[I].rgbRed      := Pal[(I Shr 1) + J].R;
      frmMain.DXDraw1.DefColorTable[I].rgbGreen    := Pal[(I Shr 1) + J].G;
      frmMain.DXDraw1.DefColorTable[I].rgbBlue     := Pal[(I Shr 1) + J].B;
      frmMain.DXDraw1.DefColorTable[I].rgbReserved := 0;

      frmKaillera.DXDraw1.ColorTable[I].rgbRed         := Pal[(I Shr 1) + J].R;
      frmKaillera.DXDraw1.ColorTable[I].rgbGreen       := Pal[(I Shr 1) + J].G;
      frmKaillera.DXDraw1.ColorTable[I].rgbBlue        := Pal[(I Shr 1) + J].B;
      frmKaillera.DXDraw1.ColorTable[I].rgbReserved    := 0;
      frmKaillera.DXDraw1.DefColorTable[I].rgbRed      := Pal[(I Shr 1) + J].R;
      frmKaillera.DXDraw1.DefColorTable[I].rgbGreen    := Pal[(I Shr 1) + J].G;
      frmKaillera.DXDraw1.DefColorTable[I].rgbBlue     := Pal[(I Shr 1) + J].B;
      frmKaillera.DXDraw1.DefColorTable[I].rgbReserved := 0;
    End; { For I }
    frmMain.DXDraw1.UpdatePalette;
    frmKaillera.DXDraw1.UpdatePalette;
  End;
End; // NewPalette;

Var
  Info  : TAtariControls;
  Info0 : TAtariControls;

Procedure GetControllers;
Var
  Cap           : TCapability;
  SwReset       : Byte;
  SwSelect      : Byte;
//  Received      : Integer;

Begin
//  frmMain.Display;
  Cap.A := 0;
  Cap.B := 0;
  If (MenuInfo.ProfileRec <> Nil) And (MenuInfo.ProfileRec.Cont <> crUnknown) Then
   Game.Controller := MenuInfo.ProfileRec.Cont;

  Case Game.Controller Of
    crJoystick: Cap.A := imJoysticks;
      crPaddle: Cap.A := imPaddles;
         crVTP: Begin
                  Cap.A := imJoy1;
                  Cap.B := imKB2;
                End;
     crDriving: Cap.A := imDriving;
    crKeyboard: Cap.B := imKeyboard;
     crBooster: Cap.A := imJoysticks + imCBS;
  Else
    Cap.A := imJoysticks;
  End; { Case }
  Cap.B := Cap.B Or imConsole;

  { Initialize the info structure }

  Info0.PortA   := $FF;
  Info0.Console := 0;
  Info0.Pad[1]  := Game.PaddleGround0;
  Info0.Pad[2]  := Game.PaddleGround1;
  Info0.Pad[3]  := Game.PaddleGround2;
  Info0.Pad[4]  := Game.PaddleGround3;
  Info0.Input4  := False;
  Info0.Input5  := False;
  Info0.Driv[1] := Game.Indy500[0];
  Info0.Driv[2] := Game.Indy500[1];
  Info0.CBS1    := False;
  Info0.CBS2    := False;
  Info0.KB      := 0;

  InterfaceHandler.GetControllerInfo(Cap,Info0);

  { Make sure that basic console switches work }

  If UsingKaillera Then
  Begin
    If frmMain.DXInput1.Keyboard.DIKeys[DIK_SLASH] Then
    Begin
      frmKaillera.edtChat.Enabled := True;
      frmKaillera.edtChat.Text    := '';
      frmKaillera.FocusControl(frmKaillera.edtChat);
    End;
  End;

  If frmMain.DXInput1.Keyboard.DIKeys[DIK_ESCAPE] Then Info0.Console := Info0.Console Or cfPower;
  If frmMain.DXInput1.Keyboard.DIKeys[DIK_F2]     Then Info0.Console := Info0.Console Or cfReset;
  If frmMain.DXInput1.Keyboard.DIKeys[DIK_F4]     Then Info0.Console := Info0.Console Or cfSelect;
  If frmMain.DXInput1.Keyboard.DIKeys[DIK_F5]     Then Info0.Console := Info0.Console Or cfColorBW;
  If frmMain.DXInput1.Keyboard.DIKeys[DIK_F6]     Then Info0.Console := Info0.Console Or cfDiff1;
  If frmMain.DXInput1.Keyboard.DIKeys[DIK_F7]     Then Info0.Console := Info0.Console Or cfDiff2;
  If frmMain.DXInput1.Keyboard.DIKeys[DIK_F3]     Then
  Begin
    If PaletteChange Then
    Begin
      Game.Palette := Game.Palette Xor 1;
      If Game.Palette = 0
       Then frmMain.acNTSCPAL.ImageIndex := 4
       Else frmMain.acNTSCPAL.ImageIndex := 5;
      NewPalette;
      PaletteChange := False;
    End;
  End
  Else PaletteChange := True;
  If (frmMain.DXInput1.Keyboard.DIKeys[DIK_EQUALS]) And (Game.VUserAdd > -40) Then Dec(Game.VUserAdd);
  If (frmMain.DXInput1.Keyboard.DIKeys[DIK_MINUS])  And (Game.VUserAdd <  40) Then Inc(Game.VUserAdd);

  If UsingKaillera Then
  Begin
    Info.Console := Info.Console And (Not (cfDiff1 Or cfDiff2));
    Info.Console := Info.Console Or (KValues[1].Console And cfDiff1) Or (KValues[2].Console And cfDiff2);
    Info.Input4  := ((KValues[1].Console And $80) <> 0);
    Info.Input5  := ((KValues[2].Console And $80) <> 0);
    Case Game.Controller Of
      crPaddle:
      Begin
        Info.Pad[1]  := KValues[1].PadDriv;
        Info.Pad[2]  := KValues[2].PadDriv;
        Info.Pad[3]  := KValues[3].PadDriv;
        Info.Pad[4]  := KValues[4].PadDriv;
        Info.PortA := (Info.PortA And $33) Or
                      (KValues[1].PortA And $80) Or
                      ((KValues[2].PortA And $80) Shr 1) Or
                      ((KValues[3].PortA And $80) Shr 4) Or
                      ((KValues[4].PortA And $80) Shr 5);
      End;
      crDriving:
      Begin
        Info.Driv[1] := KValues[1].PadDriv;
        Info.Driv[2] := KValues[2].PadDriv;
        Info.PortA := (KValues[1].PortA And $F0) Or (KValues[2].PortA And $0F);
      End;
    Else
      Info.PortA := (KValues[1].PortA And $F0) Or (KValues[2].PortA And $0F);
    End; // Case
  End
  Else Move(Info0,Info,SizeOf(Info));

  { Get controller information }

  If Game.Cart <> ctCompumate Then
  Case Game.Controller Of
    crJoystick,crBooster: Begin
                  AtariSeg[SWCHA1] := Info.PortA;
                  If Game.Latched Then
                  Begin
                    If Info.Input4 Then
                     Game.Input_Byte[INPUT4] := Game.Input_Byte[INPUT4] And $7F;
                    If Info.Input5 Then
                     Game.Input_Byte[INPUT5] := Game.Input_Byte[INPUT5] And $7F;
                  End
                  Else
                  Begin
                    If Info.Input4
                     Then Game.Input_Byte[INPUT4] := 0
                     Else Game.Input_Byte[INPUT4] := $80;
                    If Info.Input5
                     Then Game.Input_Byte[INPUT5] := 0
                     Else Game.Input_Byte[INPUT5] := $80;
                  End;
                  If Game.Controller = crBooster Then
                  Begin
                    If Info.CBS1
                     Then Game.Input_Byte[INPUT0] := Game.Input_Byte[INPUT0] Or  $80
                     Else Game.Input_Byte[INPUT0] := Game.Input_Byte[INPUT0] And $7F;
                    If Info.CBS2
                     Then Game.Input_Byte[INPUT1] := Game.Input_Byte[INPUT1] Or  $80
                     Else Game.Input_Byte[INPUT1] := Game.Input_Byte[INPUT1] And $7F;
                  End;
                End;
      crPaddle: Begin
                    Game.OldPaddleGround0 := Info.Pad[1];
                    Game.OldPaddleGround1 := Info.Pad[2];
                    Game.OldPaddleGround2 := Info.Pad[3];
                    Game.OldPaddleGround3 := Info.Pad[4];
                  AtariSeg[SWCHA1] := Info.PortA;
                End;
         crVTP: Begin
                  AtariSeg[SWCHA1] := (AtariSeg[SWCHA1] And $F) Or (Info.PortA And $F0);
                  If Game.Latched Then
                  Begin
                    If Info.Input4 Then
                     Game.Input_Byte[INPUT4] := Game.Input_Byte[INPUT4] And $7F;
                    If Info.Input5 Then
                     Game.Input_Byte[INPUT5] := Game.Input_Byte[INPUT5] And $7F;
                  End
                  Else
                  Begin
                    If Info.Input4
                     Then Game.Input_Byte[INPUT4] := 0
                     Else Game.Input_Byte[INPUT4] := $80;
                    If Info.Input5
                     Then Game.Input_Byte[INPUT5] := 0
                     Else Game.Input_Byte[INPUT5] := $80;
                  End;
                  Game.KeyColumn := Info.KB;
                  CheckKBController;
                End;
     crDriving: Begin
                  Game.Indy500[0] := Info.Driv[1];
                  Game.Indy500[1] := Info.Driv[2];
                  AtariSeg[SWCHA1] := Indy500Trans1[(Game.Indy500[0] Shr 2) And 3] And
                                      Indy500Trans2[(Game.Indy500[1] Shr 2) And 3];
                  If Game.Latched Then
                  Begin
                    If Info.Input4 Then
                     Game.Input_Byte[INPUT4] := Game.Input_Byte[INPUT4] And $7F;
                    If Info.Input5 Then
                     Game.Input_Byte[INPUT5] := Game.Input_Byte[INPUT5] And $7F;
                  End
                  Else
                  Begin
                    If Info.Input4
                     Then Game.Input_Byte[INPUT4] := 0
                     Else Game.Input_Byte[INPUT4] := $80;
                    If Info.Input5
                     Then Game.Input_Byte[INPUT5] := 0
                     Else Game.Input_Byte[INPUT5] := $80;
                  End;
                End;
    crKeyboard: Begin
                  Game.KeyColumn := Info.KB;
                  CheckKBController;
                End;
  Else
  End; { Case }

  { Compumate }

  If Game.Cart = ctCompumate Then
  Begin
    CheckCMKeyboard;
    Game.Input_Byte[INPUT0] := CMPorts[0];
    Game.Input_Byte[INPUT1] := CMPorts[1];
    Game.Input_Byte[INPUT2] := CMPorts[2];
    Game.Input_Byte[INPUT3] := CMPorts[3];
    Game.Input_Byte[INPUT4] := CMInputLatch[0];
    Game.Input_Byte[INPUT5] := CMInputLatch[1];
  End;

  { Get console switch information }

  If (Info.Console And cfPower) <> 0 Then
  Begin
    Exiting := True;
    If UsingKaillera Then KailleraEndGame;
  End;

  SwReset := AtariSeg[SWCHB1] And 1;
  If ResetChange Then
  Begin
    If (Info.Console And cfReset) <> 0 Then
    Begin
      SwReset     := 0;
      ResetChange := False;
    End
    Else SwReset := 1;
  End;

  SwSelect := AtariSeg[SWCHB1] And 2;
  If SelectChange Then
  Begin
    If (Info.Console And cfSelect) <> 0 Then
    Begin
      SwSelect     := 0;
      SelectChange := False;
    End
    Else SwSelect := 2;
  End;

  If (Info.Console And cfColorBW) <> 0 Then
  Begin
    If ColorOrBWChange Then
    Begin
      Game.ColorOrBW := Game.ColorOrBW Xor 8;
      ColorOrBWChange := False;
      If Game.ColorOrBW <> 0
       Then frmMain.acColorBW.ImageIndex := 2
       Else frmMain.acColorBW.ImageIndex := 3;
    End;
  End

  Else ColorOrBWChange := True;

  If (Info.Console And cfDiff1) <> 0 Then
  Begin
    If Difficulty1Change Then
    Begin
      Game.Difficulty1 := Game.Difficulty1 Xor $40;
      Difficulty1Change := False;
      If Game.Difficulty1 = 0
       Then frmMain.acDifficulty1.ImageIndex := 5
       Else frmMain.acDifficulty1.ImageIndex := 4;
    End;
  End
  Else Difficulty1Change := True;

  If (Info.Console And cfDiff2) <> 0 Then
  Begin
    If Difficulty2Change Then
    Begin
      Game.Difficulty2 := Game.Difficulty2 Xor $80;
      Difficulty2Change := False;
      If Game.Difficulty2 = 0
       Then frmMain.acDifficulty2.ImageIndex := 5
       Else frmMain.acDifficulty2.ImageIndex := 4;
    End;
  End
  Else Difficulty2Change := True;

  { Copy info }

  AtariSeg[SWCHA2] := AtariSeg[SWCHA1];
  AtariSeg[SWCHB1] := (SwReset Or
                       SwSelect Or
                       Game.ColorOrBW Or
                       Game.Difficulty1 Or
                       Game.Difficulty2) And $CF;
  AtariSeg[SWCHB2] := AtariSeg[SWCHB1];

  ResetChange  := True;
  SelectChange := True;

  { Check other special keys }
{
  If Key[kF1] <> 0 Then
  Begin
    GameStatus(Config.MaxCols,Game.MaxRows,Game.Difficulty1,Game.Difficulty2,AutoCenter);
    ResetClock;
  End;
}
  If frmMain.DXInput1.Keyboard.DIKeys[DIK_F10]  Then
  Begin
    If AutoCenterChange Then
    Begin
      AutoCenter       := Not AutoCenter;
      AutoCenterChange := False;
    End;
  End
  Else AutoCenterChange := True;
//  If frmMain.DXInput1.Keyboard.DIKeys[DIK_F12] Then frmMain.SaveStatus;
//  If frmMain.DXInput1.Keyboard.DIKeys[DIK_F11] Then frmMain.RestoreStatus;
End; { GetControllers }

Procedure SlowDown;
Var
  T : LongInt;
  R : Double;

  Procedure Net;
  Var Received: Integer;
  Begin
    If UsingKaillera Then
    Begin
      Case Game.Controller Of
        crPaddle: KValues[1].PadDriv := Info0.Pad[1];
       crDriving: KValues[1].PadDriv := Info0.Driv[1];
      End; // Case
      KValues[1].PortA   := Info0.PortA;
      KValues[1].Console := Info0.Console And $3F;
      If Info0.Input4 Then KValues[1].Console := KValues[1].Console Or $80;
      Received := KailleraModifyPlayValues(@KValues,SizeOf(TKailleraControls));
      If Received > 0 Then
      Begin
        Info.Console := (KValues[1].Console Or KValues[2].Console) And (Not (cfDiff1 Or cfDiff2));
        Info.Console := Info.Console Or (KValues[1].Console And cfDiff1) Or (KValues[2].Console And cfDiff2);
        Info.Input4  := ((KValues[1].Console And $80) <> 0);
        Info.Input5  := ((KValues[2].Console And $80) <> 0);
        Case Game.Controller Of
          crPaddle:
          Begin
            Info.Pad[1]  := KValues[1].PadDriv;
            Info.Pad[2]  := KValues[2].PadDriv;
            Info.Pad[3]  := KValues[3].PadDriv;
            Info.Pad[4]  := KValues[4].PadDriv;
            Info.PortA := (Info.PortA And $33) Or
                          (KValues[1].PortA And $80) Or
                          ((KValues[2].PortA And $80) Shr 1) Or
                          ((KValues[3].PortA And $80) Shr 4) Or
                          ((KValues[4].PortA And $80) Shr 5);
          End;
          crDriving:
          Begin
            Info.Driv[1] := KValues[1].PadDriv;
            Info.Driv[2] := KValues[2].PadDriv;
            Info.PortA := (KValues[1].PortA And $F0) Or (KValues[2].PortA And $0F);
          End;
        Else
          Info.PortA := (KValues[1].PortA And $F0) Or (KValues[2].PortA And $0F);
        End; // Case
      End;
    End;
  End; // Net

Begin
  Inc(frmMain.Frames);
  
  Net;

  frmMain.Display;
  If Config.FrameRate > 0 Then
  Begin
    R := Time0 + (1000 / Config.FrameRate);
    Repeat
      T := GetTickCount;
      If T < (R - 1000) Then T := Trunc(R);
    Until (T >= R);
    Time0 := R;
  End;

  // Calculate measured FPS for display

  T := GetTickCount;
  If T > frmMain.BaseTime Then frmMain.FPS := 1000 * frmMain.Frames / (T - frmMain.BaseTime);
End; { SlowDown }

Procedure SetReadMask;
Begin
  GetControllers;
  InterfaceHandler.SetReadMask(AtariSeg[SWACNT1] Xor $FF);
End; { SetReadMask }

Procedure WriteToPortA;
Begin
  InterfaceHandler.WriteToPort(AtariSeg[SWCHA1]);
  GetControllers;
End; { WriteToPortA }

Procedure DoP0Motion; Assembler;
Asm
  PUSHAD
  MOV   EAX,DWORD PTR Game.ObjectMove[Player0Set * 2]
  ADD   DWORD PTR Game.ObjectLoc[Player0Set * 2],EAX

  MOV   ECX,160
  TEST  AL,AL
  JS    @P0
  NEG   ECX
@P0:
  CMP   DWORD PTR Game.ObjectLoc[Player0Set * 2],160
  JB    @P0Ok
  ADD   DWORD PTR Game.ObjectLoc[Player0Set * 2],ECX
@P0Ok:
  MOV   EAX,DWORD PTR Game.OldPlayer0Size128
  MOV   DWORD PTR Game.Player0Size128,EAX
  POPAD
End; { DoP0Motion }

Procedure DoP1Motion; Assembler;
Asm
  PUSHAD
  MOV   EAX,DWORD PTR Game.ObjectMove[Player1Set * 2]
  ADD   DWORD PTR Game.ObjectLoc[Player1Set * 2],EAX

  MOV   ECX,160
  TEST  AL,AL
  JS    @P1
  NEG   ECX
@P1:
  CMP   DWORD PTR Game.ObjectLoc[Player1Set * 2],160
  JB    @P1Ok
  ADD   DWORD PTR Game.ObjectLoc[Player1Set * 2],ECX
@P1Ok:
  MOV   EAX,DWORD PTR Game.OldPlayer1Size128
  MOV   DWORD PTR Game.Player1Size128,EAX
  POPAD
End; { DoP1Motion }

Procedure DoM0Motion; Assembler;
Asm
  PUSHAD
  TEST  BYTE PTR AtariSeg[RESMP0],2
  JZ    @Missile0OkA
  MOV   AL,BYTE PTR Game.ObjectLoc[Player0Set * 2]
  MOV   AH,BYTE PTR Game._Player0Size
  SHR   AH,1
  ADD   AL,AH

  AND   EAX,0FFh

  CMP   EAX,160
  JB    @M0Ok1
  SUB   EAX,160
@M0Ok1:
  MOV   DWORD PTR Game.ObjectLoc[Missile0Set * 2],EAX
  JMP   @M0Ok
@Missile0OkA:
  MOV   EAX,DWORD PTR Game.ObjectMove[Missile0Set * 2]
  MOV   EBX,DWORD PTR Game.ObjectLoc[Missile0Set * 2]
  ADD   DWORD PTR Game.ObjectLoc[Missile0Set * 2],EAX
  MOV   ECX,160
  TEST  AL,AL
  JS    @M0
  NEG   ECX
@M0:
  CMP   DWORD PTR Game.ObjectLoc[Missile0Set * 2],160
  JGE   @AddToM0
  CMP   DWORD PTR Game.ObjectLoc[Missile0Set * 2],-68
  JL    @AddToM0
  CMP   DWORD PTR Game.ObjectLoc[Missile0Set * 2],0
  JGE   @M0Ok
  CMP   EAX,-1
  JG    @M0Ok
  CMP   EBX,-8
  JL    @M0Ok
@AddToM0:
  ADD   DWORD PTR Game.ObjectLoc[Missile0Set * 2],ECX

@M0Ok:
  POPAD
End; { DoM0Motion }

Procedure DoM1Motion; Assembler;
Asm
  PUSHAD
  TEST  BYTE PTR AtariSeg[RESMP1],2
  JZ    @Missile1OkA
  MOV   AL,BYTE PTR Game.ObjectLoc[Player1Set * 2]
  MOV   AH,BYTE PTR Game._Player1Size
  SHR   AH,1
  ADD   AL,AH

  AND   EAX,0FFh

  CMP   EAX,160
  JB    @M1Ok1
  SUB   EAX,160
@M1Ok1:
  MOV   DWORD PTR Game.ObjectLoc[Missile1Set * 2],EAX
  JMP   @M1Ok
@Missile1OkA:
  MOV   EAX,DWORD PTR Game.ObjectMove[Missile1Set * 2]
  MOV   EBX,DWORD PTR Game.ObjectLoc[Missile1Set * 2]
  ADD   DWORD PTR Game.ObjectLoc[Missile1Set * 2],EAX
  MOV   ECX,160
  TEST  AL,AL
  JS    @M1
  NEG   ECX
@M1:
  CMP   DWORD PTR Game.ObjectLoc[Missile1Set * 2],160
  JGE   @AddToM1
  CMP   DWORD PTR Game.ObjectLoc[Missile1Set * 2],-68
  JL    @AddToM1
  CMP   DWORD PTR Game.ObjectLoc[Missile1Set * 2],0
  JGE   @M1Ok
  CMP   EAX,-1
  JG    @M1Ok
  CMP   EBX,-8
  JL    @M1Ok
@AddToM1:
  ADD   DWORD PTR Game.ObjectLoc[Missile1Set * 2],ECX
@M1Ok:
  POPAD
End; { DoM1Motion }

Procedure DoBLMotion; Assembler;
Asm
  PUSHAD
  MOV   EAX,DWORD PTR Game.ObjectMove[BallSet * 2]
  MOV   EBX,DWORD PTR Game.ObjectLoc[BallSet * 2]
  ADD   DWORD PTR Game.ObjectLoc[BallSet * 2],EAX
  MOV   ECX,160
  TEST  AL,AL
  JS    @BL
  NEG   ECX
@BL:
  CMP   DWORD PTR Game.ObjectLoc[BallSet * 2],160
  JGE   @AddToBL
  CMP   DWORD PTR Game.ObjectLoc[BallSet * 2],-68
  JL    @AddToBL
  CMP   DWORD PTR Game.ObjectLoc[BallSet * 2],0
  JGE   @BLOk
  CMP   EAX,-1
  JG    @BLOk
  CMP   EBX,-8
  JL    @BLOk
@AddToBL:
  ADD   DWORD PTR Game.ObjectLoc[BallSet * 2],ECX
@BLOk:
  POPAD
End; { DoBLMotion }

Procedure SetP0Motion; Assembler;
Asm
  PUSHAD
  TEST  BYTE PTR Game.DoHMOVE,0FFh
  JZ    @HMP01
  MOVSX EBX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EBX,ECX
  ADD   EBX,ECX
  ADD   EBX,ECX
  CMP   EBX,8
  JGE   @HMP01
  MOV   AL,BYTE PTR AtariSeg[HMP0]
  AND   EAX,0F0h
  ADD   EBX,68
  SHL   EBX,8
  ADD   EBX,EAX
  MOV   AL,BYTE PTR Game.TIA_Regs[HMP0]
  SHR   EAX,4
  AND   EAX,0Fh
  ADD   EBX,EAX
  MOVSX EAX,BYTE PTR SetAdjust[EBX]
  MOV   DWORD PTR Game.ObjectMove[Player0Set  * 2],EAX
  CALL  DoP0Motion
@HMP01:
  POPAD
End; { SetP0Motion }

Procedure SetP1Motion; Assembler;
Asm
  PUSHAD
  TEST  BYTE PTR Game.DoHMOVE,0FFh
  JZ    @HMP01
  MOVSX EBX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EBX,ECX
  ADD   EBX,ECX
  ADD   EBX,ECX
  CMP   EBX,8
  JGE   @HMP01
  MOV   AL,BYTE PTR AtariSeg[HMP1]
  AND   EAX,0F0h
  ADD   EBX,68
  SHL   EBX,8
  ADD   EBX,EAX
  MOV   AL,BYTE PTR Game.TIA_Regs[HMP1]
  SHR   EAX,4
  AND   EAX,0Fh
  ADD   EBX,EAX
  MOVSX EAX,BYTE PTR SetAdjust[EBX]
  MOV   DWORD PTR Game.ObjectMove[Player1Set  * 2],EAX
  CALL  DoP1Motion
@HMP01:
  POPAD
End; { SetP1Motion }

Procedure SetM0Motion; Assembler;
Asm
  PUSHAD
  TEST  BYTE PTR Game.DoHMOVE,0FFh
  JZ    @HMM01
  MOVSX EBX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EBX,ECX
  ADD   EBX,ECX
  ADD   EBX,ECX
  CMP   EBX,8
  JGE   @HMM01
  MOV   AL,BYTE PTR AtariSeg[HMM0]
  AND   EAX,0F0h
  ADD   EBX,68
  SHL   EBX,8
  ADD   EBX,EAX
  MOV   AL,BYTE PTR Game.TIA_Regs[HMM0]
  SHR   EAX,4
  AND   EAX,0Fh
  ADD   EBX,EAX
  MOVSX EAX,BYTE PTR SetAdjust[EBX]
  MOV   DWORD PTR Game.ObjectMove[Missile0Set  * 2],EAX
  CALL  DoM0Motion
@HMM01:
  POPAD
End; { SetM0Motion }

Procedure SetM1Motion; Assembler;
Asm
  PUSHAD
  TEST  BYTE PTR Game.DoHMOVE,0FFh
  JZ    @HMM01
  MOVSX EBX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EBX,ECX
  ADD   EBX,ECX
  ADD   EBX,ECX
  CMP   EBX,8
  JGE   @HMM01
  MOV   AL,BYTE PTR AtariSeg[HMM1]
  AND   EAX,0F0h
  ADD   EBX,68
  SHL   EBX,8
  ADD   EBX,EAX
  MOV   AL,BYTE PTR Game.TIA_Regs[HMM1]
  SHR   EAX,4
  AND   EAX,0Fh
  ADD   EBX,EAX
  MOVSX EAX,BYTE PTR SetAdjust[EBX]
  MOV   DWORD PTR Game.ObjectMove[Missile1Set  * 2],EAX
  CALL  DoM1Motion
@HMM01:
  POPAD
End; { SetM1Motion }

Procedure SetBLMotion; Assembler;
Asm
  PUSHAD
  TEST  BYTE PTR Game.DoHMOVE,0FFh
  JZ    @HMBL1
  MOVSX EBX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EBX,ECX
  ADD   EBX,ECX
  ADD   EBX,ECX
  CMP   EBX,8
  JGE   @HMBL1
  MOV   AL,BYTE PTR AtariSeg[HMBL]
  AND   EAX,0F0h
  ADD   EBX,68
  SHL   EBX,8
  ADD   EBX,EAX
  MOV   AL,BYTE PTR Game.TIA_Regs[HMBL]
  SHR   EAX,4
  AND   EAX,0Fh
  ADD   EBX,EAX
  MOVSX EAX,BYTE PTR SetAdjust[EBX]
  MOV   DWORD PTR Game.ObjectMove[BallSet  * 2],EAX
  CALL  DoBLMotion
@HMBL1:
  POPAD
End; { SetBLMotion }

Procedure GetPlayerDelay; Assembler;
{ Input values:  EAX = player (0 or 1) }
{ Output values: EAX = delay (bit 7 set if deleting player) }
Asm
    PUSH  EBX
    PUSH  ECX
    PUSH  EDX
    PUSH  ESI
    PUSH  EDI
    MOV   ESI,EAX
    CMP   EAX,0
    JNE   @Player1
    MOV   EDI,Player0Set * 2
    JMP   @ChosePlayer
@Player1:
    MOV   EDI,Player1Set * 2
@ChosePlayer:
    MOV   BL,BYTE PTR Game.TIA_Regs[NUSIZ0 + ESI]
    AND   EBX,7
    SHL   EBX,2
    MOV   EAX,DWORD PTR Game.OldObjectLoc[EDI]
    SUB   EAX,5
    MOV   ECX,DWORD PTR Game.ObjectLoc[EDI]
    SUB   ECX,5
    CMP   ECX,EAX
    JL    @TurnOff
    MOV   EDX,ECX
    SUB   EDX,EAX
    JNS   @NoCarry
    ADD   EDX,160
@NoCarry:
    CMP   EDX,DWORD PTR PlayerSizeD[EBX]
    JA    @TurnOff

    ADD   EAX,DWORD PTR PlayerZone1[EBX]
    CMP   EAX,160
    JL    @NoCarry1
    SUB   EAX,160
@NoCarry1:
    CMP   ECX,EAX
    JL    @NoTurnOff
    ADD   EAX,DWORD PTR _PlayerSize[EBX]
    ADD   EAX,2
    CMP   EAX,160
    JL    @NoCarry2
    SUB   EAX,160
@NoCarry2:
    CMP   ECX,EAX
    JLE   @Delay

    CMP   DWORD PTR PlayerInc1[EBX],0
    JE    @TurnOff
    ADD   EAX,DWORD PTR PlayerInc1[EBX]
    CMP   EAX,160
    JL    @NoCarry3
    SUB   EAX,160
@NoCarry3:
    CMP   ECX,EAX
    JL    @TurnOff
    ADD   EAX,DWORD PTR PlayerZone2[EBX]
    CMP   EAX,160
    JL    @NoCarry4
    SUB   EAX,160
@NoCarry4:
    CMP   ECX,EAX
    JL    @NoTurnOff
    ADD   EAX,DWORD PTR _PlayerSize[EBX]
    ADD   EAX,2
    CMP   EAX,160
    JL    @NoCarry5
    SUB   EAX,160
@NoCarry5:
    CMP   ECX,EAX
    JLE   @Delay

    CMP   DWORD PTR PlayerInc2[EBX],0
    JE    @TurnOff
    ADD   EAX,DWORD PTR PlayerInc2[EBX]
    CMP   EAX,160
    JL    @NoCarry6
    SUB   EAX,160
@NoCarry6:
    CMP   ECX,EAX
    JL    @TurnOff
    ADD   EAX,DWORD PTR PlayerZone2[EBX]
    CMP   EAX,160
    JL    @NoCarry7
    SUB   EAX,160
@NoCarry7:
    CMP   ECX,EAX
    JL    @NoTurnOff
    ADD   EAX,DWORD PTR _PlayerSize[EBX]
    ADD   EAX,2
    CMP   EAX,160
    JL    @NoCarry8
    SUB   EAX,160
@NoCarry8:
    CMP   ECX,EAX
    JLE   @Delay

@TurnOff:
    SUB   EAX,EAX
    JMP   @TurnOffDone
@NoTurnOff:
    MOV   EAX,80h
    JMP   @TurnOffDone
@Delay:
    SUB   EAX,ECX
@TurnOffDone:
    POP   EDI
    POP   ESI
    POP   EDX
    POP   ECX
    POP   EBX
End; { GetPlayerDelay }


Procedure GetMissileDelay; Assembler;
{ Input values:  EAX = missile (0 or 1) }
{ Output values: EAX = delay (bit 7 set if deleting player) }
Asm
    PUSH  EBX
    PUSH  ECX
    PUSH  EDX
    PUSH  ESI
    PUSH  EDI
    MOV   ESI,EAX
    CMP   EAX,0
    JNE   @Missile1
    MOV   EDI,Missile0Set * 2
    JMP   @ChoseMissile
@Missile1:
    MOV   EDI,Missile1Set * 2
@ChoseMissile:
    MOV   BL,BYTE PTR Game.TIA_Regs[NUSIZ0 + ESI]
    AND   EBX,7
    SHL   EBX,2
    MOV   EAX,DWORD PTR Game.OldObjectLoc[EDI]
    SUB   EAX,4
    MOV   ECX,DWORD PTR Game.ObjectLoc[EDI]
    SUB   ECX,4
    CMP   ECX,EAX
    JL    @NoTurnOff
    MOV   EDX,ECX
    SUB   EDX,EAX
    JNS   @NoCarry
    ADD   EDX,160
@NoCarry:
    CMP   EDX,DWORD PTR PlayerSizeD[EBX]
    JA    @TurnOff

    ADD   EAX,DWORD PTR MissileZone1[EBX]
    CMP   EAX,160
    JL    @NoCarry1
    SUB   EAX,160
@NoCarry1:
    CMP   ECX,EAX
    JL    @NoTurnOff
    ADD   EAX,9
    CMP   EAX,160
    JL    @NoCarry2
    SUB   EAX,160
@NoCarry2:
    CMP   ECX,EAX
    JLE   @Delay

    CMP   DWORD PTR MissileInc1[EBX],0
    JE    @TurnOff
    ADD   EAX,DWORD PTR MissileInc1[EBX]
    CMP   EAX,160
    JL    @NoCarry3
    SUB   EAX,160
@NoCarry3:
    CMP   ECX,EAX
    JL    @TurnOff
    ADD   EAX,2
    CMP   EAX,160
    JL    @NoCarry4
    SUB   EAX,160
@NoCarry4:
    CMP   ECX,EAX
    JGE   @NoDelay1
    MOV   EAX,ECX
    JMP   @Delay
@NoDelay1:
    ADD   EAX,DWORD PTR MissileZone2[EBX]
    CMP   EAX,160
    JL    @NoCarry5
    SUB   EAX,160
@NoCarry5:
    CMP   ECX,EAX
    JL    @NoTurnOff
    ADD   EAX,9
    CMP   EAX,160
    JL    @NoCarry6
    SUB   EAX,160
@NoCarry6:
    CMP   ECX,EAX
    JLE   @Delay

    CMP   DWORD PTR MissileInc2[EBX],0
    JE    @TurnOff
    ADD   EAX,DWORD PTR MissileInc2[EBX]
    CMP   EAX,160
    JL    @NoCarry7
    SUB   EAX,160
@NoCarry7:
    CMP   ECX,EAX
    JL    @TurnOff
    ADD   EAX,2
    CMP   EAX,160
    JL    @NoCarry8
    SUB   EAX,160
@NoCarry8:
    CMP   ECX,EAX
    JGE   @NoDelay2
    MOV   EAX,ECX
    JMP   @Delay
@NoDelay2:
    ADD   EAX,DWORD PTR MissileZone2[EBX]
    CMP   EAX,160
    JL    @NoCarry9
    SUB   EAX,160
@NoCarry9:
    CMP   ECX,EAX
    JL    @NoTurnOff
    ADD   EAX,9
    CMP   EAX,160
    JL    @NoCarry10
    SUB   EAX,160
@NoCarry10:
    CMP   ECX,EAX
    JLE   @Delay

@TurnOff:
    MOV   BL,BYTE PTR Game.TIA_Regs[NUSIZ0 + ESI]
    SHR   EBX,3
    AND   EBX,6
    MOV   AL,BYTE PTR MissileSize[EBX]
    AND   EAX,0FFh
    JMP   @TurnOffDone
@NoTurnOff:
    MOV   EAX,80h
    JMP   @TurnOffDone
@Delay:
    SUB   EAX,ECX
    CMP   EAX,8
    JBE   @TurnOffDone
    SUB   EAX,EAX
@TurnOffDone:
    POP   EDI
    POP   ESI
    POP   EDX
    POP   ECX
    POP   EBX
End; { GetMissileDelay }


Procedure GetBallDelay; Assembler;
{ Output values: EAX = delay (bit 7 set if deleting player) }
Asm
    PUSH  EBX
    PUSH  ECX
    PUSH  EDX
    MOV   EAX,DWORD PTR Game.OldObjectLoc[BallSet * 2]
    SUB   EAX,4
    MOV   ECX,DWORD PTR Game.ObjectLoc[BallSet * 2]
    SUB   ECX,4
    CMP   ECX,EAX
    JL    @TurnOff
    MOV   EDX,ECX
    SUB   EDX,EAX
    JNC   @NoCarry
    ADD   EDX,160
@NoCarry:
    CMP   EDX,DWORD PTR Game.BallSize
    JA    @TurnOff

    ADD   EAX,DWORD PTR MissileZone1[0]
    CMP   EAX,160
    JL    @NoCarry1
    SUB   EAX,160
@NoCarry1:
    CMP   ECX,EAX
    JL    @NoTurnOff
    MOV   ECX,EAX
    ADD   EAX,9
    CMP   EAX,160
    JL    @NoCarry2
    SUB   EAX,160
@NoCarry2:
    CMP   ECX,EAX
    JLE   @Delay

@TurnOff:
    MOV   EAX,DWORD PTR Game.BallSize
    JMP   @TurnOffDone
@NoTurnOff:
    MOV   EAX,80h
    JMP   @TurnOffDone
@Delay:
    SUB   EAX,ECX
    CMP   EAX,8
    JBE   @TurnOffDone
    SUB   EAX,EAX
@TurnOffDone:
    POP   EDX
    POP   ECX
    POP   EBX
End; { GetBallDelay }

Procedure Handle_IO; Assembler;
{ ---------------------------------------------------------------------- }
{ On entry:                                                              }
{ EBX = Game.Save_BX                                                     }
{ ---------------------------------------------------------------------- }
Label LVSYNC,LVBLANK,LWSYNC,LRSYNC,LAUDV0,LAUDC0,LAUDF0,LNUSIZ0,LNUSIZ1,
      LAUDV1,LAUDC1,LAUDF1,LHMP0,LHMP1,LHMM0,LHMM1,LHMBL,
      LRESP0,LRESP1,LRESM0,LRESM1,LRESBL,LGRP0,LGRP1,LENABL,LCTRLPF,
      LHMCLR,LSWCHA1,LSWACNT1,LSWCHB1,LSWBCNT1,
      LINTTIM1,LINTTIM3,LTIM1T1,LTIM2T1,LTIM3T1,LTIM4T1,LSWCHA2,LSWACNT2,LSWCHB2,
      LSWBCNT2,LINTTIM2,LTIM1T2,LTIM2T2,LTIM3T2,LTIM4T2,GetOut;
Asm
  PUSHAD

  TEST  BYTE PTR Handle_IO_Set,0FFh
  JNZ   @L2
  MOV   EAX,OFFSET GetOut
  MOV   ECX,TIM4T2
  SUB   EBX,EBX
@L1:
  MOV   DWORD PTR Handle_IO_Loc[EBX],EAX
  ADD   EBX,4
  LOOP  @L1

  MOV   DWORD PTR Handle_IO_Loc[GRP0    * 4],OFFSET LGRP0
  MOV   DWORD PTR Handle_IO_Loc[GRP1    * 4],OFFSET LGRP1
  MOV   DWORD PTR Handle_IO_Loc[ENABL   * 4],OFFSET LENABL
  MOV   DWORD PTR Handle_IO_Loc[AUDV0   * 4],OFFSET LAUDV0
  MOV   DWORD PTR Handle_IO_Loc[AUDC0   * 4],OFFSET LAUDC0
  MOV   DWORD PTR Handle_IO_Loc[AUDF0   * 4],OFFSET LAUDF0
  MOV   DWORD PTR Handle_IO_Loc[AUDV1   * 4],OFFSET LAUDV1
  MOV   DWORD PTR Handle_IO_Loc[AUDC1   * 4],OFFSET LAUDC1
  MOV   DWORD PTR Handle_IO_Loc[AUDF1   * 4],OFFSET LAUDF1
  MOV   DWORD PTR Handle_IO_Loc[CTRLPF  * 4],OFFSET LCTRLPF
  MOV   DWORD PTR Handle_IO_Loc[HMP0    * 4],OFFSET LHMP0
  MOV   DWORD PTR Handle_IO_Loc[HMP1    * 4],OFFSET LHMP1
  MOV   DWORD PTR Handle_IO_Loc[HMM0    * 4],OFFSET LHMM0
  MOV   DWORD PTR Handle_IO_Loc[HMM1    * 4],OFFSET LHMM1
  MOV   DWORD PTR Handle_IO_Loc[HMBL    * 4],OFFSET LHMBL
  MOV   DWORD PTR Handle_IO_Loc[NUSIZ0  * 4],OFFSET LNUSIZ0
  MOV   DWORD PTR Handle_IO_Loc[NUSIZ1  * 4],OFFSET LNUSIZ1
  MOV   DWORD PTR Handle_IO_Loc[VSYNC   * 4],OFFSET LVSYNC
  MOV   DWORD PTR Handle_IO_Loc[VBLANK  * 4],OFFSET LVBLANK
  MOV   DWORD PTR Handle_IO_Loc[WSYNC   * 4],OFFSET LWSYNC
  MOV   DWORD PTR Handle_IO_Loc[RSYNC   * 4],OFFSET LRSYNC
  MOV   DWORD PTR Handle_IO_Loc[RESP0   * 4],OFFSET LRESP0
  MOV   DWORD PTR Handle_IO_Loc[RESP1   * 4],OFFSET LRESP1
  MOV   DWORD PTR Handle_IO_Loc[RESM0   * 4],OFFSET LRESM0
  MOV   DWORD PTR Handle_IO_Loc[RESM1   * 4],OFFSET LRESM1
  MOV   DWORD PTR Handle_IO_Loc[RESBL   * 4],OFFSET LRESBL
  MOV   DWORD PTR Handle_IO_Loc[HMCLR   * 4],OFFSET LHMCLR
  MOV   DWORD PTR Handle_IO_Loc[SWCHA1  * 4],OFFSET LSWCHA1
  MOV   DWORD PTR Handle_IO_Loc[SWACNT1 * 4],OFFSET LSWACNT1
  MOV   DWORD PTR Handle_IO_Loc[SWCHB1  * 4],OFFSET LSWCHB1
  MOV   DWORD PTR Handle_IO_Loc[SWBCNT1 * 4],OFFSET LSWBCNT1
  MOV   DWORD PTR Handle_IO_Loc[INTTIM1 * 4],OFFSET LINTTIM1
  MOV   DWORD PTR Handle_IO_Loc[INTTIM3 * 4],OFFSET LINTTIM3
  MOV   DWORD PTR Handle_IO_Loc[TIM1T1  * 4],OFFSET LTIM1T1
  MOV   DWORD PTR Handle_IO_Loc[TIM2T1  * 4],OFFSET LTIM2T1
  MOV   DWORD PTR Handle_IO_Loc[TIM3T1  * 4],OFFSET LTIM3T1
  MOV   DWORD PTR Handle_IO_Loc[TIM4T1  * 4],OFFSET LTIM4T1
  MOV   DWORD PTR Handle_IO_Loc[SWCHA2  * 4],OFFSET LSWCHA2
  MOV   DWORD PTR Handle_IO_Loc[SWACNT2 * 4],OFFSET LSWACNT2
  MOV   DWORD PTR Handle_IO_Loc[SWCHB2  * 4],OFFSET LSWCHB2
  MOV   DWORD PTR Handle_IO_Loc[SWBCNT2 * 4],OFFSET LSWBCNT2
  MOV   DWORD PTR Handle_IO_Loc[INTTIM2 * 4],OFFSET LINTTIM2
  MOV   DWORD PTR Handle_IO_Loc[TIM1T2  * 4],OFFSET LTIM1T2
  MOV   DWORD PTR Handle_IO_Loc[TIM2T2  * 4],OFFSET LTIM2T2
  MOV   DWORD PTR Handle_IO_Loc[TIM3T2  * 4],OFFSET LTIM3T2
  MOV   DWORD PTR Handle_IO_Loc[TIM4T2  * 4],OFFSET LTIM4T2

  MOV   BYTE PTR Handle_IO_Set,1
  MOV   EBX,DWORD PTR Game.Save_BX
@L2:
  CMP   EBX,TIM4T2
  JA    GetOut
  CMP   EBX,2Ch
  JA    @NotTIA
  MOV   BYTE PTR Game.Write_TIA,1
@NotTIA:
  SHL   EBX,2
  JMP   DWORD PTR Handle_IO_Loc[EBX]

// -------------------------------------------------------------------

LHMP0:
  CALL  SetP0Motion
  JMP   GetOut

LHMP1:
  CALL  SetP1Motion
  JMP   GetOut

LHMM0:

  MOV   EAX,DWORD PTR Game.HMOVECount
  ADD   EAX,63 - 9
  CMP   AX,WORD PTR Game.TIA_Count
  JNE   @HMM01_A
  MOV   AL,BYTE PTR Game.TIA_Regs[HMM0]
  AND   AL,0F0h
  CMP   AL,70h
  JNE   @HMM01_A
  MOV   AL,BYTE PTR AtariSeg[HMM0]
  AND   AL,0F0h
  CMP   AL,60h
  JNE   @HMM01_A
  MOV   BYTE PTR Game.M0Bug,1
  MOV   BYTE PTR Game.M0BugCount,0
@HMM01_A:

  CALL  SetM0Motion
  JMP   GetOut

LHMM1:

  CALL  SetM1Motion
  JMP   GetOut

LHMBL:

  CALL  SetBLMotion
  JMP   GetOut

LNUSIZ0:

  MOV   AL,BYTE PTR Game.TIA_Regs[NUSIZ0]
  MOV   BYTE PTR Game.OldNUSIZ0,AL

  { Set the emulator latch values -- we can't use the normal TIA_Delay  }
  { method because the delay is greater than 9 pixels and can interfere }
  { with something else, e.g. RealSports Boxing.                        }

  MOV   AL,BYTE PTR Game.TIA_Regs[NUSIZ0]
  MOV   BL,BYTE PTR AtariSeg[NUSIZ0]

  AND   EBX,0FFh
  PUSH  NUSIZ0     // Parm 1 for QueueLatch
  PUSH  EBX        // Parm 2 for QueueLatch

  MOVSX EDX,WORD PTR Game.TIA_Scan

  MOV   EAX,DWORD PTR Game.ObjectLoc[Player0Set * 2]
  MOV   DWORD PTR Game.OldObjectLoc[Player0Set * 2],EAX

  { --------------- }

  PUSH  DWORD PTR Game.ObjectLoc[Player0Set * 2]
  MOVSX EAX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EAX,ECX
  ADD   EAX,ECX
  ADD   EAX,ECX
  ADD   EAX,5
  MOV   DWORD PTR Game.ObjectLoc[Player0Set * 2],EAX

  SUB   EAX,EAX
  CALL  GetPlayerDelay

  POP   DWORD PTR Game.ObjectLoc[Player0Set * 2]

  TEST  EAX,80h
  JZ    @Delay0
@NoDelay0:
  MOVSX EAX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EAX,ECX
  ADD   EAX,ECX
  ADD   EAX,ECX
  JMP   @Delay0Done
@Delay0:
  AND   EAX,7Fh
  MOVSX EBX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EBX,ECX
  ADD   EBX,ECX
  ADD   EBX,ECX
  ADD   EAX,EBX
  JGE   @Delay0Done
  MOV   EAX,EBX
@Delay0Done:
  CMP   EAX,160
  JL    @NoWrap0
  INC   EDX
  SUB   EAX,160
@NoWrap0:
  PUSH  EAX  { Count }
  PUSH  EDX  { Scan  }

  { --------------- }

  PUSH  WORD PTR Game.TIA_Regs[NUSIZ0]
  PUSH  DWORD PTR Game.ObjectLoc[Player0Set * 2]

  MOV   BL,BYTE PTR AtariSeg[NUSIZ0]
  MOV   BYTE PTR Game.TIA_Regs[NUSIZ0],BL

  MOVSX EDX,WORD PTR Game.TIA_Scan

  MOVSX EAX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EAX,ECX
  ADD   EAX,ECX
  ADD   EAX,ECX
  ADD   EAX,5
  MOV   DWORD PTR Game.ObjectLoc[Player0Set * 2],EAX

  SUB   EAX,EAX
  CALL  GetPlayerDelay

  POP   DWORD PTR Game.ObjectLoc[Player0Set * 2]
  POP   WORD PTR Game.TIA_Regs[NUSIZ0]

  TEST  EAX,80h
  JZ    @Delay1
@NoDelay1:
  MOVSX EAX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EAX,ECX
  ADD   EAX,ECX
  ADD   EAX,ECX
  JMP   @Delay1Done
@Delay1:
  AND   EAX,7Fh
  MOVSX EBX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EBX,ECX
  ADD   EBX,ECX
  ADD   EBX,ECX
  ADD   EAX,EBX
  JGE   @Delay1Done
  MOV   EAX,EBX
@Delay1Done:
  CMP   EAX,160
  JL    @NoWrap1
  INC   EDX
  SUB   EAX,160
@NoWrap1:

  { --------------- }

  POP   EBX  { Scan  }
  POP   ECX  { Count }

  CMP   EBX,EDX
  JG    @Copy1
  JL    @NoCopy1
  CMP   EAX,ECX
  JGE   @NoCopy1
@Copy1:
  MOV   EAX,ECX
  MOV   EDX,EBX
@NoCopy1:

  { --------------- }

  PUSH  EDX        // Parm 3 for QueueLatch
  PUSH  EAX        // Parm 4 for QueueLatch
  CALL  QueueLatch

  MOV   AL,BYTE PTR Game.TIA_Regs[NUSIZ0]
  MOV   BYTE PTR AtariSeg[NUSIZ0],AL

  JMP   GetOut

LNUSIZ1:

  MOV   AL,BYTE PTR Game.TIA_Regs[NUSIZ1]
  MOV   BYTE PTR Game.OldNUSIZ1,AL

  { Set the emulator latch values -- we can't use the normal TIA_Delay  }
  { method because the delay is greater than 9 pixels and can interfere }
  { with something else, e.g. RealSports Boxing.                        }

  MOV   AL,BYTE PTR Game.TIA_Regs[NUSIZ1]
  MOV   BL,BYTE PTR AtariSeg[NUSIZ1]

  AND   EBX,0FFh
  PUSH  NUSIZ1     // Parm 1 for QueueLatch
  PUSH  EBX        // Parm 2 for QueueLatch

  MOVSX EDX,WORD PTR Game.TIA_Scan

  MOV   EAX,DWORD PTR Game.ObjectLoc[Player1Set * 2]
  MOV   DWORD PTR Game.OldObjectLoc[Player1Set * 2],EAX

  { --------------- }

  PUSH  DWORD PTR Game.ObjectLoc[Player1Set * 2]
  MOVSX EAX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EAX,ECX
  ADD   EAX,ECX
  ADD   EAX,ECX
  ADD   EAX,5
  MOV   DWORD PTR Game.ObjectLoc[Player1Set * 2],EAX

  MOV   EAX,1
  CALL  GetPlayerDelay

  POP   DWORD PTR Game.ObjectLoc[Player1Set * 2]

  TEST  EAX,80h
  JZ    @Delay0A
@NoDelay0A:
  MOVSX EAX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EAX,ECX
  ADD   EAX,ECX
  ADD   EAX,ECX
  JMP   @Delay0DoneA
@Delay0A:
  AND   EAX,7Fh
  MOVSX EBX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EBX,ECX
  ADD   EBX,ECX
  ADD   EBX,ECX
  ADD   EAX,EBX
  JGE   @Delay0DoneA
  MOV   EAX,EBX
@Delay0DoneA:
  CMP   EAX,160
  JL    @NoWrap0A
  INC   EDX
  SUB   EAX,160
@NoWrap0A:
  PUSH  EAX  { Count }
  PUSH  EDX  { Scan  }

  { --------------- }

  PUSH  WORD PTR Game.TIA_Regs[NUSIZ1]
  PUSH  DWORD PTR Game.ObjectLoc[Player1Set * 2]

  MOV   BL,BYTE PTR AtariSeg[NUSIZ1]
  MOV   BYTE PTR Game.TIA_Regs[NUSIZ1],BL

  MOVSX EDX,WORD PTR Game.TIA_Scan

  MOVSX EAX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EAX,ECX
  ADD   EAX,ECX
  ADD   EAX,ECX
  ADD   EAX,5
  MOV   DWORD PTR Game.ObjectLoc[Player1Set * 2],EAX

  MOV   EAX,1
  CALL  GetPlayerDelay

  POP   DWORD PTR Game.ObjectLoc[Player1Set * 2]
  POP   WORD PTR Game.TIA_Regs[NUSIZ1]

  TEST  EAX,80h
  JZ    @Delay1A
@NoDelay1A:
  MOVSX EAX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EAX,ECX
  ADD   EAX,ECX
  ADD   EAX,ECX
  JMP   @Delay1DoneA
@Delay1A:
  AND   EAX,7Fh
  MOVSX EBX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EBX,ECX
  ADD   EBX,ECX
  ADD   EBX,ECX
  ADD   EAX,EBX
  JGE   @Delay1DoneA
  MOV   EAX,EBX
@Delay1DoneA:
  CMP   EAX,160
  JL    @NoWrap1A
  INC   EDX
  SUB   EAX,160
@NoWrap1A:

  { --------------- }

  POP   EBX  { Scan  }
  POP   ECX  { Count }

  CMP   EBX,EDX
  JG    @Copy1A
  JL    @NoCopy1A
  CMP   EAX,ECX
  JGE   @NoCopy1A
@Copy1A:
  MOV   EAX,ECX
  MOV   EDX,EBX
@NoCopy1A:

  { --------------- }

  PUSH  EDX        // Parm 3 for QueueLatch
  PUSH  EAX        // Parm 4 for QueueLatch
  CALL  QueueLatch

  MOV   AL,BYTE PTR Game.TIA_Regs[NUSIZ1]
  MOV   BYTE PTR AtariSeg[NUSIZ1],AL

  JMP   GetOut

LAUDC0:

  PUSH  EAX
  PUSH  EDX
  PUSH  ECX
  PUSH  EDI
  MOV   AL,BYTE PTR AtariSeg[AUDC0]
  AND   EAX,0Fh
  PUSH  0
  PUSH  EAX
  CALL  SetVoice
  POP   EDI
  POP   ECX
  POP   EDX
  POP   EAX
  JMP   GetOut

LAUDV0:

  PUSH  EAX
  PUSH  EDX
  PUSH  ECX
  PUSH  EDI
  MOV   AL,BYTE PTR AtariSeg[AUDV0]
  AND   EAX,0Fh
  PUSH  0
  PUSH  EAX
  CALL  SetVolume
  POP   EDI
  POP   ECX
  POP   EDX
  POP   EAX
  JMP   GetOut

LAUDF0:

  PUSH  EAX
  PUSH  EDX
  PUSH  ECX
  PUSH  EDI
  MOV   AL,BYTE PTR AtariSeg[AUDF0]
  AND   EAX,1Fh
  PUSH  0
  PUSH  EAX
  CALL  SetFrequency
  POP   EDI
  POP   ECX
  POP   EDX
  POP   EAX
  JMP   GetOut

LAUDC1:

  PUSH  EAX
  PUSH  EDX
  PUSH  ECX
  PUSH  EDI
  MOV   AL,BYTE PTR AtariSeg[AUDC1]
  AND   EAX,0Fh
  PUSH  1
  PUSH  EAX
  CALL  SetVoice
  POP   EDI
  POP   ECX
  POP   EDX
  POP   EAX
  JMP   GetOut

LAUDV1:

  PUSH  EAX
  PUSH  EDX
  PUSH  ECX
  PUSH  EDI
  MOV   AL,BYTE PTR AtariSeg[AUDV1]
  AND   EAX,0Fh
  PUSH  1
  PUSH  EAX
  CALL  SetVolume
  POP   EDI
  POP   ECX
  POP   EDX
  POP   EAX
  JMP   GetOut

LAUDF1:

  PUSH  EAX
  PUSH  EDX
  PUSH  ECX
  PUSH  EDI
  MOV   AL,BYTE PTR AtariSeg[AUDF1]
  AND   EAX,1Fh
  PUSH  1
  PUSH  EAX
  CALL  SetFrequency
  POP   EDI
  POP   ECX
  POP   EDX
  POP   EAX
  JMP   GetOut

LCTRLPF:
  MOVZX EAX,BYTE PTR AtariSeg[CTRLPF]
  MOV   BL,BYTE PTR Game.TIA_Regs[CTRLPF]
  PUSH  CTRLPF     // Parm 1 for QueueLatch
  PUSH  EAX        // Parm 2 for QueueLatch
  MOV   BYTE PTR AtariSeg[CTRLPF],BL

  { Set the emulator latch values -- we can't use the normal TIA_Delay  }
  { method because the delay is greater than 9 pixels and can interfere }
  { with something else, e..g RealSports Boxing.                        }

  MOVSX EAX,WORD PTR Game.TIA_Scan
  PUSH  EAX        // Parm 3 for QueueLatch
  MOVSX EAX,WORD PTR Game.TIA_Count
  MOV   ECX,DWORD PTR Game.AddCycle
  ADD   EAX,ECX
  ADD   EAX,ECX
  ADD   EAX,ECX

  SUB   EBX,EBX
  CMP   EAX,0
  JL    @DoCompare
  MOV   EBX,80
  CMP   EAX,80
  JL    @DoCompare
  MOV   EBX,160
@DoCompare:
  PUSH  EBX        // Parm 4 for QueueLatch
  CALL  QueueLatch
  JMP   GetOut

LVSYNC:
  MOV   BYTE PTR Game.VBLANKOff,0

  MOV   AX,WORD PTR Game.MaxRows
  CMP   WORD PTR Game.TIA_Scan,AX
  JG    @NotGoingOff
  MOV   AL,BYTE PTR AtariSeg[VSYNC]
  TEST  AL,2
  JNZ   @NotGoingOff
  JMP   GetOut
@NotGoingOff:

  CALL  Handle_TIA
  MOV   BYTE PTR Game.Write_TIA,0
  MOVSX EAX,WORD PTR Game.TIA_Scan

  CMP   WORD PTR Game.LastVBLANK,100
  JGE   @NoSetVBLANK
  MOV   WORD PTR Game.LastVBLANK,AX
@NoSetVBLANK:

  { Handle slowdown if necessary }

  TEST  BYTE PTR AtariSeg[VSYNC],2
  JZ    @DoSlow
  TEST  BYTE PTR Game.TIA_Regs[VSYNC],2
  JNZ   @NoSlowDown
@DoSlow:
//  CMP   WORD PTR Config.FrameRate,0
//  JZ    @NoSlowDown
  PUSHAD
  CALL  SlowDown
  POPAD
@NoSlowDown:

  { Check to see if we are streaming to an .AVI file }

  PUSHAD
  CALL  CheckAVIStream
  POPAD

  MOV   AL,BYTE PTR AtariSeg[VSYNC]
  MOV   BYTE PTR Game.TIA_Regs[VSYNC],AL

  { For purposes of delaying the emulator, look at when the VSYNC took }
  { place to determine if the game is NTSC/60Hz or PAL/50Hz            }

  TEST  BYTE PTR Game.LineDelayFirst,0FFh
  JNZ   @AlreadyTested
  CMP   WORD PTR Game.LineDelay,252
  JL    @AlreadyTested                                { Can't tell yet }
  CMP   WORD PTR Game.LineDelay,324
  JG    @AlreadyTested                                { Can't tell yet }
  CMP   WORD PTR Game.LineDelay,272
  JL    @GameIsNTSC                                   { NTSC is at 262 }
  CMP   WORD PTR Game.LineDelay,304
  JG    @GameIsPAL                                    { NTSC is at 262 }
  JMP   @AlreadyTested                                { Can't tell yet }
@GameIsNTSC:
  MOV   WORD PTR Game.LineDelayMax,262
  JMP   @AlreadyTested
@GameIsPAL:
  MOV   WORD PTR Game.LineDelayMax,314
@AlreadyTested:

  { If the VSYNC has arrived, don't force a slowdown next time (assume that }
  { another VSYNC will come.  If one doesn't come, we'll eventually force a }
  { slowdown)                                                               }

  MOV   BYTE PTR Game.LineDelayFirst,0

  { Clear the line delay variable.  Since VSYNC is being asserted, we  }
  { don't need to force the emulator to slow down every 262 scan lines }

  MOV   WORD PTR Game.LineDelay,0

  { Reset the scan line counter }

  MOV   WORD PTR Game.TIA_Scan,-40

  { See if the position was retrieved from the profile file }

  MOV   AX,WORD PTR Game.UserSetPos
  CMP   AX,NoPosSet
  JE    @DoAutoCenter
  ADD   WORD PTR Game.TIA_Scan,AX
  JMP   @NoAutoCenter
@DoAutoCenter:
  MOV   AX,WORD PTR Game.VAdd
  TEST  BYTE PTR AutoCenter,0FFh
  JZ    @NoAutoCenter
  ADD   WORD PTR Game.TIA_Scan,AX
@NoAutoCenter:
  MOV   AX,WORD PTR Game.VUserAdd
  ADD   WORD PTR Game.TIA_Scan,AX
  MOV   WORD PTR Game.LineStart,0

  MOV   EAX,DWORD PTR LocalBufSize
  SUB   EAX,160
  MOV   DWORD PTR Game.Addr,EAX
                               
//  MOV   DWORD PTR Game.Addr,ScnBufSize - 160  // 0
  JMP   GetOut

LENABL:

  MOV   AL,BYTE PTR AtariSeg[ENABL]
  MOV   BL,BYTE PTR Game.TIA_Regs[ENABL]
  MOV   BYTE PTR AtariSeg[ENABL],BL
  MOV   BYTE PTR Game.BallLatch,AL

  JMP   GetOut

LGRP0:
  MOV   AL,BYTE PTR AtariSeg[GRP0]
  MOV   BL,BYTE PTR Game.TIA_Regs[GRP0]
  MOV   BYTE PTR AtariSeg[GRP0],BL
  MOV   BYTE PTR Game.GRP0Latch,AL
  JMP   GetOut

LGRP1:
  MOV   AL,BYTE PTR AtariSeg[GRP1]
  MOV   BL,BYTE PTR Game.TIA_Regs[GRP1]
  MOV   BYTE PTR AtariSeg[GRP1],BL
  MOV   BYTE PTR Game.GRP1Latch,AL
  JMP   GetOut

LVBLANK:

  TEST  BYTE PTR AtariSeg[VBLANK],2
  JZ    @NotLast
  TEST  BYTE PTR Game.TIA_Regs[VBLANK],2
  JNZ   @NotLast

  MOVSX EBX,WORD PTR Game.TIA_Scan
  CMP   EBX,100
  JL    @NotLast

  MOV   WORD PTR Game.LastVBLANK,BX
@NotLast:

  MOV   AH,BYTE PTR AtariSeg[VBLANK]
  TEST  AH,80h
  JZ    @NoGround1

  CMP   BYTE PTR Game.Cart,ctCBS
  JE    @NoGround1
  CMP   BYTE PTR Game.Cart,ctCompumate
  JE    @NoGround1
  MOV   WORD PTR Game.Input_Byte[INPUT0],8
  MOV   WORD PTR Game.Input_Byte[INPUT2],0
@NoGround1:
  TEST  BYTE PTR Game.TIA_Regs[VBLANK],80h
  JZ    @NoGround
  SUB   EBX,EBX

  MOV   DWORD PTR Game.PaddleGround0,EBX
  MOV   DWORD PTR Game.PaddleGround1,EBX
  MOV   DWORD PTR Game.PaddleGround2,EBX
  MOV   DWORD PTR Game.PaddleGround3,EBX

  CMP   BYTE PTR Game.Cart,ctCBS
  JE    @NoGround2
  CMP   BYTE PTR Game.Cart,ctCompumate
  JE    @NoGround2
  MOV   WORD PTR Game.Input_Byte[INPUT0],8
  MOV   WORD PTR Game.Input_Byte[INPUT2],0
@NoGround2:

@NoGround:

  TEST  BYTE PTR Game.TIA_Regs[VBLANK],80h
  JZ    @NoGetControllers
  TEST  BYTE PTR AtariSeg[VBLANK],80h
  JNZ   @NoGetControllers

  MOV   EAX,DWORD PTR Game.OldPaddleGround0
  MOV   DWORD PTR Game.PaddleGround0,EAX
  MOV   EAX,DWORD PTR Game.OldPaddleGround1
  MOV   DWORD PTR Game.PaddleGround1,EAX
  MOV   EAX,DWORD PTR Game.OldPaddleGround2
  MOV   DWORD PTR Game.PaddleGround2,EAX
  MOV   EAX,DWORD PTR Game.OldPaddleGround3
  MOV   DWORD PTR Game.PaddleGround3,EAX

@NoGetControllers:

  AND   AH,40h
  ROL   AH,2
  MOV   BYTE PTR Game.Latched,AH
  TEST  AH,1
  JZ    @NotLatched
@NotLatched:


  TEST  BYTE PTR AtariSeg[VBLANK],2
  JNZ   @NotOff
  TEST  BYTE PTR Game.TIA_Regs[VBLANK],2
  JZ    @NotOff
  CMP   WORD PTR Game.TIA_Scan,-11
  JGE   @NotOff
@Resync:
  MOV   BYTE PTR Game.TopVBLANK,0
@NotOff:

  { Auto-centering routine }

  TEST  BYTE PTR AtariSeg[VBLANK],2
  JNZ   @NoAdd
  TEST  BYTE PTR Game.TIA_Regs[VBLANK],2
  JZ    @NoAdd
  TEST  BYTE PTR Game.VBLANKOff,0FFh
  JNZ   @NoAdd
  MOV   BYTE PTR Game.VBLANKOff,1

  MOV   CX,WORD PTR Game.MaxRows
  SHR   CX,1
  MOV   DX,CX
  MOV   BX,WORD PTR Game.LastVBLANK
  SUB   BX,WORD PTR Game.TIA_Scan
  MOV   AX,WORD PTR Game.MaxRows
  CMP   BX,AX
  JLE   @NoWiden
  ADD   AX,10
  CMP   BX,AX
  JGE   @Average
  MOV   CX,0
  MOV   DX,10

  ADD   DX,WORD PTR Game.VUserAdd
  ADD   CX,WORD PTR Game.VUserAdd

  MOV   BX,WORD PTR Game.TIA_Scan
  CMP   BX,DX
  JG    @Add2
  CMP   BX,CX
  JL    @Add1
  JMP   @NoAdd
@Average:
  SUB   CX,2
  ADD   DX,3
@NoWiden:

  ADD   DX,WORD PTR Game.VUserAdd
  ADD   CX,WORD PTR Game.VUserAdd

  MOV   BX,WORD PTR Game.LastVBLANK
  ADD   BX,WORD PTR Game.TIA_Scan
  SHR   BX,1
  CMP   BX,DX
  JG    @Add2
  CMP   BX,CX
  JL    @Add1
  JMP   @NoAdd

@Add2:
  MOV   WORD PTR Game.VAddAdjust,-1
  JMP   @Add3
@Add1:
  MOV   WORD PTR Game.VAddAdjust,1
@Add3:
  MOV   AX,WORD PTR Game.VAddAdjust
  CMP   WORD PTR Game.VAdd,20
  JGE   @NoAdd
  CMP   WORD PTR Game.VAdd,-20
  JLE   @NoAdd

  TEST  BYTE PTR AutoCenter,0FFh
  JZ    @NoAdd

  ADD   WORD PTR Game.VAdd,AX
@NoAdd:
  JMP   GetOut

LWSYNC:
    SUB   EDX,EDX
    MOV   EAX,160
    SUB   AX,WORD PTR Game.TIA_Count
    CWDE
    MOV   DL,BYTE PTR Div3[EAX]
    SUB   EDX,DWORD PTR Game.AddCycle
    MOVSX EAX,WORD PTR Game.TIA_Count
    MOV   ECX,DWORD PTR Game.AddCycle
    ADD   EAX,ECX
    ADD   EAX,ECX
    ADD   EAX,ECX
    CMP   EAX,160
    JLE   @NoExtraLine

    ADD   EDX,76                           // Used for determining paddle positions

    PUSHAD
    MOV   WORD PTR Game.TIA_Count,160      // Finish current line
    CALL  Handle_TIA
    POPAD
    MOV   WORD PTR Game.Old_TIA_Count,0    // Do another line (pending)

    MOVSX EAX,WORD PTR Game.TIA_Scan       // Move downward a scan line
    CMP   EAX,DWORD PTR MaxScan
    JGE   @DoneLines
    INC   WORD PTR Game.TIA_Scan
@DoneLines:

    // Go to the next scan line

    MOVSX ECX,WORD PTR Game.TIA_Scan
    CMP   CX,WORD PTR Game.MaxRows
    JAE   @Negative
    MOV   EAX,ECX
    SHL   EAX,5
    SHL   ECX,7
    ADD   EAX,ECX
    MOV   ECX,DWORD PTR LocalBufSize
    SUB   ECX,160
    SUB   ECX,EAX
    MOV   EAX,ECX
@SetAddress:
    MOV   DWORD PTR Game.Addr,EAX
    MOV   WORD PTR Game.LineStart,AX
@Negative:

    ADD   DWORD PTR Game.TimerElapsed,76
    MOV   EAX,DWORD PTR Game.TimerX
    ADD   DWORD PTR Game.TimerElapsed,EAX
    MOV   DWORD PTR Game.TimerX,0

@NoExtraLine:

    CMP   BYTE PTR Game.Controller,crPaddle
    JNE   @NoPaddle

    TEST  BYTE PTR AtariSeg[VBLANK],80h
    JNZ   @NoPaddle

    MOV   EAX,EDX

    CMP   BYTE PTR Game.Cart,ctCompumate
    JE    @NoPaddle
    TEST  BYTE PTR Game.Input_Byte[INPUT0],80h
    JNZ   @NoPaddle0
    SUB   DWORD PTR Game.PaddleGround0,EAX
    JNC   @NoPaddle0
    MOV   BYTE PTR Game.Input_Byte[INPUT0],80h
@NoPaddle0:

    TEST  BYTE PTR Game.Input_Byte[INPUT1],80h
    JNZ   @NoPaddle1
    SUB   DWORD PTR Game.PaddleGround1,EAX
    JNC   @NoPaddle1
    MOV   BYTE PTR Game.Input_Byte[INPUT1],80h
@NoPaddle1:

    TEST  BYTE PTR Game.Input_Byte[INPUT2],80h
    JNZ   @NoPaddle2
    SUB   DWORD PTR Game.PaddleGround2,EAX
    JNC   @NoPaddle2
    MOV   BYTE PTR Game.Input_Byte[INPUT2],80h
@NoPaddle2:

    TEST  BYTE PTR Game.Input_Byte[INPUT3],80h
    JNZ   @NoPaddle3
    SUB   DWORD PTR Game.PaddleGround3,EAX
    JNC   @NoPaddle3
    MOV   BYTE PTR Game.Input_Byte[INPUT3],80h
@NoPaddle3:
@NoPaddle:
  MOV   WORD PTR Game.TIA_Count,160
  MOV   BYTE PTR Game.Write_TIA,2
  JMP   GetOut

LRSYNC:
  JMP   GetOut

LRESP0:

  MOVSX EAX,WORD PTR Game.ResetOfs
  MOV   DWORD PTR Game.ResetOffset[0],EAX
  ADD   WORD PTR Game.ResetOfs,3

  MOV   EAX,DWORD PTR Game.ObjectLoc[Player0Set * 2]
  MOV   DWORD PTR Game.OldObjectLoc[Player0Set * 2],EAX
  OR    BYTE PTR Game.ObjectSet,Player0Set
  JMP   GetOut

LRESP1:

  MOVSX EAX,WORD PTR Game.ResetOfs
  MOV   DWORD PTR Game.ResetOffset[4],EAX
  ADD   WORD PTR Game.ResetOfs,3

  MOV   EAX,DWORD PTR Game.ObjectLoc[Player1Set * 2]
  MOV   DWORD PTR Game.OldObjectLoc[Player1Set * 2],EAX
  OR    BYTE PTR Game.ObjectSet,Player1Set
  JMP   GetOut

LRESM0:

  TEST  BYTE PTR AtariSeg[RESMP0],2
  JZ    @Missile0Ok
  MOV   AL,BYTE PTR Game.ObjectLoc[Player0Set * 2]
  MOV   AH,BYTE PTR Game._Player0Size
  SHR   AH,1
  ADD   AL,AH

  AND   EAX,0FFh

  CMP   EAX,160
  JB    @M0Ok1A
  SUB   EAX,160
@M0Ok1A:
  CWDE
  MOV   DWORD PTR Game.ObjectLoc[Missile0Set * 2],EAX
  JMP   GetOut
@Missile0Ok:

  MOVSX EAX,WORD PTR Game.ResetOfs
  MOV   DWORD PTR Game.ResetOffset[8],EAX
  ADD   WORD PTR Game.ResetOfs,3

  MOV   EAX,DWORD PTR Game.ObjectLoc[Missile0Set * 2]
  MOV   DWORD PTR Game.OldObjectLoc[Missile0Set * 2],EAX

  OR    BYTE PTR Game.ObjectSet,Missile0Set
  JMP   GetOut

LRESM1:

  TEST  BYTE PTR AtariSeg[RESMP1],2
  JZ    @Missile1Ok
  MOV   AL,BYTE PTR Game.ObjectLoc[Player1Set * 2]
  MOV   AH,BYTE PTR Game._Player1Size
  SHR   AH,1
  ADD   AL,AH

  AND   EAX,0FFh
  CMP   EAX,160
  JB    @M1Ok1A
  SUB   EAX,160
@M1Ok1A:
  CWDE
  MOV   DWORD PTR Game.ObjectLoc[Missile1Set * 2],EAX
  JMP   GetOut
@Missile1Ok:

  MOVSX EAX,WORD PTR Game.ResetOfs
  MOV   DWORD PTR Game.ResetOffset[12],EAX
  ADD   WORD PTR Game.ResetOfs,3

  MOV   EAX,DWORD PTR Game.ObjectLoc[Missile1Set * 2]
  MOV   DWORD PTR Game.OldObjectLoc[Missile1Set * 2],EAX

  OR    BYTE PTR Game.ObjectSet,Missile1Set
  JMP   GetOut

LRESBL:

  MOVSX EAX,WORD PTR Game.ResetOfs
  MOV   DWORD PTR Game.ResetOffset[16],EAX
  ADD   WORD PTR Game.ResetOfs,3

  MOV   EAX,DWORD PTR Game.ObjectLoc[BallSet * 2]
  MOV   DWORD PTR Game.OldObjectLoc[BallSet * 2],EAX

  OR    BYTE PTR Game.ObjectSet,BallSet
  JMP   GetOut

LHMCLR:
  SUB   EAX,EAX
  MOV   DWORD PTR AtariSeg[HMP0],EAX
  MOV   BYTE PTR AtariSeg[HMBL],AL

  CALL  SetP0Motion
  CALL  SetP1Motion
  CALL  SetM0Motion
  CALL  SetM1Motion
  CALL  SetBLMotion

  MOV   DWORD PTR Game.TIA_Regs[HMP0],EAX
  MOV   BYTE PTR Game.TIA_Regs[HMBL],AL
  MOV   BYTE PTR Game.Write_TIA,0

  MOV   EAX,DWORD PTR Game.HMOVECount
  ADD   EAX,60 - 9
  CMP   AX,WORD PTR Game.TIA_Count
  JNE   @HMM01A
  TEST  BYTE PTR Game.DoHMOVE,0FFh
  JZ    @HMM01A
  MOV   BYTE PTR Game.M0Bug,1
  MOV   BYTE PTR Game.M0BugCount,0
@HMM01A:
  JMP   GetOut

LSWCHA1:

  CMP   BYTE PTR Game.Cart,ctCompumate
  JE    @SkipCM1
  MOV   AL,BYTE PTR AtariSeg[SWACNT1]
  MOV   BL,BYTE PTR AtariSeg[SWCHA1]
  MOV   BH,BYTE PTR AtariSeg[SWCHA2]
  MOV   CX,BX
  MOV   AH,AL
  NOT   AL
  AND   BH,AL
  AND   BL,AH
  OR    BH,BL
  MOV   BYTE PTR AtariSeg[SWCHA2],BH
  AND   CL,AH
  AND   CH,AL
  OR    CL,CH
  MOV   BYTE PTR AtariSeg[SWCHA1],CL

  PUSHAD
  PUSHF
  CALL  WriteToPortA
  POPF
  POPAD
@SkipCM1:

  { If we're writing to this port, we must be attempting to use the  }
  { keyboard controllers.  Turn on the respective bits of INPUT0/1/4 }

  JMP   GetOut

LSWACNT1:

  MOV   AL,BYTE PTR AtariSeg[SWACNT1]
  MOV   BYTE PTR AtariSeg[SWACNT2],AL

  PUSHAD
  PUSHF
  CALL  SetReadMask
  POPF
  POPAD
  
  JMP   GetOut

LSWCHB1:

  MOV   AL,BYTE PTR AtariSeg[SWCHB2]
  MOV   BYTE PTR AtariSeg[SWCHB1],AL
  JMP   GetOut

LSWBCNT1:

  MOV   AL,BYTE PTR AtariSeg[SWBCNT2]
  MOV   BYTE PTR AtariSeg[SWBCNT1],AL
  JMP   GetOut

LINTTIM1:
  MOV   AL,BYTE PTR AtariSeg[INTTIM2]
  MOV   BYTE PTR AtariSeg[INTTIM1],AL
  JMP   GetOut

LINTTIM3:

  MOV   BYTE PTR AtariSeg[INTTIM3],0
  JMP   GetOut

LTIM1T1:

  MOV   AL,BYTE PTR AtariSeg[TIM1T1]
  MOV   BYTE PTR AtariSeg[TIM1T2],AL
  MOV   BYTE PTR AtariSeg[INTTIM1],AL
  MOV   BYTE PTR Game.TimerDone,0
  MOV   DWORD PTR Game.TimerInterval,1
  MOV   DWORD PTR Game.TimerShift,0
  MOV   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerValue,EAX
  SUB   EAX,EAX
  MOV   DWORD PTR Game.TimerElapsed,EAX

  MOVZX EAX,BYTE PTR AtariSeg[INTTIM1]
  MOV   DWORD PTR Game.OrigTimer,EAX
  MOVSX EBX,WORD PTR Game.TIA_Count
  ADD   EBX,68
  MOVZX EAX,BYTE PTR Div3[EBX]
  ADD   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerX,EAX
  JMP   GetOut

LTIM2T1:

  MOV   AL,BYTE PTR AtariSeg[TIM2T1]
  MOV   BYTE PTR AtariSeg[TIM2T2],AL
  MOV   BYTE PTR AtariSeg[INTTIM1],AL
  MOV   BYTE PTR Game.TimerDone,0
  MOV   DWORD PTR Game.TimerInterval,8
  MOV   DWORD PTR Game.TimerShift,3
  MOV   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerValue,EAX
  SUB   EAX,EAX
  MOV   DWORD PTR Game.TimerElapsed,EAX

  MOVZX EAX,BYTE PTR AtariSeg[INTTIM1]
  MOV   DWORD PTR Game.OrigTimer,EAX
  MOVSX EBX,WORD PTR Game.TIA_Count
  ADD   EBX,68
  MOVZX EAX,BYTE PTR Div3[EBX]
  ADD   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerX,EAX
  JMP   GetOut

LTIM3T1:

  MOV   AL,BYTE PTR AtariSeg[TIM3T1]
  MOV   BYTE PTR AtariSeg[TIM3T2],AL
  MOV   BYTE PTR AtariSeg[INTTIM1],AL
  MOV   BYTE PTR Game.TimerDone,0
  MOV   DWORD PTR Game.TimerInterval,64
  MOV   DWORD PTR Game.TimerShift,6
  MOV   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerValue,EAX
  SUB   EAX,EAX
  MOV   DWORD PTR Game.TimerElapsed,EAX

  MOVZX EAX,BYTE PTR AtariSeg[INTTIM1]
  MOV   DWORD PTR Game.OrigTimer,EAX
  MOVSX EBX,WORD PTR Game.TIA_Count
  ADD   EBX,68
  MOVZX EAX,BYTE PTR Div3[EBX]
  ADD   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerX,EAX
  JMP   GetOut

LTIM4T1:

  MOV   AL,BYTE PTR AtariSeg[TIM4T1]
  MOV   BYTE PTR AtariSeg[TIM4T2],AL
  MOV   BYTE PTR AtariSeg[INTTIM1],AL
  MOV   BYTE PTR Game.TimerDone,0
  MOV   DWORD PTR Game.TimerInterval,1024
  MOV   DWORD PTR Game.TimerShift,10
  MOV   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerValue,EAX
  SUB   EAX,EAX
  MOV   DWORD PTR Game.TimerElapsed,EAX

  MOVZX EAX,BYTE PTR AtariSeg[INTTIM1]
  MOV   DWORD PTR Game.OrigTimer,EAX
  MOVSX EBX,WORD PTR Game.TIA_Count
  ADD   EBX,68
  MOVZX EAX,BYTE PTR Div3[EBX]
  ADD   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerX,EAX
  JMP   GetOut

LSWCHA2:

  CMP   BYTE PTR Game.Cart,ctCompumate
  JE    @SkipCM2
  MOV   AL,BYTE PTR AtariSeg[SWACNT1]
  MOV   BL,BYTE PTR AtariSeg[SWCHA2]
  MOV   BH,BYTE PTR AtariSeg[SWCHA1]
  MOV   CX,BX
  MOV   AH,AL
  NOT   AL
  AND   BH,AL
  AND   BL,AH
  OR    BH,BL
  MOV   BYTE PTR AtariSeg[SWCHA1],BH
  AND   CL,AH
  AND   CH,AL
  OR    CL,CH
  MOV   BYTE PTR AtariSeg[SWCHA2],CL

  PUSHAD
  PUSHF
  CALL  WriteToPortA
  POPF
  POPAD
@SkipCM2:  

  { If we're writing to this port, we must be attempting to use the  }
  { keyboard controllers.  Turn on the respective bits of INPUT0/1/4 }

  JMP   GetOut

LSWACNT2:

  MOV   AL,BYTE PTR AtariSeg[SWACNT2]
  MOV   BYTE PTR AtariSeg[SWACNT1],AL

  PUSHAD
  PUSHF
  CALL  SetReadMask
  POPF
  POPAD
  JMP   GetOut

LSWCHB2:

  MOV   AL,BYTE PTR AtariSeg[SWCHB1]
  MOV   BYTE PTR AtariSeg[SWCHB2],AL
  JMP   GetOut

LSWBCNT2:

  MOV   AL,BYTE PTR AtariSeg[SWBCNT1]
  MOV   BYTE PTR AtariSeg[SWBCNT2],AL
  JMP   GetOut

LINTTIM2:

  MOV   AL,BYTE PTR AtariSeg[INTTIM2]
  MOV   BYTE PTR AtariSeg[INTTIM1],AL
  JMP   GetOut

LTIM1T2:

  MOV   AL,BYTE PTR AtariSeg[TIM1T2]
  MOV   BYTE PTR AtariSeg[TIM1T1],AL
  MOV   BYTE PTR AtariSeg[INTTIM1],AL
  MOV   BYTE PTR Game.TimerDone,0
  MOV   DWORD PTR Game.TimerInterval,1
  MOV   DWORD PTR Game.TimerShift,0
  MOV   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerValue,EAX
  SUB   EAX,EAX
  MOV   DWORD PTR Game.TimerElapsed,EAX

  MOVZX EAX,BYTE PTR AtariSeg[INTTIM1]
  MOV   DWORD PTR Game.OrigTimer,EAX
  MOVSX EBX,WORD PTR Game.TIA_Count
  ADD   EBX,68
  MOVZX EAX,BYTE PTR Div3[EBX]
  ADD   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerX,EAX
  JMP   GetOut

LTIM2T2:

  MOV   AL,BYTE PTR AtariSeg[TIM2T2]
  MOV   BYTE PTR AtariSeg[TIM2T1],AL
  MOV   BYTE PTR AtariSeg[INTTIM1],AL
  MOV   BYTE PTR Game.TimerDone,0
  MOV   DWORD PTR Game.TimerInterval,8
  MOV   DWORD PTR Game.TimerShift,3
  MOV   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerValue,EAX
  SUB   EAX,EAX
  MOV   DWORD PTR Game.TimerElapsed,EAX

  MOVZX EAX,BYTE PTR AtariSeg[INTTIM1]
  MOV   DWORD PTR Game.OrigTimer,EAX
  MOVSX EBX,WORD PTR Game.TIA_Count
  ADD   EBX,68
  MOVZX EAX,BYTE PTR Div3[EBX]
  ADD   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerX,EAX
  JMP   GetOut

LTIM3T2:

  MOV   AL,BYTE PTR AtariSeg[TIM3T2]
  MOV   BYTE PTR AtariSeg[TIM3T1],AL
  MOV   BYTE PTR AtariSeg[INTTIM1],AL
  MOV   BYTE PTR Game.TimerDone,0
  MOV   DWORD PTR Game.TimerInterval,64
  MOV   DWORD PTR Game.TimerShift,6
  MOV   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerValue,EAX
  SUB   EAX,EAX
  MOV   DWORD PTR Game.TimerElapsed,EAX

  MOVZX EAX,BYTE PTR AtariSeg[INTTIM1]
  MOV   DWORD PTR Game.OrigTimer,EAX
  MOVSX EBX,WORD PTR Game.TIA_Count
  ADD   EBX,68
  MOVZX EAX,BYTE PTR Div3[EBX]
  ADD   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerX,EAX
  JMP   GetOut

LTIM4T2:

  MOV   AL,BYTE PTR AtariSeg[TIM4T2]
  MOV   BYTE PTR AtariSeg[TIM4T1],AL
  MOV   BYTE PTR AtariSeg[INTTIM1],AL
  MOV   BYTE PTR Game.TimerDone,0
  MOV   DWORD PTR Game.TimerInterval,1024
  MOV   DWORD PTR Game.TimerShift,10
  MOV   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerValue,EAX
  SUB   EAX,EAX
  MOV   DWORD PTR Game.TimerElapsed,EAX

  MOVZX EAX,BYTE PTR AtariSeg[INTTIM1]
  MOV   DWORD PTR Game.OrigTimer,EAX
  MOVSX EBX,WORD PTR Game.TIA_Count
  ADD   EBX,68
  MOVZX EAX,BYTE PTR Div3[EBX]
  ADD   EAX,DWORD PTR Game.AddCycle
  NEG   EAX
  MOV   DWORD PTR Game.TimerX,EAX

GetOut:
  POPAD
End; { Handle_IO }

Procedure Handle_IO_After; Assembler;
{ ------------------------------------------------------------------------- }
{ On entry:                                                                 }
{ EBX = Game.Save_BX                                                        }
{ ------------------------------------------------------------------------- }
Label LVBLANK,LGRP0,LGRP1,LENAM0,LENAM1,LENABL,LRESMP0,LRESMP1,LVDELP0,LVDELP1,
      LCOLUP0,LCOLUP1,LCOLUPF,LCOLUBK,LCTRLPF,LREFP0,LREFP1,
      LCXCLR,LHMOVE,LWSYNC,GetOut;
Asm
  PUSHAD

  TEST  BYTE PTR Handle_IO_Set_After,0FFh
  JNZ   @L2

  MOV   EAX,OFFSET GetOut
  MOV   ECX,CXCLR
  SUB   EBX,EBX
@L1:
  MOV   DWORD PTR Handle_IO_Loc_After[EBX],EAX
  ADD   EBX,4
  LOOP  @L1

  MOV   DWORD PTR Handle_IO_Loc_After[VBLANK  * 4],OFFSET LVBLANK
  MOV   DWORD PTR Handle_IO_Loc_After[GRP0    * 4],OFFSET LGRP0
  MOV   DWORD PTR Handle_IO_Loc_After[GRP1    * 4],OFFSET LGRP1
  MOV   DWORD PTR Handle_IO_Loc_After[ENAM0   * 4],OFFSET LENAM0
  MOV   DWORD PTR Handle_IO_Loc_After[ENAM1   * 4],OFFSET LENAM1
  MOV   DWORD PTR Handle_IO_Loc_After[ENABL   * 4],OFFSET LENABL
  MOV   DWORD PTR Handle_IO_Loc_After[RESMP0  * 4],OFFSET LRESMP0
  MOV   DWORD PTR Handle_IO_Loc_After[RESMP1  * 4],OFFSET LRESMP1
  MOV   DWORD PTR Handle_IO_Loc_After[COLUP0  * 4],OFFSET LCOLUP0
  MOV   DWORD PTR Handle_IO_Loc_After[COLUP1  * 4],OFFSET LCOLUP1
  MOV   DWORD PTR Handle_IO_Loc_After[COLUPF  * 4],OFFSET LCOLUPF
  MOV   DWORD PTR Handle_IO_Loc_After[COLUBK  * 4],OFFSET LCOLUBK
  MOV   DWORD PTR Handle_IO_Loc_After[CTRLPF  * 4],OFFSET LCTRLPF
  MOV   DWORD PTR Handle_IO_Loc_After[REFP0   * 4],OFFSET LREFP0
  MOV   DWORD PTR Handle_IO_Loc_After[REFP1   * 4],OFFSET LREFP1
  MOV   DWORD PTR Handle_IO_Loc_After[HMOVE   * 4],OFFSET LHMOVE
  MOV   DWORD PTR Handle_IO_Loc_After[CXCLR   * 4],OFFSET LCXCLR
  MOV   DWORD PTR Handle_IO_Loc_After[WSYNC   * 4],OFFSET LWSYNC
  MOV   DWORD PTR Handle_IO_Loc_After[VDELP0  * 4],OFFSET LVDELP0
  MOV   DWORD PTR Handle_IO_Loc_After[VDELP1  * 4],OFFSET LVDELP1

  MOV   BYTE PTR Handle_IO_Set_After,1
  MOV   EBX,DWORD PTR Game.Save_BX
@L2:
  CMP   EBX,CXCLR
  JA    GetOut
  SHL   EBX,2
  JMP   DWORD PTR Handle_IO_Loc_After[EBX]

LWSYNC:
    TEST  BYTE PTR Game.M0Bug,0FFh
    JZ    @NoM0Bug
    INC   BYTE PTR Game.M0BugCount
    AND   BYTE PTR Game.M0BugCount,3
    MOV   AL,BYTE PTR AtariSeg[ENAM0]
    CMP   BYTE PTR Game.M0BugCount,3
    JNE   @LWSYNC1
    SUB   AL,AL
@LWSYNC1:
    AND   BYTE PTR Game.DispJump,0EFh
    TEST  AL,2
    JZ    @LWSYNC2
    TEST  BYTE PTR AtariSeg[RESMP0],2
    JNZ   @LWSYNC2
    OR    BYTE PTR Game.DispJump,10h
@LWSYNC2:

    MOV   BL,BYTE PTR Game.TIA_Regs[NUSIZ0]
    CMP   BYTE PTR Game.M0BugCount,2
    JNE   @LWSYNC3
    MOV   AL,BL
    SHR   AL,4
    AND   AL,3
    INC   AL
    CMP   AL,4
    JB    @LWSYNC4
    MOV   AL,3
@LWSYNC4:
    SHL   AL,4
    AND   BL,0CFh
    OR    BL,AL
@LWSYNC3:
    MOV   AL,BL
    MOV   AH,AL
    SHR   AL,1
    AND   EAX,0718h
    OR    AL,AH
    SUB   AH,AH
    SHL   EAX,7
    MOV   DWORD PTR Game.Missile0SizeNum,EAX
    MOV   DWORD PTR Game.OldMissile0SizeNum,EAX

    MOV   ESI,EBX
    SHR   ESI,4
    AND   ESI,3
    MOVZX ECX,BYTE PTR MissileSize[ESI]
    MOV   WORD PTR Game.Missile0Size,CX
    MOV   EDX,ECX
    DEC   ECX
    SHR   ECX,1
    MOV   DWORD PTR Game.Missile0Adjust,ECX
    SUB   EDX,160
    MOV   DWORD PTR Game.Missile0Size160,EDX

    SUB   EBX,EBX
    MOV   BL,BYTE PTR Game.M0BugCount
    SHL   EBX,2
    MOV   EAX,DWORD PTR M0BugMove[EBX]
    SUB   DWORD PTR Game.ObjectLoc[Missile0Set * 2],EAX
    CMP   DWORD PTR Game.ObjectLoc[Missile0Set * 2],0
    JGE   @NoM0Bug
    ADD   DWORD PTR Game.ObjectLoc[Missile0Set * 2],160
@NoM0Bug:
    CMP   WORD PTR Game.TIA_Count,8
    JL    @NoClearHMOVE
    MOV   BYTE PTR Game.DoHMOVE,0
    MOV   BYTE PTR Game.OldDoHMOVE,0
@NoClearHMOVE:
    JMP   GetOut

LVDELP0:
  TEST  BYTE PTR AtariSeg[VDELP0],1
  JNZ   GetOut
  MOV   BL,BYTE PTR Game.GRP0Latch
  MOV   BYTE PTR AtariSeg[GRP0],BL
  MOV   BYTE PTR Game.TIA_Regs[GRP0],BL

  AND   BYTE PTR Game.DispJump,0DFh
  TEST  BL,0FFh
  JZ    @LVDELP0A
  OR    BYTE PTR Game.DispJump,20h
@LVDELP0A:
  JMP   GetOut

LVDELP1:
  TEST  BYTE PTR AtariSeg[VDELP1],1
  JNZ   GetOut
  MOV   BL,BYTE PTR Game.GRP1Latch
  MOV   BYTE PTR AtariSeg[GRP1],BL
  MOV   BYTE PTR Game.TIA_Regs[GRP1],BL

  AND   BYTE PTR Game.DispJump,0F7h
  TEST  BL,0FFh
  JZ    @LVDELP1A
  OR    BYTE PTR Game.DispJump,8
@LVDELP1A:
  JMP   GetOut

LCXCLR:
  SUB   EAX,EAX
  MOV   DWORD PTR Game.Input_Byte[0],EAX
  MOV   DWORD PTR Game.Input_Byte[4],EAX
  MOV   AL,BYTE PTR AtariSeg[CXCLR]
  MOV   BYTE PTR Game.TIA_Regs[CXCLR],AL
  JMP   GetOut

LVBLANK:
  TEST  BYTE PTR AtariSeg[VBLANK],80h
  JNZ   @NoCheckControllers
  CMP   BYTE PTR Game.Controller,crKeyboard
  JE    @CheckControllers
  CMP   BYTE PTR Game.Controller,crVTP
  JE    @CheckControllers
  JMP   @NoCheckControllers
@CheckControllers:

@NoCheckControllers:
  TEST  BYTE PTR AtariSeg[VBLANK],80h
  JZ    @NoGround
  CMP   BYTE PTR Game.Cart,ctCBS
  JE    @NoGround
  CMP   BYTE PTR Game.Cart,ctCompumate
  JE    @NoGround
  MOV   WORD PTR Game.Input_Byte[INPUT0],8
  MOV   WORD PTR Game.Input_Byte[INPUT2],0
@NoGround:

  MOVSX EBX,WORD PTR Game.TIA_Scan
  TEST  BYTE PTR AtariSeg[VBLANK],2
  JZ    @NoClear
@ClearExit:
  MOV   DWORD PTR Game.LastScan,EBX
@NoClear:
  JMP   GetOut

LGRP0:
  TEST  BYTE PTR AtariSeg[VDELP0],1
  JNZ   @DelayedP0
@NotDelayedP0:
  MOV   AL,BYTE PTR Game.GRP0Latch
  MOV   BYTE PTR AtariSeg[GRP0],AL
  MOV   BYTE PTR Game.TIA_Regs[GRP0],AL
@DelayedP0:
  MOV   BL,BYTE PTR Game.GRP1Latch
  MOV   BYTE PTR AtariSeg[GRP1],BL
  MOV   BYTE PTR Game.TIA_Regs[GRP1],BL
  AND   BYTE PTR Game.DispJump,0F7h
  TEST  BL,0FFh
  JZ    @LGRP0B
  OR    BYTE PTR Game.DispJump,8
@LGRP0B:
  AND   BYTE PTR Game.DispJump,0DFh
  TEST  BYTE PTR Game.TIA_Regs[GRP0],0FFh  { New }
  JZ    @LGRP0A
  OR    BYTE PTR Game.DispJump,20h
@LGRP0A:
  JMP   GetOut

LGRP1:
  TEST  BYTE PTR AtariSeg[VDELP1],1
  JNZ   @DelayedP1
@NotDelayedP1:
  MOV   AL,BYTE PTR Game.GRP1Latch
  MOV   BYTE PTR AtariSeg[GRP1],AL
  MOV   BYTE PTR Game.TIA_Regs[GRP1],AL
@DelayedP1:
  MOV   BL,BYTE PTR Game.GRP0Latch
  MOV   BYTE PTR AtariSeg[GRP0],BL
  MOV   BYTE PTR Game.TIA_Regs[GRP0],BL
  AND   BYTE PTR Game.DispJump,0DFh
  TEST  BL,0FFh
  JZ    @LGRP1B
  OR    BYTE PTR Game.DispJump,20h
@LGRP1B:
  MOV   BL,BYTE PTR Game.BallLatch
  MOV   BYTE PTR AtariSeg[ENABL],BL
  MOV   BYTE PTR Game.TIA_Regs[ENABL],BL

  AND   BYTE PTR Game.DispJump,0FDh
  TEST  BL,2h
  JZ    @LGRP1C
  OR    BYTE PTR Game.DispJump,2h
@LGRP1C:

  AND   BYTE PTR Game.DispJump,0F7h
  TEST  BYTE PTR Game.TIA_Regs[GRP1],0FFh
  JZ    @LGRP1A
  OR    BYTE PTR Game.DispJump,8
@LGRP1A:
  JMP   GetOut

LENAM0:

  AND   BYTE PTR Game.DispJump,0EFh
  TEST  BYTE PTR AtariSeg[ENAM0],2
  JZ    @LENAM0A
  TEST  BYTE PTR AtariSeg[RESMP0],2
  JNZ   @LENAM0A
  OR    BYTE PTR Game.DispJump,10h
@LENAM0A:
  JMP   GetOut

LENAM1:
  AND   BYTE PTR Game.DispJump,0FBh
  TEST  BYTE PTR AtariSeg[ENAM1],2
  JZ    @LENAM1A
  TEST  BYTE PTR AtariSeg[RESMP1],2
  JNZ   @LENAM1A
  OR    BYTE PTR Game.DispJump,4
@LENAM1A:
  JMP   GetOut

LENABL:

  TEST  BYTE PTR AtariSeg[VDELBL],1
  JNZ   @DelayedBL
  MOV   AL,BYTE PTR Game.BallLatch
  MOV   BYTE PTR AtariSeg[ENABL],AL
  MOV   BYTE PTR Game.TIA_Regs[ENABL],AL
@DelayedBL:
  AND   BYTE PTR Game.DispJump,0FDh
  TEST  BYTE PTR AtariSeg[ENABL],2
  JZ    @LENABLA
  OR    BYTE PTR Game.DispJump,2
@LENABLA:
  JMP   GetOut

LRESMP0:

  TEST  BYTE PTR AtariSeg[RESMP0],2
  JZ    @Missile0Ok
  MOV   AL,BYTE PTR Game.ObjectLoc[Player0Set * 2]
  MOV   AH,BYTE PTR Game._Player0Size
  SHR   AH,1
  ADD   AL,AH

  AND   EAX,0FFh
  CMP   EAX,160
  JB    @M0Ok1B
  SUB   EAX,160
@M0Ok1B:
  MOV   DWORD PTR Game.ObjectLoc[Missile0Set * 2],EAX
@Missile0Ok:

  AND   BYTE PTR Game.DispJump,0EFh
  TEST  BYTE PTR AtariSeg[ENAM0],2
  JZ    @LRESMP0A
  TEST  BYTE PTR AtariSeg[RESMP0],2
  JNZ   @LRESMP0A
  OR    BYTE PTR Game.DispJump,10h
@LRESMP0A:
  JMP   GetOut

LRESMP1:
  TEST  BYTE PTR AtariSeg[RESMP1],2
  JZ    @Missile1Ok
  MOV   AL,BYTE PTR Game.ObjectLoc[Player1Set * 2]
  MOV   AH,BYTE PTR Game._Player1Size
  SHR   AH,1
  ADD   AL,AH

  AND   EAX,0FFh
  CMP   EAX,160
  JB    @M1Ok1B
  SUB   EAX,160
@M1Ok1B:
  MOV   DWORD PTR Game.ObjectLoc[Missile1Set * 2],EAX
@Missile1Ok:

  AND   BYTE PTR Game.DispJump,0FBh
  TEST  BYTE PTR AtariSeg[ENAM1],2
  JZ    @LRESMP1A
  TEST  BYTE PTR AtariSeg[RESMP1],2
  JNZ   @LRESMP1A
  OR    BYTE PTR Game.DispJump,4
@LRESMP1A:
  JMP   GetOut

LCOLUP0:
  MOV   AL,BYTE PTR Game.TIA_Regs[COLUP0]
  MOV   AH,AL
  MOV   WORD PTR Game.ColorLum[0],AX
  MOV   BX,WORD PTR Game.ColorLum[4]
  MOV   DX,WORD PTR Game.ColorLum[2]
  TEST  BYTE PTR Game.TIA_Regs[CTRLPF],2
  JZ    @LP01

  MOV   CL,BYTE PTR Game.TIA_Regs[CTRLPF]
  AND   CL,0Fh
  CMP   CL,0Fh
  JZ    @LP01

  MOV   WORD PTR Game.CLW,AX
  MOV   WORD PTR Game.CLW[2],AX
  MOV   WORD PTR Game.CRW,DX
  MOV   WORD PTR Game.CRW[2],DX
  JMP   @LP02
@LP01:
  MOV   WORD PTR Game.CLW,BX
  MOV   WORD PTR Game.CLW[2],BX
  MOV   WORD PTR Game.CRW,BX
  MOV   WORD PTR Game.CRW[2],BX
@LP02:
  JMP   GetOut

LCOLUP1:

  MOV   AL,BYTE PTR Game.TIA_Regs[COLUP1]
  MOV   AH,AL
  MOV   WORD PTR Game.ColorLum[2],AX
  MOV   BX,WORD PTR Game.ColorLum[4]
  MOV   CX,WORD PTR Game.ColorLum[0]
  TEST  BYTE PTR Game.TIA_Regs[CTRLPF],2
  JZ    @LP11

  MOV   DL,BYTE PTR Game.TIA_Regs[CTRLPF]
  AND   DL,0Fh
  CMP   DL,0Fh
  JZ    @LP11

  MOV   WORD PTR Game.CLW,CX
  MOV   WORD PTR Game.CLW[2],CX
  MOV   WORD PTR Game.CRW,AX
  MOV   WORD PTR Game.CRW[2],AX
  JMP   @LP12
@LP11:
  MOV   WORD PTR Game.CLW,BX
  MOV   WORD PTR Game.CLW[2],BX
  MOV   WORD PTR Game.CRW,BX
  MOV   WORD PTR Game.CRW[2],BX
@LP12:
  JMP   GetOut

LCOLUPF:

  MOV   AL,BYTE PTR Game.TIA_Regs[COLUPF]
  MOV   AH,AL
  MOV   WORD PTR Game.ColorLum[4],AX
  MOV   CX,WORD PTR Game.ColorLum[0]
  MOV   DX,WORD PTR Game.ColorLum[2]
  TEST  BYTE PTR Game.TIA_Regs[CTRLPF],2
  JZ    @LPF1

  MOV   BL,BYTE PTR Game.TIA_Regs[CTRLPF]
  AND   BL,0Fh
  CMP   BL,0Fh
  JZ    @LPF1

  MOV   WORD PTR Game.CLW,CX
  MOV   WORD PTR Game.CLW[2],CX
  MOV   WORD PTR Game.CRW,DX
  MOV   WORD PTR Game.CRW[2],DX
  JMP   @LPF2
@LPF1:
  MOV   WORD PTR Game.CLW,AX
  MOV   WORD PTR Game.CLW[2],AX
  MOV   WORD PTR Game.CRW,AX
  MOV   WORD PTR Game.CRW[2],AX
@LPF2:
  JMP   GetOut

LCOLUBK:

  MOV   AL,BYTE PTR Game.TIA_Regs[COLUBK]
  MOV   AH,AL
  MOV   WORD PTR Game.ColorLum[6],AX
  JMP   GetOut

LCTRLPF:

  { Handle everything but reflection immediately }

  MOVZX EDI,WORD PTR Game.TIA_Latch_Queue
  DEC   EDI
  ADD   EDI,EDI
  MOV   AL,BYTE PTR Game.TIA_Latch_Value[EDI]
  MOV   ESI,EAX
  SHR   ESI,4
  AND   ESI,3
  MOV   CL,BYTE PTR MissileSize[ESI]
  SUB   CH,CH
  MOV   WORD PTR Game.BallSize,CX

  SUB   CX,160
  MOV   WORD PTR Game.BallSize160,CX
  MOV   CX,WORD PTR Game.ColorLum[0]
  MOV   DX,WORD PTR Game.ColorLum[2]
  MOV   BX,WORD PTR Game.ColorLum[4]
  TEST  AL,2
  JZ    @LCPF1
  MOV   WORD PTR Game.CLW,CX
  MOV   WORD PTR Game.CLW[2],CX
  MOV   WORD PTR Game.CRW,DX
  MOV   WORD PTR Game.CRW[2],DX
  JMP   @LCPF2
@LCPF1:
  MOV   WORD PTR Game.CLW,BX
  MOV   WORD PTR Game.CLW[2],BX
  MOV   WORD PTR Game.CRW,BX
  MOV   WORD PTR Game.CRW[2],BX
@LCPF2:

  CMP   DWORD PTR Game.ObjectLoc[BallSet * 2],0
  JGE   GetOut

  MOV   AL,BYTE PTR Game.TIA_Latch_Value[EDI]
  SHR   EAX,4
  AND   EAX,3
  CMP   EAX,3
  JE    @CPF1
  SUB   EAX,EAX
@CPF1:
  NEG   EAX
  SUB   EAX,6
  CMP   DWORD PTR Game.ObjectLoc[BallSet * 2],EAX
  JNE   GetOut

  MOV   BL,BYTE PTR Game.TIA_Latch_Value[EDI]
  SHR   EBX,4
  AND   EBX,3
  MOV   ECX,-9
  CMP   EBX,3
  JE    @CPF1A
  ADD   ECX,3
@CPF1A:
  MOV   DWORD PTR Game.ObjectLoc[BallSet * 2],ECX
  JMP   GetOut

LREFP0:

  MOV   CL,BYTE PTR Game.TIA_Regs[REFP0]
  MOV   BL,BYTE PTR Game.TIA_Regs[NUSIZ0]
  AND   EBX,7
  SHL   EBX,2
  MOV   EAX,EBX
  SHL   EAX,6
  SHL   CL,4
  AND   CL,80h
  OR    AL,CL
  MOV   WORD PTR Game.Player0Size128,AX
  MOV   WORD PTR Game.OldPlayer0Size128,AX
  MOV   EAX,DWORD PTR PlayerSize[EBX]
  MOV   WORD PTR Game.Player0Size,AX
  SUB   AX,160
  MOV   WORD PTR Game.Player0Size160,AX
  JMP   GetOut

LREFP1:

  MOV   CL,BYTE PTR Game.TIA_Regs[REFP1]
  MOV   BL,BYTE PTR Game.TIA_Regs[NUSIZ1]
  AND   EBX,7
  SHL   EBX,2
  MOV   EAX,EBX
  SHL   EAX,6
  SHL   CL,4
  AND   CL,80h
  OR    AL,CL
  MOV   WORD PTR Game.Player1Size128,AX
  MOV   WORD PTR Game.OldPlayer1Size128,AX
  MOV   EAX,DWORD PTR PlayerSize[EBX]
  MOV   WORD PTR Game.Player1Size,AX
  SUB   AX,160
  MOV   WORD PTR Game.Player1Size160,AX
  JMP   GetOut

LHMOVE:
  AND   BYTE PTR Game.DispJump,0EFh
  TEST  BYTE PTR AtariSeg[ENAM0],2
  JZ    @LHMOVEA
  TEST  BYTE PTR AtariSeg[RESMP0],2
  JNZ   @LHMOVEA
  OR    BYTE PTR Game.DispJump,10h
@LHMOVEA:

  MOV   BL,BYTE PTR Game.TIA_Regs[NUSIZ0]

  MOV   AL,BL
  MOV   AH,AL
  SHR   AL,1
  AND   EAX,0718h
  OR    AL,AH
  AND   AH,0
  SHL   EAX,7
  MOV   DWORD PTR Game.Missile0SizeNum,EAX
  MOV   DWORD PTR Game.OldMissile0SizeNum,EAX

  MOV   ESI,EBX
  SHR   ESI,4
  AND   ESI,3
  MOVZX ECX,BYTE PTR MissileSize[ESI]
  MOV   DWORD PTR Game.Missile0Size,ECX
  MOV   EDX,ECX
  DEC   ECX
  SHR   ECX,1
  MOV   DWORD PTR Game.Missile0Adjust,ECX
  SUB   EDX,160
  MOV   DWORD PTR Game.Missile0Size160,EDX


  MOV   BYTE PTR Game.M0Bug,0
  MOV   BYTE PTR Game.DoHMOVE,1
  MOV   BYTE PTR Game.OldDoHMOVE,1
  MOVSX EAX,WORD PTR Game.TIA_Count
  MOV   DWORD PTR Game.HMOVECount,EAX

  { Retrieve all of the move values }

  MOVSX EAX,BYTE PTR Game.TIA_Regs[HMP0]
  SAR   EAX,4
  MOV   EBX,EAX   { Player 0 movement value }
  NEG   EBX

  MOVSX EAX,BYTE PTR Game.TIA_Regs[HMP1]
  SAR   EAX,4
  MOV   ECX,EAX   { Player 1 movement value }
  NEG   ECX

  MOVSX EAX,BYTE PTR Game.TIA_Regs[HMM0]
  SAR   EAX,4
  MOV   EDX,EAX   { Missile 0 movement value }
  NEG   EDX

  MOVSX EAX,BYTE PTR Game.TIA_Regs[HMM1]
  SAR   EAX,4
  MOV   ESI,EAX   { Missile 1 movement value }
  NEG   ESI

  MOVSX EAX,BYTE PTR Game.TIA_Regs[HMBL]
  SAR   EAX,4
  MOV   EDI,EAX   { Ball movement value }
  NEG   EDI

  { Adjust the move values based on when the HMOVE took place }

  MOVSX EAX,WORD PTR Game.TIA_Count
  CMP   EAX,-59
  JL    @NoAdjust
  CMP   EAX,-7
  JG    @NotRegionOne

  { Region 1: keep value at or above a certain minimum }

  ADD   EAX,59
  SHR   EAX,2
  SUB   EAX,7

  CMP   EBX,EAX
  JGE   @MinP1
  MOV   EBX,EAX
@MinP1:
  CMP   ECX,EAX
  JGE   @MinM0
  MOV   ECX,EAX
@MinM0:
  CMP   EDX,EAX
  JGE   @MinM1
  MOV   EDX,EAX
@MinM1:
  CMP   ESI,EAX
  JGE   @MinBL
  MOV   ESI,EAX
@MinBL:
  CMP   EDI,EAX
  JGE   @NoAdjust
  MOV   EDI,EAX
  JMP   @NoAdjust

@NotRegionOne:
  CMP   EAX,93
  JL    @NoAdjust
  CMP   EAX,157
  JGE   @NoAdjust

  { Region 2: add or subtract an offset, with 0 as the maximum value }

  SUB   EAX,93
  SHR   EAX,2
  NEG   EAX
  ADD   EAX,7

  ADD   EBX,EAX
  JS    @MaxP1
  SUB   EBX,EBX
@MaxP1:
  ADD   ECX,EAX
  JS    @MaxM0
  SUB   ECX,ECX
@MaxM0:
  ADD   EDX,EAX
  JS    @MaxM1
  SUB   EDX,EDX
@MaxM1:
  ADD   ESI,EAX
  JS    @MaxBL
  SUB   ESI,ESI
@MaxBL:
  ADD   EDI,EAX
  JS    @NoAdjust
  SUB   EDI,EDI

@NoAdjust:

  { Save the movement values }

  MOV   DWORD PTR Game.ObjectMove[Player0Set  * 2],EBX
  MOV   DWORD PTR Game.ObjectMove[Player1Set  * 2],ECX
  MOV   DWORD PTR Game.ObjectMove[Missile0Set * 2],EDX
  MOV   DWORD PTR Game.ObjectMove[Missile1Set * 2],ESI
  MOV   DWORD PTR Game.ObjectMove[BallSet     * 2],EDI

  { See if we are going to miss the HMOVE because of a pending set }

  SUB   AL,AL
  CMP   BYTE PTR Game.TIA_Latch_RegCount[RESP0],0
  JE    @NoMissP0
  INC   AL
@NoMissP0:
  MOV   BYTE PTR Game.MissedHMOVE[Player0Set],AL

  SUB   AL,AL
  CMP   BYTE PTR Game.TIA_Latch_RegCount[RESP1],0
  JE    @NoMissP1
  INC   AL
@NoMissP1:
  MOV   BYTE PTR Game.MissedHMOVE[Player1Set],AL

  SUB   AL,AL
  CMP   BYTE PTR Game.TIA_Latch_RegCount[RESM0],0
  JE    @NoMissM0
  INC   AL
@NoMissM0:
  MOV   BYTE PTR Game.MissedHMOVE[Missile0Set],AL

  SUB   AL,AL
  CMP   BYTE PTR Game.TIA_Latch_RegCount[RESM1],0
  JE    @NoMissM1
  INC   AL
@NoMissM1:
  MOV   BYTE PTR Game.MissedHMOVE[Missile1Set],AL

  SUB   AL,AL
  CMP   BYTE PTR Game.TIA_Latch_RegCount[RESBL],0
  JE    @NoMissBL
  INC   AL
@NoMissBL:
  MOV   BYTE PTR Game.MissedHMOVE[BallSet],AL

  { Add the movement values to each object's position }

  CALL  DoP0Motion
  CALL  DoP1Motion
  CALL  DoM0Motion
  CALL  DoM1Motion
  CALL  DoBLMotion

GetOut:
  POPAD
End; { Handle_IO_After }

Procedure Handle_IO_Latch; Assembler;
{ ------------------------------------------------------------------------- }
{ On entry:                                                                 }
{ EBX = TIA register                                                         }
{ EDX = New latch value                                                      }
{ ------------------------------------------------------------------------- }
Label LCTRLPF,LRESP0,LRESP1,LRESM0,LRESM1,LRESBL,LNUSIZ0,LNUSIZ1,GetOut;
Asm
  PUSHAD

  PUSH  EBX
  TEST  BYTE PTR Handle_IO_Set_Latch,0FFh
  JNZ   @L2

  MOV   EAX,OFFSET GetOut
  MOV   ECX,CXCLR
  SUB   EBX,EBX
@L1:
  MOV   DWORD PTR Handle_IO_Loc_Latch[EBX],EAX
  ADD   BX,4
  LOOP  @L1

  MOV   DWORD PTR Handle_IO_Loc_Latch[CTRLPF  * 4],OFFSET LCTRLPF
  MOV   DWORD PTR Handle_IO_Loc_Latch[NUSIZ0  * 4],OFFSET LNUSIZ0
  MOV   DWORD PTR Handle_IO_Loc_Latch[NUSIZ1  * 4],OFFSET LNUSIZ1
  MOV   DWORD PTR Handle_IO_Loc_Latch[RESP0   * 4],OFFSET LRESP0
  MOV   DWORD PTR Handle_IO_Loc_Latch[RESP1   * 4],OFFSET LRESP1
  MOV   DWORD PTR Handle_IO_Loc_Latch[RESM0   * 4],OFFSET LRESM0
  MOV   DWORD PTR Handle_IO_Loc_Latch[RESM1   * 4],OFFSET LRESM1
  MOV   DWORD PTR Handle_IO_Loc_Latch[RESBL   * 4],OFFSET LRESBL

  MOV   BYTE PTR Handle_IO_Set_Latch,1
@L2:
  POP   EBX
  CMP   EBX,CXCLR
  JA    GetOut
  SHL   EBX,2
  JMP   DWORD PTR Handle_IO_Loc_Latch[EBX]

LCTRLPF:

  CMP   DWORD PTR Game.ObjectLoc[BallSet * 2],0
  JGE   @BallNotOffScreen

  MOV   AL,BYTE PTR Game.TIA_Regs[CTRLPF]
  SHR   EAX,4
  AND   EAX,3
  CMP   EAX,3
  JE    @CPF1
  SUB   EAX,EAX
@CPF1:
  NEG   EAX
  SUB   EAX,6
  CMP   DWORD PTR Game.ObjectLoc[BallSet * 2],EAX
  JNE   @BallNotOffScreen

  MOV   BL,BYTE PTR Game.TIA_Regs[CTRLPF]
  SHR   EBX,4
  AND   EBX,3
  MOV   ECX,-9
  CMP   EBX,3
  JE    @CPF1A
  ADD   ECX,3
@CPF1A:
  MOV   DWORD PTR Game.ObjectLoc[BallSet * 2],ECX
@BallNotOffScreen:
{ ----- }

  MOV   AL,BYTE PTR Game.TIA_Regs[CTRLPF]
  MOV   ESI,EAX
  SHR   ESI,4
  AND   ESI,3
  MOV   CL,BYTE PTR MissileSize[ESI]
  SUB   CH,CH
  MOV   WORD PTR Game.BallSize,CX

  SUB   CX,160
  MOV   WORD PTR Game.BallSize160,CX
  MOV   CX,WORD PTR Game.ColorLum[0]
  MOV   DX,WORD PTR Game.ColorLum[2]
  MOV   BX,WORD PTR Game.ColorLum[4]
  TEST  AL,2
  JZ    @LCPF1

  AND   AL,0Fh
  CMP   AL,0Fh
  JZ    @LCPF1

  MOV   WORD PTR Game.CLW,CX
  MOV   WORD PTR Game.CLW[2],CX
  MOV   WORD PTR Game.CRW,DX
  MOV   WORD PTR Game.CRW[2],DX
  JMP   @LCPF2
@LCPF1:
  MOV   WORD PTR Game.CLW,BX
  MOV   WORD PTR Game.CLW[2],BX
  MOV   WORD PTR Game.CRW,BX
  MOV   WORD PTR Game.CRW[2],BX
@LCPF2:

  JMP   GetOut

LRESP0:
  MOV   DWORD PTR Game.ObjectLoc[Player0Set * 2],EDX
  MOV   DWORD PTR Game.OldObjectLoc[Player0Set * 2],EDX
  MOV   EAX,DWORD PTR Game.TIA_Latch_ResetPlayer0Size128
  MOV   DWORD PTR Game.ResetPlayer0Size128,EAX
  ADD   EAX,DWORD PTR Game.OldPlayer0Size128
  MOV   DWORD PTR Game.Player0Size128,EAX
  TEST  BYTE PTR Game.MissedHMOVE[Player0Set],0FFh
  JZ    @NoP0Move
  CALL  DoP0Motion
  MOV   BYTE PTR Game.MissedHMOVE[Player0Set],0
@NoP0Move:
  JMP   GetOut

LRESP1:
  MOV   DWORD PTR Game.ObjectLoc[Player1Set * 2],EDX
  MOV   DWORD PTR Game.OldObjectLoc[Player1Set * 2],EDX
  MOV   EAX,DWORD PTR Game.TIA_Latch_ResetPlayer1Size128
  MOV   DWORD PTR Game.ResetPlayer1Size128,EAX
  ADD   EAX,DWORD PTR Game.OldPlayer1Size128
  MOV   DWORD PTR Game.Player1Size128,EAX
  TEST  BYTE PTR Game.MissedHMOVE[Player1Set],0FFh
  JZ    @NoP1Move
  CALL  DoP1Motion
  MOV   BYTE PTR Game.MissedHMOVE[Player1Set],0
@NoP1Move:
  JMP   GetOut

LRESM0:
  MOV   DWORD PTR Game.ObjectLoc[Missile0Set * 2],EDX
  MOV   DWORD PTR Game.OldObjectLoc[Missile0Set * 2],EDX
  MOV   EAX,DWORD PTR Game.TIA_Latch_Missile0SizeNum
  MOV   DWORD PTR Game.Missile0SizeNum,EAX
  TEST  BYTE PTR Game.MissedHMOVE[Missile0Set],0FFh
  JZ    @NoM0Move
  CALL  DoM0Motion
  MOV   BYTE PTR Game.MissedHMOVE[Missile0Set],0
@NoM0Move:
  JMP   GetOut

LRESM1:
  MOV   DWORD PTR Game.ObjectLoc[Missile1Set * 2],EDX
  MOV   DWORD PTR Game.OldObjectLoc[Missile1Set * 2],EDX
  MOV   EAX,DWORD PTR Game.TIA_Latch_Missile1SizeNum
  MOV   DWORD PTR Game.Missile1SizeNum,EAX
  TEST  BYTE PTR Game.MissedHMOVE[Missile1Set],0FFh
  JZ    @NoM1Move
  CALL  DoM1Motion
  MOV   BYTE PTR Game.MissedHMOVE[Missile1Set],0
@NoM1Move:
  JMP   GetOut

LRESBL:
  MOV   DWORD PTR Game.ObjectLoc[BallSet * 2],EDX
  MOV   DWORD PTR Game.OldObjectLoc[BallSet * 2],EDX
  TEST  BYTE PTR Game.MissedHMOVE[BallSet],0FFh
  JZ    @NoBLMove
  CALL  DoBLMotion
  MOV   BYTE PTR Game.MissedHMOVE[BallSet],0
@NoBLMove:
  JMP   GetOut

LNUSIZ0:
  MOV   BL,BYTE PTR Game.TIA_Regs[NUSIZ0]

  MOV   AL,BL
  MOV   AH,AL
  SHR   AL,1
  AND   EAX,0718h
  OR    AL,AH
  AND   EAX,0FFh
  SHL   EAX,7
  MOV   DWORD PTR Game.Missile0SizeNum,EAX
  MOV   DWORD PTR Game.OldMissile0SizeNum,EAX

  MOV   ESI,EBX
  SHR   ESI,4
  AND   ESI,3
  MOVZX ECX,BYTE PTR MissileSize[ESI]
  MOV   DWORD PTR Game.Missile0Size,ECX
  MOV   EDX,ECX

  DEC   ECX
  SHR   ECX,1
  MOV   DWORD PTR Game.Missile0Adjust,ECX

  SUB   EDX,160
  MOV   DWORD PTR Game.Missile0Size160,EDX
  AND   EBX,7
  SHL   EBX,2
  MOV   EAX,EBX
  SHL   EAX,6
  MOV   CL,BYTE PTR Game.TIA_Regs[REFP0]
  SHL   CL,4
  AND   CL,80h
  OR    AL,CL
  MOV   DWORD PTR Game.Player0Size128,EAX
  MOV   DWORD PTR Game.OldPlayer0Size128,EAX

  { If previously writing to RESP0 caused a player copy to disappear, }
  { make sure that the copy doesn't reappear                          }

  CMP   DWORD PTR Game.ResetPlayer0Size128,0
  JE    @NoReset0Add
  MOV   EAX,DWORD PTR Add1A[EBX]
  MOV   DWORD PTR Game.ResetPlayer0Size128,EAX
  ADD   DWORD PTR Game.Player0Size128,EAX
@NoReset0Add:

  MOV   EAX,DWORD PTR _PlayerSize[EBX]
  MOV   DWORD PTR Game._Player0Size,EAX
  MOV   EAX,DWORD PTR PlayerSize[EBX]
  MOV   DWORD PTR Game.Player0Size,EAX
  SUB   EAX,160
  MOV   DWORD PTR Game.Player0Size160,EAX

  CMP   DWORD PTR Game.ObjectLoc[Missile0Set * 2],0
  JGE   @CheckBlank0

  MOV   AL,BYTE PTR Game.TIA_Regs[NUSIZ0]
  SHR   EAX,4
  AND   EAX,3
  CMP   EAX,3
  JE    @NSZ0
  SUB   EAX,EAX
@NSZ0:
  NEG   EAX
  SUB   EAX,6
  CMP   DWORD PTR Game.ObjectLoc[Missile0Set * 2],EAX
  JNE   @CheckBlank0

  MOV   BL,BYTE PTR AtariSeg[NUSIZ0]
  SHR   EBX,4
  AND   EBX,3
  MOV   ECX,-9
  CMP   EBX,3
  JE    @NSZ0A
  ADD   ECX,3
@NSZ0A:
  MOV   DWORD PTR Game.ObjectLoc[Missile0Set * 2],ECX
@CheckBlank0:
  JMP   GetOut

LNUSIZ1:
  MOV   BL,BYTE PTR Game.TIA_Regs[NUSIZ1]

  MOV   AL,BL
  MOV   AH,AL
  SHR   AL,1
  AND   EAX,0718h
  OR    AL,AH
  AND   EAX,0FFh
  SHL   EAX,7
  MOV   DWORD PTR Game.Missile1SizeNum,EAX
  MOV   DWORD PTR Game.OldMissile1SizeNum,EAX

  MOV   ESI,EBX
  SHR   ESI,4
  AND   ESI,3
  MOVZX ECX,BYTE PTR MissileSize[ESI]
  MOV   DWORD PTR Game.Missile1Size,ECX
  MOV   EDX,ECX

  DEC   ECX
  SHR   ECX,1
  MOV   DWORD PTR Game.Missile1Adjust,ECX

  SUB   EDX,160
  MOV   DWORD PTR Game.Missile1Size160,EDX
  AND   EBX,7
  SHL   EBX,2
  MOV   EAX,EBX
  SHL   EAX,6
  MOV   CL,BYTE PTR Game.TIA_Regs[REFP1]
  SHL   CL,4
  AND   CL,80h
  OR    AL,CL
  MOV   DWORD PTR Game.Player1Size128,EAX
  MOV   DWORD PTR Game.OldPlayer1Size128,EAX

  { If previously writing to RESP1 caused a player copy to disappear, }
  { make sure that the copy doesn't reappear                          }

  CMP   DWORD PTR Game.ResetPlayer1Size128,0
  JE    @NoReset1Add
  MOV   EAX,DWORD PTR Add1A[EBX]
  MOV   DWORD PTR Game.ResetPlayer1Size128,EAX
  ADD   DWORD PTR Game.Player1Size128,EAX
@NoReset1Add:

  MOV   EAX,DWORD PTR _PlayerSize[EBX]
  MOV   DWORD PTR Game._Player1Size,EAX
  MOV   EAX,DWORD PTR PlayerSize[EBX]
  MOV   DWORD PTR Game.Player1Size,EAX
  SUB   EAX,160
  MOV   DWORD PTR Game.Player1Size160,EAX

  CMP   DWORD PTR Game.ObjectLoc[Missile1Set * 2],0
  JGE   @CheckBlank1

  MOV   AL,BYTE PTR Game.TIA_Regs[NUSIZ1]
  SHR   EAX,4
  AND   EAX,3
  CMP   EAX,3
  JE    @NSZ1
  SUB   EAX,EAX
@NSZ1:
  NEG   EAX
  SUB   EAX,6
  CMP   DWORD PTR Game.ObjectLoc[Missile1Set * 2],EAX
  JNE   @CheckBlank1

  MOV   BL,BYTE PTR AtariSeg[NUSIZ1]
  SHR   EBX,4
  AND   EBX,3
  MOV   ECX,-9
  CMP   EBX,3
  JE    @NSZ1A
  ADD   ECX,3
@NSZ1A:
  MOV   DWORD PTR Game.ObjectLoc[Missile1Set * 2],ECX

@CheckBlank1:
  JMP   GetOut

GetOut:
  POPAD
End; { Handle_IO_Latch }

Procedure InitEmulator;
Begin
{
  If BreakExpColl <> Nil Then
  Begin
    BreakExpColl.Free;
    BreakExpColl := Nil;
  End;
}
  { There is no initial break expression.  Initialize the pointer. }

  HaltLine     := 999;
//  BreakExpColl := Nil;
  frmDebugger.lblExpression.Caption := '(none)';
  PF2Wave      := 0;
  Game._6507_P := $20;
  Game._6507_A := 0;
  Game._6507_X := 0;
  Game._6507_Y := 0;
  Game._6507_S := $FF;
  Game.LineDelay           := 0;
  Game.LineDelayFirst      := False;
  Game.LineDelayMax        := 262;               { Can become 314 for PAL games }
  AutoCenter               := Config.AutoCenter; { Copy so it can be changed  }
                                                 {  locally without affecting }
                                                 {  overall preferences       }
  Game.FixTimer            := 0;
  Game.FixTimerNum         := 0;
  FillChar(Game.ResetOffset,SizeOf(Game.ResetOffset),#0);
  FillChar(Game.MissedHMOVE,SizeOf(Game.MissedHMOVE),#0);
  Game.ResetOfs            := 0;
  Game.VBLANKOff           := False;
  Game.LastVBLANK          := 200;
  Game.Missile0SizeNum     := 0;
  Game.Missile1SizeNum     := 0;
  Game.OldMissile0SizeNum  := 0;
  Game.OldMissile1SizeNum  := 0;
  Game.OldPlayer0Size128   := 0;
  Game.OldPlayer1Size128   := 0;
  Game.M0Bug               := False;
  Game.M0BugCount          := 0;
  Game.StarpathWriteValue  := 0;
  Game.VAdd                := 0;
  Game.VAddAdjust          := 0;
  Game.VUserAdd            := 0;
  FillChar(Game.TIA_Latch_Value,SizeOf(Game.TIA_Latch_Value),#0);
  FillChar(Game.TIA_Latch_Reg,SizeOf(Game.TIA_Latch_Reg),#0);
  FillChar(Game.TIA_Latch_Scan,SizeOf(Game.TIA_Latch_Scan),#0);
  FillChar(Game.TIA_Latch_Count,SizeOf(Game.TIA_Latch_Count),#0);
  FillChar(Game.TIA_Latch_RegCount,SizeOf(Game.TIA_Latch_RegCount),#0);
  TIA_Latch_Check          := True;
  Game.TIA_Latch_Queue     := 0;
  Game.Indy500[0]          := 0;
  Game.Indy500[1]          := 0;
  Game.LastScan            := 0;
  Game.NewScan             := 0;
  Game.PaddleGround0       := PadMax;
  Game.PaddleGround1       := PadMax;
  Game.PaddleGround2       := PadMax;
  Game.PaddleGround3       := PadMax;
  Game.OldPaddleGround0    := PadMax;
  Game.OldPaddleGround1    := PadMax;
  Game.OldPaddleGround2    := PadMax;
  Game.OldPaddleGround3    := PadMax;
  Game.GRP0Latch           := 0;
  Game.GRP1Latch           := 0;
  Game.BallLatch           := 0;
  Game.TIA_Scan            := -40;
  Game.DoHMOVE             := False;
  Game.OldDoHMOVE          := False;
  Game.LineStart           := 0;
  Game.TimerDone           := False;
  Game.TimerInterval       := 1024;
  Game.TimerValue          := 0;
  Game.TimerShift          := 10;
  Game.TimerX              := 0;
  Game.OrigTimer           := $14;
  Game.TimerElapsed        := 0;
  AtariSeg[INTTIM1]        := $14;
  Game.ColorOrBW           := 8;
  Game.Difficulty1         := 0;
  Game.Difficulty2         := 0;
  PaletteChange            := True;
  ResetChange              := True;
  SelectChange             := True;
  ColorOrBWChange          := True;
  Difficulty1Change        := True;
  Difficulty2Change        := True;
  AutoCenterChange         := True;
  Game.TopVBLANK           := True;
  AtariSeg[SWCHB1]    := Game.ColorOrBW Or Game.Difficulty1 Or Game.Difficulty2 Or 3;
  AtariSeg[SWCHB2]    := Game.ColorOrBW Or Game.Difficulty1 Or Game.Difficulty2 Or 3;
  Game.TIA_Count           := -68;
  Game.Old_TIA_Count       := -68;
  FillChar(Game.ObjectLoc,SizeOf(Game.ObjectLoc),#0);
  FillChar(Game.OldObjectLoc,SizeOf(Game.OldObjectLoc),#0);
  FillChar(Game.NewObjectLoc,SizeOf(Game.NewObjectLoc),#0);
  Game.Addr                := LocalBufSize - 160;
  Game.Latched             := False;
  Game.ReadTime            := 1;
  Game.Write_TIA           := 0;
  Handle_IO_Set       := False;
  Handle_IO_Set_After := False;
  Handle_IO_Set_Latch := False;
  Game.StarpathWrite       := False;
  Game.AddCycle            := 0;
  Game.Player0Size         := 7;
  Game.Player1Size         := 7;
  Game.Player0Size160      := -153;
  Game.Player1Size160      := -153;
  Game.Player0Size128      := 0;
  Game.Player1Size128      := 0;
  Game.ResetPlayer0Size128 := 0;
  Game.ResetPlayer1Size128 := 0;
  Game.Missile0Size        := 1;
  Game.Missile1Size        := 1;
  Game.Missile0Size160     := -159;
  Game.Missile1Size160     := -159;
  Game.BallSize            := 1;
  Game.BallSize160         := -159;
  Game.ObjectSet           := 0;
  Handle_TIA_Jump_Set      := False;
  Game.DispJump            := 0;
  FillChar(Game.Input_Byte,SizeOf(Game.Input_Byte),#0);
  Game.Input_Byte[INPUT0]  := 8;
  Game.Input_Byte[INPUT4]  := $80;
  Game.Input_Byte[INPUT5]  := $80;
  Game.Input_Byte[$E]      := $F;
  Game.Input_Byte[$F]      := $F;
  Game.Missile0Adjust      := 0;
  Game.Missile1Adjust      := 0;
  FillChar(Handle_IO_Loc,SizeOf(Handle_IO_Loc),#0);
  FillChar(Handle_IO_Loc_After,SizeOf(Handle_IO_Loc_After),#0);
  FillChar(Handle_IO_Loc_Latch,SizeOf(Handle_IO_Loc_Latch),#0);
  FillChar(Game.ColorLum,SizeOf(Game.ColorLum),#0);
  FillChar(TIA_Delay,SizeOf(TIA_Delay),#0);
  TIA_Delay[GRP0]  := 1;
  TIA_Delay[GRP1]  := 1;
  TIA_Delay[REFP0] := 1;
  TIA_Delay[REFP1] := 1;
  TIA_Delay[PF0]   := 4;
  TIA_Delay[PF1]   := 4;
  TIA_Delay[PF2]   := 4;
  TIA_Delay[VBLANK] := 1;
  TIA_Delay[ENAM0]  := 1;
  TIA_Delay[ENAM1]  := 1;
  TIA_Delay[ENABL]  := 1;

  // Initialize Compumate

  CMRAMState     := $10;
  CMROMBank      := $3000;
  CMColumn       := 0;
  WriteOp        := 0;
  CMSWCHA        := $73;
  If Game.Cart = ctCompumate Then
  Begin
    Game.Input_Byte[INPUT0] := 0;
    Game.Input_Byte[INPUT1] := $80;
    Game.Input_Byte[INPUT2] := $80;
    Game.Input_Byte[INPUT3] := 0;
  End;
  FillChar(CMRAM,SizeOf(CMRAM),0);
End; { InitEmulator }

Procedure ADC_BCD; Assembler;
{ In:   CL    - accumulator            }
{       DL    - value to add           }
{       Flags - carry is set correctly }
{ Out:  CL    - set on exit            }
{       CH    - set on exit            }
Asm
  PUSH   EBX
  PUSHF
  PUSH   EDX
  PUSHF
  AND    CH,03Ch
  MOV    BL,CL
  MOV    BH,CL
  SHR    BH,4
  AND    DL,0Fh
  AND    BL,0Fh
  POPF
  ADC    BL,DL
  POP    EDX
  PUSH   EDX
  SHR    DL,4
  ADD    BH,DL

  CMP    BL,9
  JBE    @L1
  ADD    BL,6         { Fixup the low nibble }
@L1:
  POP    EDX
  POPF
  PUSH   EDX

  ADC    DL,CL
  JNZ    @L2
  OR     CH,2         { Set the zero flag }
@L2:
  MOV    DL,BH
  SHL    DL,4
  AND    DL,80h
  OR     CH,DL        { Set the negative flag }

  MOV    DL,BH
  SHL    DL,4
  XOR    DL,CL
  AND    DL,80h
  JZ     @L3
  POP    EDX
  PUSH   EDX
  XOR    DL,CL
  AND    DL,80h
  JNZ    @L3
  OR     CH,40h       { Set the overflow flag }
@L3:
  POP    EDX

  TEST   BL,0F0h
  JZ     @L7
  INC    BH
@L7:
  CMP    BH,9
  JBE    @L4
  ADD    BH,6         { Fixup the high nibble }
@L4:

  TEST   BH,0F0h
  JZ     @L5
  OR     CH,1         { Set the carry flag }
@L5:

  SHL    BH,4
  AND    BL,0Fh
  OR     BL,BH
  MOV    CL,BL        { Set the result }
  POP    EBX
End; { ADC_BCD }


Procedure SBC_BCD; Assembler;
{ In:   CL    - accumulator            }
{       DL    - value to subtract      }
{       Flags - carry is set correctly }
{ Out:  CL    - set on exit            }
{       CH    - set on exit            }

Asm
  PUSH   EBX
  PUSHF
  PUSH   EDX
  PUSHF
  AND    CH,03Ch
  MOV    BL,CL
  MOV    BH,CL
  SHR    BH,4
  AND    DL,0Fh
  AND    BL,0Fh
  POPF
  SBB    BL,DL
  TEST   BL,0F0h      { TEST clears the carry flag }
  JZ     @L1
  SUB    BL,6
  AND    BL,0Fh
  STC
@L1:
  POP    EDX
  PUSH   EDX
  PUSHF
  SHR    DL,4
  POPF
  SBB    BH,DL
  TEST   BH,0F0h
  JZ     @L2
  SUB    BH,6
@L2:
  SHL    BH,4
  OR     BL,BH
  POP    EDX
  POPF
  MOV    BH,CL
  SBB    BH,DL
  JC     @L6          { Note the difference! }
  PUSHF
  OR     CH,1
  POPF
@L6:
  JNO    @L7
  OR     CH,40h
@L7:
  OR     BH,BH
  JNZ    @L8
  OR     CH,2
@L8:
  MOV    DL,BH
  AND    DL,80h
  ADD    CH,DL
  MOV    CL,BL
  POP    EBX
End; { SBC_BCD }

Procedure HandleStarpathRTS; Assembler;
Asm
  PUSHAD

  MOV   EAX,1FF8h
  MOV   EDX,EAX
{
  PUSH  EAX
  PUSH  EAX
}
{
  PUSH   DWORD PTR Game.SPBankNum
  PUSH   DWORD PTR Game.TIA_Count
  PUSH   DWORD PTR Game.TIA_Scan
}

  CALL   HandleStarpath
  MOV    CL,BYTE PTR SPBank
  MOV    BYTE PTR Game.SPBankNum,CL

  POPAD
End; { HandleStarpathRTS }

Procedure ResetMissile0; Assembler;
Asm
  TEST  BYTE PTR AtariSeg[RESMP0],2
  JZ    @Missile0Ok
  MOV   AL,BYTE PTR Game.ObjectLoc[Player0Set * 2]
  MOV   AH,BYTE PTR Game._Player0Size
  SHR   AH,1
  ADD   AL,AH

  AND   EAX,0FFh
  CMP   EAX,160
  JB    @M0Ok1A
  SUB   EAX,160
@M0Ok1A:
  MOV   DWORD PTR Game.ObjectLoc[Missile0Set * 2],EAX
@Missile0Ok:
End; { ResetMissile0 }


Procedure ResetMissile1; Assembler;
Asm
  TEST  BYTE PTR AtariSeg[RESMP1],2
  JZ    @Missile1Ok
  MOV   AL,BYTE PTR Game.ObjectLoc[Player1Set * 2]
  MOV   AH,BYTE PTR Game._Player1Size
  SHR   AH,1
  ADD   AL,AH

  AND   EAX,0FFh
  CMP   EAX,160
  JB    @M1Ok1A
  SUB   EAX,160
@M1Ok1A:
  MOV   DWORD PTR Game.ObjectLoc[Missile1Set * 2],EAX
@Missile1Ok:
End; { ResetMissile1 }


Procedure SetPaddlePositions; Assembler;
Asm
  PUSH  EBX
  MOV   EBX,DWORD PTR Game.AddCycle

  CMP   BYTE PTR Game.Cart,ctCompumate
  JE    @NoPaddle3
  TEST  BYTE PTR Game.Input_Byte[INPUT0],80h
  JNZ   @NoPaddle0
  SUB   DWORD PTR Game.PaddleGround0,EBX
  JNC   @NoPaddle0
  MOV   BYTE PTR Game.Input_Byte[INPUT0],80h
@NoPaddle0:

  TEST  BYTE PTR Game.Input_Byte[INPUT1],80h
  JNZ   @NoPaddle1
  SUB   DWORD PTR Game.PaddleGround1,EBX
  JNC   @NoPaddle1
  MOV   BYTE PTR Game.Input_Byte[INPUT1],80h
@NoPaddle1:

  TEST  BYTE PTR Game.Input_Byte[INPUT2],80h
  JNZ   @NoPaddle2
  SUB   DWORD PTR Game.PaddleGround2,EBX
  JNC   @NoPaddle2
  MOV   BYTE PTR Game.Input_Byte[INPUT2],80h
@NoPaddle2:

  TEST  BYTE PTR Game.Input_Byte[INPUT3],80h
  JNZ   @NoPaddle3
  SUB   DWORD PTR Game.PaddleGround3,EBX
  JNC   @NoPaddle3
  MOV   BYTE PTR Game.Input_Byte[INPUT3],80h
@NoPaddle3:

  POP   EBX
End; { SetPaddlePositions }


Procedure SetObjectLocations; Assembler;
Asm
  PUSHAD

    SUB   ESI,ESI
    MOVSX ECX,WORD PTR Game.TIA_Count
    TEST  BYTE PTR Game.OldDoHMOVE,0FFh
    JZ    @NoExtraAdd
    MOVSX EBX,WORD PTR Game.TIA_Count
    ADD   EBX,2
    MOVSX EAX,BYTE PTR ExtraAdd[EBX + 68]
    MOV   ESI,EAX
@NoExtraAdd:

    MOV   BX,WORD PTR Game.ObjectSet

    { Player 0 }

    TEST  BX,Player0Set
    JZ    @NotP0Set
    MOV   EAX,ECX
    ADD   EAX,DWORD PTR Game.ResetOffset[0]
    CMP   EAX,160
    JB    @SignOk1
    SUB   EAX,EAX
    JMP   @SetP0Loc
@SignOk1:
    MOV   EAX,ECX
    ADD   EAX,DWORD PTR Game.ResetOffset[0]
    ADD   EAX,SetLocDelay
@SetP0Loc:
    CMP   WORD PTR Game.TIA_Count,7
    JGE   @NoP0Inc
    TEST  BYTE PTR Game.OldDoHMOVE,0FFh
    JNZ   @DoP0Move
    CMP   WORD PTR Game.TIA_Count,0
    JGE   @NoP0Inc
    MOV   EAX,3
    JMP   @NoP0Inc
@DoP0Move:
    MOV   EAX,ESI
    ADD   EAX,DWORD PTR Game.ObjectMove[Player0Set * 2]
@NoP0Move:
    CMP   EAX,8
    JL    @P0IncOk
    MOV   EAX,8
@P0IncOk:
    ADD   EAX,3
@NoP0Inc:
    MOV   DWORD PTR Game.ObjectLoc[Player0Set * 2],EAX

    SUB   EAX,EAX
    CALL  GetPlayerDelay
    TEST  EAX,80h
    JZ    @DelayP0

    SUB   EAX,EAX
    MOV   DWORD PTR Game.TIA_Latch_ResetPlayer0Size128,EAX
    MOVSX EAX,WORD PTR Game.TIA_Count
    JMP   @DoP0Delay

@DelayP0:
    ADD   EAX,DWORD PTR Game.ObjectLoc[Player0Set * 2]
    PUSH  EBX
    MOV   BL,BYTE PTR Game.TIA_Regs[NUSIZ0]
    AND   EBX,7
    SHL   EBX,2
    MOV   EDX,DWORD PTR Add1A[EBX]
    MOV   DWORD PTR Game.TIA_Latch_ResetPlayer0Size128,EDX
    POP   EBX
@DoP0Delay:
    PUSH  EBX
    MOVSX EBX,WORD PTR Game.TIA_Scan
    MOV   EDX,EBX
    MOV   BL,BYTE PTR Game.TIA_Regs[RESP0]

    PUSH  RESP0
    PUSH  DWORD PTR Game.ObjectLoc[Player0Set * 2]

    MOV   EBX,EAX
    CMP   EBX,160
    JL    @NoP0DelayWrap
    SUB   EBX,160
    INC   EDX
@NoP0DelayWrap:
    PUSH  EDX
    PUSH  EBX
    CALL  QueueLatch

    MOV   EAX,DWORD PTR Game.ObjectLoc[Player0Set * 2]
    MOV   DWORD PTR Game.NewObjectLoc[Player0Set * 2],EAX
    MOV   EAX,DWORD PTR Game.OldObjectLoc[Player0Set * 2]
    MOV   DWORD PTR Game.ObjectLoc[Player0Set * 2],EAX
    POP   EBX
@TurnP0OffDone:
    CALL  ResetMissile0

@NotP0Set:

    { Player 1 }

    TEST  BX,Player1Set
    JZ    @NotP1Set
    MOV   EAX,ECX
    ADD   EAX,DWORD PTR Game.ResetOffset[4]
    CMP   EAX,160
    JB    @SignOk2
    SUB   EAX,EAX
    JMP   @SetP1Loc
@SignOk2:
    MOV   EAX,ECX
    ADD   EAX,DWORD PTR Game.ResetOffset[4]
    ADD   EAX,SetLocDelay
@SetP1Loc:
    CMP   WORD PTR Game.TIA_Count,7
    JGE   @NoP1Inc
    TEST  BYTE PTR Game.OldDoHMOVE,0FFh
    JNZ   @DoP1Move
    CMP   WORD PTR Game.TIA_Count,0
    JGE   @NoP1Inc
    MOV   EAX,3
    JMP   @NoP1Inc
@DoP1Move:
    MOV   EAX,ESI
    ADD   EAX,DWORD PTR Game.ObjectMove[Player1Set * 2]
@NoP1Move:
    CMP   EAX,8
    JL    @P1IncOk
    MOV   EAX,8
@P1IncOk:
    ADD   EAX,3
@NoP1Inc:
    MOV   DWORD PTR Game.ObjectLoc[Player1Set * 2],EAX

    MOV   EAX,1
    CALL  GetPlayerDelay
    TEST  EAX,80h
    JZ    @DelayP1

    SUB   EAX,EAX
    MOV   DWORD PTR Game.TIA_Latch_ResetPlayer1Size128,EAX
    MOVSX EAX,WORD PTR Game.TIA_Count
    JMP   @DoP1Delay

@DelayP1:
    ADD   EAX,DWORD PTR Game.ObjectLoc[Player1Set * 2]
    PUSH  EBX
    MOV   BL,BYTE PTR Game.TIA_Regs[NUSIZ1]
    AND   EBX,7
    SHL   EBX,2
    MOV   EDX,DWORD PTR Add1A[EBX]
    MOV   DWORD PTR Game.TIA_Latch_ResetPlayer1Size128,EDX
    POP   EBX
@DoP1Delay:
    PUSH  EBX
    MOVSX EBX,WORD PTR Game.TIA_Scan
    MOV   EDX,EBX
    MOV   BL,BYTE PTR Game.TIA_Regs[RESP1]

    PUSH  RESP1
    PUSH  DWORD PTR Game.ObjectLoc[Player1Set * 2]

    MOV   EBX,EAX
    CMP   EBX,160
    JL    @NoP1DelayWrap
    SUB   EBX,160
    INC   EDX
@NoP1DelayWrap:
    PUSH  EDX
    PUSH  EBX
    CALL  QueueLatch

    MOV   EAX,DWORD PTR Game.ObjectLoc[Player1Set * 2]
    MOV   DWORD PTR Game.NewObjectLoc[Player1Set * 2],EAX
    MOV   EAX,DWORD PTR Game.OldObjectLoc[Player1Set * 2]
    MOV   DWORD PTR Game.ObjectLoc[Player1Set * 2],EAX
    POP   EBX
@TurnP1OffDone:
    CALL  ResetMissile1

@NotP1Set:

    { Missile 0 }

    TEST  BX,Missile0Set
    JZ    @NotM0Set
    MOV   EAX,ECX
    ADD   EAX,DWORD PTR Game.ResetOffset[8]
    CMP   EAX,160
    JB    @SignOk3
    MOV   EAX,2
    JMP   @SetM0Loc
@SignOk3:
    MOV   EAX,ECX
    ADD   EAX,DWORD PTR Game.ResetOffset[8]
    ADD   EAX,SetLocDelay - 1
@SetM0Loc:
    CMP   WORD PTR Game.TIA_Count,7
    JGE   @NoM0Inc
    TEST  BYTE PTR Game.OldDoHMOVE,0FFh
    JNZ   @DoM0Move
    CMP   WORD PTR Game.TIA_Count,0
    JGE   @NoM0Inc
    MOV   EAX,2
    JMP   @NoM0Inc
@DoM0Move:
    MOV   EAX,ESI
    ADD   EAX,DWORD PTR Game.ObjectMove[Missile0Set * 2]
@NoM0Move:
    CMP   EAX,8
    JL    @M0IncOk
    MOV   EAX,8
@M0IncOk:
    ADD   EAX,2
@NoM0Inc:
    MOV   DWORD PTR Game.ObjectLoc[Missile0Set * 2],EAX

    SUB   EAX,EAX
    CALL  GetMissileDelay
    TEST  EAX,80h
    JZ    @DelayM0

    MOV   EAX,DWORD PTR Game.Missile0SizeNum
    MOV   DWORD PTR Game.TIA_Latch_Missile0SizeNum,EAX
    MOVSX EAX,WORD PTR Game.TIA_Count
    JMP   @DoM0Delay

@DelayM0:
    ADD   EAX,DWORD PTR Game.ObjectLoc[Missile0Set * 2]
    PUSH  EBX
    MOV   BL,BYTE PTR Game.TIA_Regs[NUSIZ0]
    AND   EBX,7
    SHL   EBX,2
    MOV   EDX,DWORD PTR MissileAdd1[EBX]
    MOV   DWORD PTR Game.TIA_Latch_Missile0SizeNum,EDX
    POP   EBX
@DoM0Delay:
    PUSH  EBX
    MOVSX EBX,WORD PTR Game.TIA_Scan
    MOV   EDX,EBX
    MOV   BL,BYTE PTR Game.TIA_Regs[RESM0]

    PUSH  RESM0
    PUSH  DWORD PTR Game.ObjectLoc[Missile0Set * 2]

    MOV   EBX,EAX
    CMP   EBX,160
    JL    @NoM0DelayWrap
    SUB   EBX,160
    INC   EDX
@NoM0DelayWrap:

    PUSH  EDX
    PUSH  EBX
    CALL  QueueLatch

    MOV   EAX,DWORD PTR Game.ObjectLoc[Missile0Set * 2]
    MOV   DWORD PTR Game.NewObjectLoc[Missile0Set * 2],EAX
    MOV   EAX,DWORD PTR Game.OldObjectLoc[Missile0Set * 2]
    MOV   DWORD PTR Game.ObjectLoc[Missile0Set * 2],EAX
    POP   EBX
@TurnM0OffDone:

@NotM0Set:

    { Missile 1 }

    TEST  BX,Missile1Set
    JZ    @NotM1Set
    MOV   EAX,ECX
    ADD   EAX,DWORD PTR Game.ResetOffset[12]
    CMP   EAX,160
    JB    @SignOk4
    MOV   EAX,2
    JMP   @SetM1Loc
@SignOk4:
    MOV   EAX,ECX
    ADD   EAX,DWORD PTR Game.ResetOffset[12]
    ADD   EAX,SetLocDelay - 1
@SetM1Loc:
    CMP   WORD PTR Game.TIA_Count,7
    JGE   @NoM1Inc
    TEST  BYTE PTR Game.OldDoHMOVE,0FFh
    JNZ   @DoM1Move
    CMP   WORD PTR Game.TIA_Count,0
    JGE   @NoM1Inc
    MOV   EAX,2
    JMP   @NoM1Inc
@DoM1Move:
    MOV   EAX,ESI
    ADD   AX,WORD PTR Game.ObjectMove[Missile1Set * 2]
@NoM1Move:
    CMP   EAX,8
    JL    @M1IncOk
    MOV   EAX,8
@M1IncOk:
    ADD   EAX,2
@NoM1Inc:
    MOV   DWORD PTR Game.ObjectLoc[Missile1Set * 2],EAX

    MOV   EAX,1
    CALL  GetMissileDelay
    TEST  EAX,80h
    JZ    @DelayM1

    MOV   EAX,DWORD PTR Game.Missile1SizeNum
    MOV   DWORD PTR Game.TIA_Latch_Missile1SizeNum,EAX
    MOVSX EAX,WORD PTR Game.TIA_Count
    JMP   @DoM1Delay

@DelayM1:
    ADD   EAX,DWORD PTR Game.ObjectLoc[Missile1Set * 2]
    PUSH  EBX
    MOV   BL,BYTE PTR Game.TIA_Regs[NUSIZ1]
    AND   EBX,7
    SHL   EBX,2
    MOV   EDX,DWORD PTR MissileAdd1[EBX]
    MOV   DWORD PTR Game.TIA_Latch_Missile1SizeNum,EDX
    POP   EBX
@DoM1Delay:
    PUSH  EBX
    MOVSX EBX,WORD PTR Game.TIA_Scan
    MOV   EDX,EBX
    MOV   BL,BYTE PTR Game.TIA_Regs[RESM1]

    PUSH  RESM1
    PUSH  DWORD PTR Game.ObjectLoc[Missile1Set * 2]

    MOV   EBX,EAX
    CMP   EBX,160
    JL    @NoM1DelayWrap
    SUB   EBX,160
    INC   EDX
@NoM1DelayWrap:

    PUSH  EDX
    PUSH  EBX
    CALL  QueueLatch

    MOV   EAX,DWORD PTR Game.ObjectLoc[Missile1Set * 2]
    MOV   DWORD PTR Game.NewObjectLoc[Missile1Set * 2],EAX
    MOV   EAX,DWORD PTR Game.OldObjectLoc[Missile1Set * 2]
    MOV   DWORD PTR Game.ObjectLoc[Missile1Set * 2],EAX
    POP   EBX
@TurnM1OffDone:

@NotM1Set:

    { Ball }

    TEST  BX,BallSet
    JZ    @NotBLSet
    MOV   EAX,ECX
    ADD   EAX,DWORD PTR Game.ResetOffset[16]
    CMP   EAX,160
    JB    @SignOk5
    MOV   EAX,2
    JMP   @SetBLLoc
@SignOk5:
    MOV   EAX,ECX
    ADD   EAX,DWORD PTR Game.ResetOffset[16]
    ADD   EAX,SetLocDelay - 1
@SetBLLoc:
    CMP   WORD PTR Game.TIA_Count,7
    JGE   @NoBLInc
    TEST  BYTE PTR Game.OldDoHMOVE,0FFh
    JNZ   @DoBLMove
    CMP   WORD PTR Game.TIA_Count,0
    JGE   @NoBLInc
    MOV   EAX,2
    JMP   @NoBLInc
@DoBLMove:
    MOV   EAX,ESI
    ADD   EAX,DWORD PTR Game.ObjectMove[BallSet * 2]
@NoBLMove:
    CMP   EAX,8
    JL    @BLIncOk
    MOV   EAX,8
@BLIncOk:
    ADD   EAX,2
@NoBLInc:
    MOV   DWORD PTR Game.ObjectLoc[BallSet * 2],EAX

    CALL  GetBallDelay
    TEST  EAX,80h
    JNZ   @DelayBL

    MOVSX EAX,WORD PTR Game.TIA_Count
    JMP   @DoBLDelay

@DelayBL:
    AND   EAX,7Fh
    ADD   EAX,DWORD PTR Game.ObjectLoc[BallSet * 2]
    ADD   EAX,4
@DoBLDelay:
    PUSH  EBX
    MOVSX EBX,WORD PTR Game.TIA_Scan
    MOV   EDX,EBX
    MOV   BL,BYTE PTR Game.TIA_Regs[RESBL]

    PUSH  RESBL
    PUSH  DWORD PTR Game.ObjectLoc[BallSet * 2]

    MOV   EBX,EAX
    CMP   EBX,160
    JL    @NoBLDelayWrap
    SUB   EBX,160
    INC   EDX
@NoBLDelayWrap:

    PUSH  EDX
    PUSH  EBX
    CALL  QueueLatch

    MOV   EAX,DWORD PTR Game.ObjectLoc[BallSet * 2]
    MOV   DWORD PTR Game.NewObjectLoc[BallSet * 2],EAX
    MOV   EAX,DWORD PTR Game.OldObjectLoc[BallSet * 2]
    MOV   DWORD PTR Game.ObjectLoc[BallSet * 2],EAX
    POP   EBX
@TurnBLOffDone:

@NotBLSet:
    MOV   WORD PTR Game.ObjectSet,0

  POPAD
End; { SetObjectLocations }
(*
Procedure ShowStatus(PC,P,A,X,Y,S: LongInt);
Var F: System.Text;
Begin
  AssignFile(F,ExtractFilePath(Application.ExeName) + 'PCAEWIN.LOG');
  If Not FileExists(ExtractFilePath(Application.ExeName) + 'PCAEWIN.LOG')
   Then ReWrite(F)
   Else Append(F);
  WriteLn(F,'PC = $' + HexWord(PC) + '  ($' + HexByte(AtariSeg[PC]) + ') ' +
            'P,A,X,Y,S = ' + HexByte(P) + ',' + HexByte(A) + ',' +
            HexByte(X) + ',' + HexByte(Y) + ',' + HexByte(S) + ' ' +
            'TIA_Count = ' + IntToStr(Game.TIA_Count) + ' ' +
            'TIA_Scan = ' + IntToStr(Game.TIA_Scan));
  CloseFile(F);
End; // ShowStatus
*)
Procedure Interpret(Var _Start: Word; Var _P,_A,_X,_Y,_S: Byte);
Var
  P,A,X,Y,S  : Byte;
  Start      : Word;
  CheckSound : Byte;

Label DoNothing,EmulateLoop,DoneReadTime,GetOut,
      L00,L01,L02,L03,L04,L05,L06,L07,L08,L09,L0A,L0B,L0C,L0D,L0E,L0F,
      L10,L11,L12,L13,L14,L15,L16,L17,L18,L19,L1A,L1B,L1C,L1D,L1E,L1F,
      L20,L21,L22,L23,L24,L25,L26,L27,L28,L29,L2A,L2B,L2C,L2D,L2E,L2F,
      L30,L31,L32,L33,L34,L35,L36,L37,L38,L39,L3A,L3B,L3C,L3D,L3E,L3F,
      L40,L41,L42,L43,L44,L45,L46,L47,L48,L49,L4A,L4B,L4C,L4D,L4E,L4F,
      L50,L51,L52,L53,L54,L55,L56,L57,L58,L59,L5A,L5B,L5C,L5D,L5E,L5F,
      L60,L61,L62,L63,L64,L65,L66,L67,L68,L69,L6A,L6B,L6C,L6D,L6E,L6F,
      L70,L71,L72,L73,L74,L75,L76,L77,L78,L79,L7A,L7B,L7C,L7D,L7E,L7F,
      L80,L81,L82,L83,L84,L85,L86,L87,L88,L89,L8A,L8B,L8C,L8D,L8E,L8F,
      L90,L91,L92,L93,L94,L95,L96,L97,L98,L99,L9A,L9B,L9C,L9D,L9E,L9F,
      LA0,LA1,LA2,LA3,LA4,LA5,LA6,LA7,LA8,LA9,LAA,LAB,LAC,LAD,LAE,LAF,
      LB0,LB1,LB2,LB3,LB4,LB5,LB6,LB7,LB8,LB9,LBA,LBB,LBC,LBD,LBE,LBF,
      LC0,LC1,LC2,LC3,LC4,LC5,LC6,LC7,LC8,LC9,LCA,LCB,LCC,LCD,LCE,LCF,
      LD0,LD1,LD2,LD3,LD4,LD5,LD6,LD7,LD8,LD9,LDA,LDB,LDC,LDD,LDE,LDF,
      LE0,LE1,LE2,LE3,LE4,LE5,LE6,LE7,LE8,LE9,LEA,LEB,LEC,LED,LEE,LEF,
      LF0,LF1,LF2,LF3,LF4,LF5,LF6,LF7,LF8,LF9,LFA,LFB,LFC,LFD,LFE,LFF;

  Function EvaluateBreakExp: Boolean;
  Begin
    EvaluateBreakExp := Evaluate(BreakExpColl,PGameROM(@AtariSeg[0])^,
                                 Game.ObjectLoc[Index_Player0Set],
                                 Game.ObjectLoc[Index_Player1Set],
                                 Game.ObjectLoc[Index_Missile0Set],
                                 Game.ObjectLoc[Index_Missile1Set],
                                 Game.ObjectLoc[Index_BallSet],
                                 Debugger_X,Debugger_Y,Debugger_A,Debugger_P,Debugger_S,Debugger_PC,
                                 Game.TIA_Count,Game.TIA_Scan,ExpError);
  End; // EvaluateBreakExp

Begin

  { AL - X reg            AH - Y reg    }
  { BL - work             BH - work     }
  { CL - Accumulator      CH - Flags    }
  { DL - work             DH - Stack    }
  { SI - unused           DI - PC Reg   }
  { BP - used             SP - not used }

  P                   := _P;
  A                   := _A;
  X                   := _X;
  Y                   := _Y;
  S                   := _S;
  Start               := _Start;
  Move(AtariSeg,Game.TIA_Regs,SizeOf(Game.TIA_Regs));
  Exiting      := False;
  ControlFrame := 0;
  CheckSound   := 0;

  { Load locations here }

  Asm
    PUSHAD
    
    JMP   @Fill
@FillStart:
    DD    OFFSET L00
    DD    OFFSET L01
    DD    OFFSET L02
    DD    OFFSET L03
    DD    OFFSET L04
    DD    OFFSET L05
    DD    OFFSET L06
    DD    OFFSET L07
    DD    OFFSET L08
    DD    OFFSET L09
    DD    OFFSET L0A
    DD    OFFSET L0B
    DD    OFFSET L0C
    DD    OFFSET L0D
    DD    OFFSET L0E
    DD    OFFSET L0F

    DD    OFFSET L10
    DD    OFFSET L11
    DD    OFFSET DoNothing
    DD    OFFSET L13
    DD    OFFSET L14
    DD    OFFSET L15
    DD    OFFSET L16
    DD    OFFSET L17
    DD    OFFSET L18
    DD    OFFSET L19
    DD    OFFSET DoNothing
    DD    OFFSET L1B
    DD    OFFSET L1C
    DD    OFFSET L1D
    DD    OFFSET L1E
    DD    OFFSET L1F

    DD    OFFSET L20
    DD    OFFSET L21
    DD    OFFSET DoNothing
    DD    OFFSET L23
    DD    OFFSET L24
    DD    OFFSET L25
    DD    OFFSET L26
    DD    OFFSET L27
    DD    OFFSET L28
    DD    OFFSET L29
    DD    OFFSET L2A
    DD    OFFSET L2B
    DD    OFFSET L2C
    DD    OFFSET L2D
    DD    OFFSET L2E
    DD    OFFSET L2F

    DD    OFFSET L30
    DD    OFFSET L31
    DD    OFFSET DoNothing
    DD    OFFSET L33
    DD    OFFSET L34
    DD    OFFSET L35
    DD    OFFSET L36
    DD    OFFSET L37
    DD    OFFSET L38
    DD    OFFSET L39
    DD    OFFSET DoNothing
    DD    OFFSET L3B
    DD    OFFSET L3C
    DD    OFFSET L3D
    DD    OFFSET L3E
    DD    OFFSET L3F

    DD    OFFSET L40
    DD    OFFSET L41
    DD    OFFSET DoNothing
    DD    OFFSET L43
    DD    OFFSET L44
    DD    OFFSET L45
    DD    OFFSET L46
    DD    OFFSET L47
    DD    OFFSET L48
    DD    OFFSET L49
    DD    OFFSET L4A
    DD    OFFSET L4B
    DD    OFFSET L4C
    DD    OFFSET L4D
    DD    OFFSET L4E
    DD    OFFSET L4F

    DD    OFFSET L50
    DD    OFFSET L51
    DD    OFFSET DoNothing
    DD    OFFSET L53
    DD    OFFSET L54
    DD    OFFSET L55
    DD    OFFSET L56
    DD    OFFSET L57
    DD    OFFSET L58
    DD    OFFSET L59
    DD    OFFSET DoNothing
    DD    OFFSET L5B
    DD    OFFSET L5C
    DD    OFFSET L5D
    DD    OFFSET L5E
    DD    OFFSET L5F

    DD    OFFSET L60
    DD    OFFSET L61
    DD    OFFSET DoNothing
    DD    OFFSET L63
    DD    OFFSET L64
    DD    OFFSET L65
    DD    OFFSET L66
    DD    OFFSET L67
    DD    OFFSET L68
    DD    OFFSET L69
    DD    OFFSET L6A
    DD    OFFSET L6B
    DD    OFFSET L6C
    DD    OFFSET L6D
    DD    OFFSET L6E
    DD    OFFSET L6F

    DD    OFFSET L70
    DD    OFFSET L71
    DD    OFFSET DoNothing
    DD    OFFSET L73
    DD    OFFSET L74
    DD    OFFSET L75
    DD    OFFSET L76
    DD    OFFSET L77
    DD    OFFSET L78
    DD    OFFSET L79
    DD    OFFSET DoNothing
    DD    OFFSET L7B
    DD    OFFSET L7C
    DD    OFFSET L7D
    DD    OFFSET L7E
    DD    OFFSET L7F

    DD    OFFSET L80
    DD    OFFSET L81
    DD    OFFSET L82
    DD    OFFSET L83
    DD    OFFSET L84
    DD    OFFSET L85
    DD    OFFSET L86
    DD    OFFSET L87
    DD    OFFSET L88
    DD    OFFSET DoNothing
    DD    OFFSET L8A
    DD    OFFSET L8B
    DD    OFFSET L8C
    DD    OFFSET L8D
    DD    OFFSET L8E
    DD    OFFSET L8F

    DD    OFFSET L90
    DD    OFFSET L91
    DD    OFFSET DoNothing
    DD    OFFSET L93
    DD    OFFSET L94
    DD    OFFSET L95
    DD    OFFSET L96
    DD    OFFSET L97
    DD    OFFSET L98
    DD    OFFSET L99
    DD    OFFSET L9A
    DD    OFFSET L9B
    DD    OFFSET L9C
    DD    OFFSET L9D
    DD    OFFSET L9E
    DD    OFFSET L9F

    DD    OFFSET LA0
    DD    OFFSET LA1
    DD    OFFSET LA2
    DD    OFFSET LA3
    DD    OFFSET LA4
    DD    OFFSET LA5
    DD    OFFSET LA6
    DD    OFFSET LA7
    DD    OFFSET LA8
    DD    OFFSET LA9
    DD    OFFSET LAA
    DD    OFFSET LAB
    DD    OFFSET LAC
    DD    OFFSET LAD
    DD    OFFSET LAE
    DD    OFFSET LAF

    DD    OFFSET LB0
    DD    OFFSET LB1
    DD    OFFSET DoNothing
    DD    OFFSET LB3
    DD    OFFSET LB4
    DD    OFFSET LB5
    DD    OFFSET LB6
    DD    OFFSET LB7
    DD    OFFSET LB8
    DD    OFFSET LB9
    DD    OFFSET LBA
    DD    OFFSET LBB
    DD    OFFSET LBC
    DD    OFFSET LBD
    DD    OFFSET LBE
    DD    OFFSET LBF

    DD    OFFSET LC0
    DD    OFFSET LC1
    DD    OFFSET LC2
    DD    OFFSET LC3
    DD    OFFSET LC4
    DD    OFFSET LC5
    DD    OFFSET LC6
    DD    OFFSET LC7
    DD    OFFSET LC8
    DD    OFFSET LC9
    DD    OFFSET LCA
    DD    OFFSET LCB
    DD    OFFSET LCC
    DD    OFFSET LCD
    DD    OFFSET LCE
    DD    OFFSET LCF

    DD    OFFSET LD0
    DD    OFFSET LD1
    DD    OFFSET DoNothing
    DD    OFFSET LD3
    DD    OFFSET LD4
    DD    OFFSET LD5
    DD    OFFSET LD6
    DD    OFFSET LD7
    DD    OFFSET LD8
    DD    OFFSET LD9
    DD    OFFSET DoNothing
    DD    OFFSET LDB
    DD    OFFSET LDC
    DD    OFFSET LDD
    DD    OFFSET LDE
    DD    OFFSET LDF

    DD    OFFSET LE0
    DD    OFFSET LE1
    DD    OFFSET LE2
    DD    OFFSET LE3
    DD    OFFSET LE4
    DD    OFFSET LE5
    DD    OFFSET LE6
    DD    OFFSET LE7
    DD    OFFSET LE8
    DD    OFFSET LE9
    DD    OFFSET DoNothing
    DD    OFFSET LEB
    DD    OFFSET LEC
    DD    OFFSET LED
    DD    OFFSET LEE
    DD    OFFSET LEF

    DD    OFFSET LF0
    DD    OFFSET LF1
    DD    OFFSET DoNothing
    DD    OFFSET LF3
    DD    OFFSET LF4
    DD    OFFSET LF5
    DD    OFFSET LF6
    DD    OFFSET LF7
    DD    OFFSET LF8
    DD    OFFSET LF9
    DD    OFFSET DoNothing
    DD    OFFSET LFB
    DD    OFFSET LFC
    DD    OFFSET LFD
    DD    OFFSET LFE
    DD    OFFSET LFF
@Fill:

    // Fill the Locations array with opcode code offsets

    MOV   ECX,100h
    SUB   EBX,EBX
    MOV   ESI,OFFSET @FillStart
    CLD
@FillLoop:
    MOV   EAX,DWORD PTR [ESI]
    MOV   DWORD PTR Locations[EBX],EAX
    ADD   ESI,4
    ADD   EBX,4
    LOOP  @FillLoop

    // Load the 6507 register values

    MOVZX EDI,WORD PTR Start
    ADD   EDI,OFFSET AtariSeg
    MOV   AL,BYTE PTR X
    MOV   AH,BYTE PTR Y
    MOV   CL,BYTE PTR A
    MOV   CH,BYTE PTR P
    MOV   DH,BYTE PTR S
    DEC   EDI
DoNothing:
    INC   EDI

    // --------------------------------------------------------------
    // Main emulation loop
    // --------------------------------------------------------------

EmulateLoop:
    DEC   WORD PTR Game.ReadTime
    JNZ   @NoReadTime

    MOV   BYTE PTR Game._6507_P,CH
    MOV   BYTE PTR Game._6507_A,CL
    MOV   BYTE PTR Game._6507_X,AL
    MOV   BYTE PTR Game._6507_Y,AH
    MOV   BYTE PTR Game._6507_S,DH
    PUSH  EDI
    SUB   EDI,OFFSET AtariSeg
    MOV   WORD PTR Game._6507_PC,DI
    POP   EDI

    PUSHAD
    PUSHF
    CALL  GetControllers
    POPF
    POPAD

    MOV   WORD PTR Game.ReadTime,Read_Delay

    MOV   AL,BYTE PTR AtariSeg[SWCHA1]
    MOV   BYTE PTR AtariSeg[SWCHA2],AL
    MOV   AL,BYTE PTR AtariSeg[SWCHB1]
    MOV   BYTE PTR AtariSeg[SWCHB2],AL

    MOV   CH,BYTE PTR Game._6507_P
    MOV   CL,BYTE PTR Game._6507_A
    MOV   AL,BYTE PTR Game._6507_X
    MOV   AH,BYTE PTR Game._6507_Y
    MOV   DH,BYTE PTR Game._6507_S
    MOVZX EDI,WORD PTR Game._6507_PC
    ADD   EDI,OFFSET AtariSeg

    TEST  BYTE PTR Exiting,0FFh
    JZ    @NoReadTime
    JMP   L02

@NoReadTime:


// -------------------------------
(*
    PUSHAD
    MOV   EBX,ECX
    MOV   ESI,EDX
    MOVZX EDX,CH  {P}
    MOVZX ECX,BL  {A}
    MOVZX EBX,AL  {X}
    PUSH  EBX
    MOVZX EBX,AH  {Y}
    PUSH  EBX
    MOVZX EBX,SI  {S}
    SUB   BH,BH
    PUSH  EBX
    MOV   EAX,EDI {PC}
    SUB   EAX,OFFSET AtariSeg
    CALL  ShowStatus
    POPAD
*)
// -------------------------------


    { The write cycle is the last of the instruction cycles; add the }
    { instruction cycles first.                                      }

    MOV   EBX,DWORD PTR Game.AddCycle
    LEA   EBX,[EBX + EBX * 2]
    ADD   WORD PTR Game.TIA_Count,BX

    { Now handle a write to the TIA }

    TEST  BYTE PTR Game.Write_TIA,0FFh
    JZ    @NoWriteTIA

    { If the write was to WSYNC, then Handle_IO has already properly set }
    { Game.TIA_Count, don't add the instruction time to it.                   }

    CMP   BYTE PTR Game.Write_TIA,2
    JNE   @NotWSYNC
    SUB   WORD PTR Game.TIA_Count,BX
@NotWSYNC:
    PUSH  EAX
    PUSH  EDX
    PUSH  ECX
    PUSH  EDI

    MOV   EBX,DWORD PTR Game.Save_BX
    CMP   BX,NUSIZ0
    JB    @AddDelay
    CMP   BX,NUSIZ1
    JA    @AddDelay
    TEST  WORD PTR Game.DoHMOVE,0FFh
    JZ    @AddDelay
    CMP   WORD PTR Game.TIA_Count,8
    JGE   @AddDelay
    SUB   EBX,EBX
@AddDelay:
    ADD   EBX,EBX
    MOVZX EBX,WORD PTR TIA_Delay[EBX]

    CMP   EBX,4
    JNE   @No
    SUB   BX,WORD PTR Game.TIA_Count
    DEC   BX
    AND   EBX,3

    MOV   BL,BYTE PTR PFDelay[EBX]

@No:

    MOV   SI,WORD PTR Game.TIA_Count
    ADD   WORD PTR Game.TIA_Count,BX
    PUSH  ESI
    CALL  Handle_TIA
    POP   ESI
    MOV   WORD PTR Game.TIA_Count,SI

    MOV   EBX,DWORD PTR Game.Save_BX
    MOV   AL,BYTE PTR AtariSeg[EBX]
    MOV   BYTE PTR Game.TIA_Regs[EBX],AL
    CALL  Handle_IO_After
    POP   EDI
    POP   ECX
    POP   EDX
    POP   EAX

    { See if an object's position has been reset }

    TEST  WORD PTR Game.ObjectSet,0FFh
    JZ    @NoObjectsSet

    PUSH  EBX
    PUSH  ECX
    PUSH  EDX
    PUSH  EAX

    CALL  SetObjectLocations

    POP   EAX
    POP   EDX
    POP   ECX
    POP   EBX

@NoObjectsSet:

    { If the write was to WSYNC, then the delay time has already been     }
    { figured into the correct Game.TIA_Count.  Don't subtract the delay time. }

    CMP   BYTE PTR Game.Write_TIA,2
    JE    @WSYNC
@WSYNC:
    MOV   BYTE PTR Game.Write_TIA,0
@NoWriteTIA:

    MOV   WORD PTR Game.ResetOfs,0

    CMP   BYTE PTR Game.Controller,crPaddle
    JNE   @NoPaddle

    TEST  BYTE PTR AtariSeg[VBLANK],80h
    JNZ   @NoPaddle

    CALL  SetPaddlePositions

@NoPaddle:

    { Get the next instruction here to avoid a Pentium AGI }
    { (Address Generation Interlock)                       }

    MOV   ESI,DWORD PTR [EDI]
    MOV   EBX,160                  { This sets BH to ZERO (IMPORTANT!) }
    AND   ESI,0FFh

    { Handle break on expression (check for null segment) }

    TEST  WORD PTR BreakExpColl[2],0FFFFh
    JZ    @NoBreakOnExp

    TEST  BYTE PTR DebuggerBegin,0FFh
    JNZ   @NoBreakOnExp2

    PUSH  EAX
    PUSH  EBX
    PUSH  ECX
    PUSH  EDX

    PUSH  ESI  { Save this for later }
    PUSH  EDI  { Save this for later }

    MOV   BYTE PTR Debugger_X,AL
    MOV   BYTE PTR Debugger_Y,AH
    MOV   BYTE PTR Debugger_A,CL
    MOV   BYTE PTR Debugger_P,CH
    MOV   BYTE PTR Debugger_S,DH
    SUB   EDI,OFFSET AtariSeg
    MOV   WORD PTR Debugger_PC,DI
    CALL  EvaluateBreakExp
(*
    PUSH  DWORD PTR BreakExpColl
    PUSH  OFFSET AtariSeg
    PUSH  WORD PTR Game.ObjectLoc[Player0Set * 2]
    PUSH  WORD PTR Game.ObjectLoc[Player1Set * 2]
    PUSH  WORD PTR Game.ObjectLoc[Missile0Set * 2]
    PUSH  WORD PTR Game.ObjectLoc[Missile1Set * 2]
    PUSH  WORD PTR Game.ObjectLoc[BallSet * 2]
    SUB   BH,BH
    MOV   BL,AL  { reg X }
    PUSH  BX
    MOV   BL,AH  { reg Y }
    PUSH  BX
    MOV   BL,CL  { reg A }
    PUSH  BX
    MOV   BL,CH  { reg P }
    PUSH  BX
    MOV   BL,DH  { reg S }
    PUSH  BX
    PUSH  WORD PTR Game.TIA_Count
    PUSH  WORD PTR Game.TIA_Scan
    PUSH  OFFSET ExpError
    CALL  Evaluate
*)
    POP   EDI
    POP   ESI

    TEST  AX,AX
    JZ    @NoBreakOnExp1

    MOV   AX,SI
    MOV   BYTE PTR Game.OldByte,AL
    MOV   BYTE PTR [EDI],BreakInstruction
    MOV   SI,BreakInstruction
    MOV   EAX,EDI
    SUB   EAX,OFFSET AtariSeg
    MOV   WORD PTR Game.OldStart,AX

@NoBreakOnExp1:
    POP   EDX
    POP   ECX
    POP   EBX
    POP   EAX
@NoBreakOnExp2:
    MOV   BYTE PTR DebuggerBegin,0 { Clear the first-time flag }
@NoBreakOnExp:

    { Check to see if we've reached the end of the scan line }

    CMP   WORD PTR Game.TIA_Count,BX         
    JL    @NoNewLine

    // Queue two sound samples

    CMP   WORD PTR SoundQueue_Num,1022
    JAE   @NoQueue
    PUSHAD
    CALL  QueueSoundSample
    POPAD
@NoQueue:

    // See if we have to fill the next half of the sound buffer

    INC   BYTE PTR CheckSound
    TEST  BYTE PTR CheckSound,7Fh
    JNZ   @NoCheckSound
    PUSHAD
    CALL  FillBuffer
    POPAD
@NoCheckSound:

    CMP   WORD PTR Game.Old_TIA_Count,BX
    JL    @NoOldAdjust
    MOV   WORD PTR Game.Old_TIA_Count,BX
@NoOldAdjust:

    MOV   BL,BYTE PTR Game.DoHMOVE
    MOV   BYTE PTR Game.OldDoHMOVE,BL

    ADD   DWORD PTR Game.TimerElapsed,76
    MOV   EBX,DWORD PTR Game.TimerX
    ADD   DWORD PTR Game.TimerElapsed,EBX
    MOV   DWORD PTR Game.TimerX,0
    MOV   EBX,228
    
    PUSH  EAX
    PUSH  EDX
    PUSH  ECX
    PUSH  EDI
    PUSH  ESI
    PUSH  EDI
    CALL  Handle_TIA
    POP   EDI

    MOV   EBX,DWORD PTR Game.OldPlayer0Size128
    MOV   DWORD PTR Game.Player0Size128,EBX
    MOV   EBX,DWORD PTR Game.OldPlayer1Size128
    MOV   DWORD PTR Game.Player1Size128,EBX

    MOV   EBX,DWORD PTR Game.OldMissile0SizeNum
    MOV   DWORD PTR Game.Missile0SizeNum,EBX
    MOV   EBX,DWORD PTR Game.OldMissile1SizeNum
    MOV   DWORD PTR Game.Missile1SizeNum,EBX

    MOVSX EBX,WORD PTR Game.TIA_Scan         { Ensure that BH = 0! }
    CMP   EBX,DWORD PTR MaxScan
    JGE   @DoneLines
    INC   EBX
@DoneLines:
    CMP   EBX,0
    JGE   @NotNegative
    CMP   DWORD PTR Game.HMOVECount,94
    JG    @NotNegative
    MOV   BYTE PTR Game.DoHMOVE,0
    MOV   BYTE PTR Game.OldDoHMOVE,0
@NotNegative:

    { If a player object was reset and this caused the first copy }
    { to disappear, cause the copy to reappear                    }

    CMP   DWORD PTR Game.ResetPlayer0Size128,0
    JE    @CheckResetP1
    MOV   EAX,DWORD PTR Game.OldPlayer0Size128
    MOV   DWORD PTR Game.Player0Size128,EAX
@CheckResetP1:
    CMP   DWORD PTR Game.ResetPlayer1Size128,0
    JE    @CheckResetDone
    MOV   EAX,DWORD PTR Game.OldPlayer1Size128
    MOV   DWORD PTR Game.Player1Size128,EAX
@CheckResetDone:
    MOV   DWORD PTR Game.ResetPlayer0Size128,0
    MOV   DWORD PTR Game.ResetPlayer1Size128,0

    { See if the debugger is set to halt at this scan line }

    TEST  BYTE PTR Debugger,0FFh
    JZ    @NoHalt
    CMP   EBX,DWORD PTR HaltLine
    JNE   @NoHalt
@Stop:
    POP   ESI
    MOV   EAX,ESI
    MOV   BYTE PTR Game.OldByte,AL
    MOV   BYTE PTR [EDI],BreakInstruction
    MOV   ESI,BreakInstruction
    PUSH  ESI
    MOV   EAX,EDI
    SUB   EAX,OFFSET AtariSeg
    MOV   WORD PTR Game.OldStart,AX
@NoHalt:

    { See if the emulator needs to be forced to slow down.  This is }
    { necessary every 262/314 scan lines if VSYNC is never asserted }

    PUSH  EBX
    MOV   BX,WORD PTR Game.LineDelayMax
    INC   WORD PTR Game.LineDelay
    CMP   WORD PTR Game.LineDelay,700  { Arbitrary value, should be big }
    JL    @SeeIfForceDelay

    { If a VSYNC hasn't happened by now, assume that one isn't going to }
    { happen ever, and assume NTSC/60Hz                                 }

    MOV   BYTE PTR Game.LineDelayFirst,1
@SeeIfForceDelay:
    TEST  BYTE PTR Game.LineDelayFirst,0FFh
    JZ    @NoForceDelay
@ForceDelay:
    CMP   WORD PTR Game.LineDelay,BX
    JLE   @NoForceDelay
    MOV   WORD PTR Game.LineDelay,0
//    CMP   WORD PTR Config.FrameRate,0
//    JE    @NoForceDelay
    PUSHAD
    CALL  SlowDown
    POPAD
@NoForceDelay:
    POP   EBX

    { Go to the next scan line }

    CMP   BX,WORD PTR Game.MaxRows
    JAE   @Negative
    MOV   EAX,EBX
    SHL   EAX,5
    PUSH  EBX
    SHL   EBX,7
    ADD   EAX,EBX


    MOV   EBX,DWORD PTR LocalBufSize
    SUB   EBX,160
    SUB   EBX,EAX
    MOV   EAX,EBX

    POP   EBX
@SetAddress:
    MOV   DWORD PTR Game.Addr,EAX
    MOV   WORD PTR Game.LineStart,AX

@Negative:

    MOV   AL,BYTE PTR Game.BallLatch
    MOV   BYTE PTR AtariSeg[ENABL],AL
    AND   BYTE PTR Game.DispJump,0FDh
    TEST  AL,2
    JZ    @LVDELBL
    OR    BYTE PTR Game.DispJump,2h
@LVDELBL:


    MOV   AX,WORD PTR AtariSeg[GRP0]
    MOV   WORD PTR Game.TIA_Regs[GRP0],AX

    SUB   WORD PTR Game.TIA_Count,228
    MOV   WORD PTR Game.Old_TIA_Count,-68

    POP   ESI
    POP   EDI
    POP   ECX
    POP   EDX
    POP   EAX
    MOV   WORD PTR Game.TIA_Scan,BX
    AND   EBX,0FFh
//    SUB   BH,BH
    AND   BYTE PTR Game.DispJump,0FDh      { Turn ball off }
    TEST  BYTE PTR AtariSeg[ENABL],2
    JZ    @NoNewLine
    OR    BYTE PTR Game.DispJump,2         { Display the ball }
@NoNewLine:
    MOV   DL,BYTE PTR Cycles[ESI]
    SHL   ESI,2
    MOV   BYTE PTR Game.AddCycle,DL
    JMP   DWORD PTR Locations[ESI]
  End; { Asm }

{ --------------------------- Assembly emulator --------------------------- }

L00:                 { BRK }

  Asm
    DEC    DH
    MOV    BL,DH

    ADD    EDI,2
    SUB    EDI,OFFSET AtariSeg

    PUSH   EDI
    AND    WORD PTR Game.Hi3,0E000h
    OR     DI,WORD PTR Game.Hi3
    MOV    WORD PTR AtariSeg[EBX],DI
    POP    EDI

    ADD    EDI,OFFSET AtariSeg


    MOV    WORD PTR Game.ResetOfs,-12

    INC    BL
    PUSH   EBX
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    POP    EBX
    DEC    BL

    PUSH   EBX
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    POP    EBX

    DEC    BL
    MOV    BYTE PTR AtariSeg[EBX],CH

    PUSH   EBX
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    POP    EBX

    SUB    DH,2
    OR     CH,014h
    MOV    DI,WORD PTR AtariSeg[1FFEh]        { 6502: [0FFFEh] }

    MOV    WORD PTR Game.Hi3,DI

    AND    EDI,01FFFh        { Atari can only address 8K }
    ADD    EDI,OFFSET AtariSeg
    JMP    EmulateLoop
  End; { Asm }

L01:                 { ORA ind. x }

 Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh         { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,07Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    OR     CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    OR     CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L02:                 { Breakpoint instruction }

  Asm
    MOV   BYTE PTR X,AL
    MOV   BYTE PTR Y,AH
    MOV   BYTE PTR A,CL
    MOV   BYTE PTR P,CH
    MOV   BYTE PTR S,DH
    SUB   EDI,OFFSET AtariSeg
    MOV   WORD PTR Start,DI
    POPAD
    JMP   GetOut
  End; { Asm }

L03:                 { SLO ind. x - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh         { Atari can only address 8K }
    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,07Ch
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,BYTE PTR AtariSeg[EBX]
    RCL    DL,1
    JNC    @L2
    OR     CH,1
@L2:
    OR     DL,CL
    MOV    BYTE PTR AtariSeg[EBX],DH
    JZ     @L1
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,BYTE PTR AtariSeg[EBX]
    RCL    DL,1
    JNC    @L2a
    OR     CH,1
  @L2a:
    OR     DL,CL
    MOV    BYTE PTR AtariSeg[EBX],DH
    JZ     @L1
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L04:                 { SKB Quasi-Opcode }

  Asm
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L05:                 { ORA zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    AND    CH,07Dh

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    OR     CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    OR     CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L06:                 { ASL zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    OR     CH,3

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX

    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    SHL    DL,1

    JC     @L2A
    AND    CH,0FEh
  @L2A:
    OR     DL,DL
    JZ     @L1A
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
  @L1A:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop

@NotCrit:
    OR     CH,3
    SHL    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L07:                 { SLO zero page - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,07Ch
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,BYTE PTR AtariSeg[EBX]
    RCL    DL,1
    JNC    @L2
    OR     CH,1
@L2:
    OR     DL,CL
    MOV    BYTE PTR AtariSeg[EBX],DH
    JZ     @L1
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,BYTE PTR AtariSeg[EBX]
    RCL    DL,1
    JNC    @L2a
    OR     CH,1
  @L2a:
    OR     DL,CL
    MOV    BYTE PTR AtariSeg[EBX],DH
    JZ     @L1
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L08:                 { PHP }

  Asm
    MOV    BL,DH

    TEST   BYTE PTR Game.BankSwitch[EBX + 100h],0FFh
    JZ     @NoSwitch
    ADD    BX,100h
    CALL   SwitchBank
    SUB    BX,100h
@NoSwitch:
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    MOV    BYTE PTR AtariSeg[EBX],CH
    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    DEC    DH
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L09:                 { ORA immediate }

  Asm
    OR     CL,BYTE PTR [EDI+1]
    JZ     @L1
    MOV    DL,CL
    AND    CH,7Dh
    AND    DL,80h
    ADD    EDI,2
    ADD    CH,DL
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    OR     CH,02h
    JMP    EmulateLoop
  End; { Asm }

L0A:                 { ASL accum. }

  Asm
    OR     CH,3
    ADD    CL,CL
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    CH,7Dh
    AND    DL,80h
    INC    EDI
    ADD    CH,DL
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L0B:                 { ANC immediate - UNDOCUMENTED }

  Asm
    AND    CL,BYTE PTR [EDI+1]
    JZ     @L1
    MOV    DL,CL
    AND    CH,7Dh
    AND    DL,80h
    ADD    EDI,2
    ADD    CH,DL
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    OR     CH,02h
    JMP    EmulateLoop
  End; { Asm }

L0C:                 { SKW Quasi-Opcode }

  Asm
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L0D:                { ORA absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh         { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    OR     CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    OR     CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L0E:                 { ASL absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh         { Atari can only address 8K }


    CMP    BX,1000h
    JB     @NotROM

    CMP    BYTE PTR Game.Cart,ctStarpath
    JE     @NotROM
    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JNZ    @NotROM
    ADD    EDI,3
    JMP    EmulateLoop
@NotROM:

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    OR     CH,3
    SHL    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L0F:                 { SLO absolute - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,07Ch
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,BYTE PTR AtariSeg[EBX]
    RCL    DL,1
    JNC    @L2
    OR     CH,1
@L2:
    OR     DL,CL
    MOV    BYTE PTR AtariSeg[EBX],DH
    JZ     @L1
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,BYTE PTR AtariSeg[EBX]
    RCL    DL,1
    JNC    @L2a
    OR     CH,1
  @L2a:
    OR     DL,CL
    MOV    BYTE PTR AtariSeg[EBX],DH
    JZ     @L1
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L10:                 { BPL }

  Asm
    TEST   CH,80h
    JNZ    @L1
    MOVSX  EBX,BYTE PTR [EDI+1]
    ADD    EDI,2
    PUSH   EAX
    SUB    EDI,OFFSET AtariSeg
    MOV    EAX,EDI
    ADD    EDI,EBX
    INC    DWORD PTR Game.AddCycle
    MOV    EBX,EDI
    ADD    EDI,OFFSET AtariSeg
    CMP    BH,AH
    JE     @L2
    INC    DWORD PTR Game.AddCycle
@L2:
    POP    EAX
    JMP    EmulateLoop
@L1:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L11:                 { ORA ind. y }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    OR     CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    OR     CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L12:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L13:                 { SLO ind. y - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    MOV    BL,BYTE PTR [EDI+1]
    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,07Ch
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,BYTE PTR AtariSeg[EBX]
    RCL    DL,1
    JNC    @L2
    OR     CH,1
@L2:
    OR     DL,CL
    MOV    BYTE PTR AtariSeg[EBX],DH
    JZ     @L1
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,BYTE PTR AtariSeg[EBX]
    RCL    DL,1
    JNC    @L2a
    OR     CH,1
  @L2a:
    OR     DL,CL
    MOV    BYTE PTR AtariSeg[EBX],DH
    JZ     @L1
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L14:                 { SKB Quasi-Opcode }

  Asm
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L15:                 { ORA z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    OR     CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    OR     CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L16:                 { ASL z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    OR     CH,3
    SHL    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L17:                 { SLO z. page x - UNDOCUMENTED }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    MOV    BL,BYTE PTR [EDI+1]
    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,07Ch
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,BYTE PTR AtariSeg[EBX]
    RCL    DL,1
    JNC    @L2
    OR     CH,1
@L2:
    OR     DL,CL
    MOV    BYTE PTR AtariSeg[EBX],DH
    JZ     @L1
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,BYTE PTR AtariSeg[EBX]
    RCL    DL,1
    JNC    @L2a
    OR     CH,1
  @L2a:
    OR     DL,CL
    MOV    BYTE PTR AtariSeg[EBX],DH
    JZ     @L1
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L18:                 { CLC }

  Asm
    AND    CH,0FEh
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L19:                 { ORA abs. y }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    OR     CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    OR     CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L1A:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L1B:                 { SLO abs. y - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    CMP    BX,1000h
    JB     @NotROM

    CMP    BYTE PTR Game.Cart,ctStarpath
    JE     @NotROM
    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JNZ    @NotROM
    ADD    EDI,3
    JMP    EmulateLoop
@NotROM:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,07Ch
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,BYTE PTR AtariSeg[EBX]
    RCL    DL,1
    JNC    @L2
    OR     CH,1
@L2:
    OR     DL,CL
    MOV    BYTE PTR AtariSeg[EBX],DH
    JZ     @L1
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,BYTE PTR AtariSeg[EBX]
    RCL    DL,1
    JNC    @L2a
    OR     CH,1
  @L2a:
    OR     DL,CL
    MOV    BYTE PTR AtariSeg[EBX],DH
    JZ     @L1
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L1C:                 { SKW Quasi-Opcode }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BYTE PTR Game.AddCycle,DL
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L1D:                 { ORA abs. x }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    OR     CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    OR     CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L1E:                 { ASL abs. x }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    ADC    BH,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    CMP    BX,1000h
    JB     @NotROM
    CMP    BYTE PTR Game.Cart,ctStarpath
    JE     @NotROM
    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JNZ    @NotROM

    OR     CH,3
    MOV    DL,BYTE PTR AtariSeg[EBX]
    SHL    DL,1
    JMP    @L3

@NotROM:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    OR     CH,3
    SHL    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L3:
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L1F:                 { SLO abs. x - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,07Ch
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,BYTE PTR AtariSeg[EBX]
    RCL    DL,1
    JNC    @L2
    OR     CH,1
@L2:
    OR     DL,CL
    MOV    BYTE PTR AtariSeg[EBX],DH
    JZ     @L1
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,BYTE PTR AtariSeg[EBX]
    RCL    DL,1
    JNC    @L2a
    OR     CH,1
@L2a:
    OR     DL,CL
    MOV    BYTE PTR AtariSeg[EBX],DH
    JZ     @L1
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L20:                 { JSR }

  Asm
    DEC    DH
    MOV    BL,DH

    PUSH   EDI
    SUB    EDI,OFFSET AtariSeg
    AND    WORD PTR Game.Hi3,0E000h
    OR     DI,WORD PTR Game.Hi3
    MOV    WORD PTR AtariSeg[EBX],DI
    POP    EDI

    ADD    WORD PTR AtariSeg[EBX],2
    DEC    DH

    MOVZX  EDI,WORD PTR [EDI+1]

    MOV    WORD PTR Game.Hi3,DI

    TEST   BYTE PTR Game.BankSwitch[EBX + 100h],0FFh
    JZ     @NoActivision
    CMP    BYTE PTR Game.Cart,ctPitfall2
    JNE    @NoPitfall2
    XOR    DI,2000h        { Pitfall II Game.BankSwitching is reversed }
@NoPitfall2:
    TEST   DI,2000h
    JZ     @Act1
    CMP    BYTE PTR Game.CurrentBank,0
    JNE    @Act1a
    MOV    BYTE PTR Game.BankSwitch[EBX + 100h],1     { Already at 1 }
    JMP    @Act2
@Act1A:
    MOV    BYTE PTR Game.BankSwitch[EBX + 100h],31    { Switching to 1 }
    JMP    @Act2

@Act1:
    CMP    BYTE PTR Game.CurrentBank,4
    JNE    @Act2a
    MOV    BYTE PTR Game.BankSwitch[EBX + 100h],5     { Already at 2 }
    JMP    @Act2
@Act2a:
    MOV    BYTE PTR Game.BankSwitch[EBX + 100h],30    { Switching to 2 }
@Act2:
    ADD    BX,100h
    ADD    EDI,OFFSET AtariSeg
    CALL   SwitchBank
    SUB    EDI,OFFSET AtariSeg
    SUB    BX,100h
@NoActivision:

    AND    EDI,1FFFh         { Atari can only address 8K }
    ADD    EDI,OFFSET AtariSeg
    JMP    EmulateLoop
  End; { Asm }

L21:                 { AND ind. x }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    AND    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    AND    CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End;{ Asm }

L22:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L23:                 { RLA ind. x - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX

    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    RCL    DL,1
    JC     @L2a
    AND    CH,0FEh
  @L2a:
    AND    CL,DL
    MOV    DL,CL
    OR     DL,DL

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCL    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    AND    CL,DL
    MOV    DL,CL
    OR     DL,DL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L24:                 { BIT zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    BL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    MOV    DL,BL
    AND    DL,CL
    JZ     @L1
    AND    CH,3Dh
    AND    BL,0C0h
    OR     CH,BL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    BL,BYTE PTR AtariSeg[EBX]
    MOV    DL,BL
    AND    DL,CL
    JZ     @L1
    AND    CH,3Dh
    AND    BL,0C0h
    OR     CH,BL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    AND    CH,3Fh
    AND    BL,0C0h
    OR     CH,BL
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L25:                 { AND zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    AND    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    AND    CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L26:                 { ROL zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    RCL    DL,1
    JC     @L2a
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCL    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L27:                 { RLA zero page - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    RCL    DL,1
    JC     @L2a
    AND    CH,0FEh
  @L2a:
    AND    CL,DL
    MOV    DL,CL
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCL    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    AND    CL,DL
    MOV    DL,CL
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L28:                 { PLP }

  Asm
    INC    DH
    MOV    BL,DH

    TEST   BYTE PTR Game.BankSwitch[EBX + 100h],0FFh
    JZ     @NoSwitch
    ADD    BX,100h
    CALL   SwitchBank
    SUB    BX,100h
@NoSwitch:

    MOV    CH,BYTE PTR AtariSeg[EBX]
    OR     CH,20h
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L29:                 { AND immediate }

  Asm
    AND    CL,BYTE PTR [EDI+1]
    JZ     @L1
    MOV    DL,CL
    AND    CH,7Dh
    AND    DL,80h
    ADD    EDI,2
    ADD    CH,DL
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    OR     CH,02h
    JMP    EmulateLoop
  End; { Asm }

L2A:                 { ROL accum. }

  Asm
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCL    CL,1
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    CH,7Dh
    AND    DL,80h
    INC    EDI
    ADD    CH,DL
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L2B:                 { ANC immediate - UNDOCUMENTED }

  Asm
    AND    CL,BYTE PTR [EDI+1]
    JZ     @L1
    MOV    DL,CL
    AND    CH,7Dh
    AND    DL,80h
    ADD    EDI,2
    ADD    CH,DL
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    OR     CH,02h
    JMP    EmulateLoop
  End; { Asm }

L2C:                 { BIT absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    BL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    MOV    DL,BL
    AND    DL,CL
    JZ     @L1
    AND    CH,3Dh
    AND    BL,0C0h
    OR     CH,BL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    BL,BYTE PTR AtariSeg[EBX]
    MOV    DL,BL
    AND    DL,CL
    JZ     @L1
    AND    CH,3Dh
    AND    BL,0C0h
    OR     CH,BL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    AND    CH,3Fh
    AND    BL,0C0h
    OR     CH,BL
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L2D:                 { AND absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    AND    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    AND    CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L2E:                 { ROL absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    RCL    DL,1
    JC     @L2a
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCL    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L2F:                 { RLA absolute - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    RCL    DL,1
    JC     @L2a
    AND    CH,0FEh
  @L2a:
    AND    CL,DL
    MOV    DL,CL
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCL    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    AND    CL,DL
    MOV    DL,CL
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L30:                 { BMI }

  Asm
    TEST   CH,80h
    JZ     @L1
    MOVSX  EBX,BYTE PTR [EDI+1] 
    ADD    EDI,2
    PUSH   EAX
    SUB    EDI,OFFSET AtariSeg
    MOV    EAX,EDI
    ADD    EDI,EBX
    INC    DWORD PTR Game.AddCycle
    MOV    EBX,EDI
    ADD    EDI,OFFSET AtariSeg
    CMP    BH,AH
    JE     @L2
    INC    DWORD PTR Game.AddCycle
@L2:
    POP    EAX
    JMP    EmulateLoop
@L1:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L31:                 { AND ind. y }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    AND    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    AND    CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L32:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L33:                 { RLA ind. y - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX

    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    RCL    DL,1
    JC     @L2a
    AND    CH,0FEh
  @L2a:
    AND    CL,DL
    MOV    DL,CL
    OR     DL,DL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:

    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCL    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    AND    CL,DL
    MOV    DL,CL
    OR     DL,DL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L34:                 { SKB Quasi-Opcode }

  Asm
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L35:                 { AND z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    AND    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    AND    CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L36:                 { ROL z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    RCL    DL,1
    JC     @L2a
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:

    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCL    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L37:                 { RLA z. page x - UNDOCUMENTED }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    RCL    DL,1
    JC     @L2a
    AND    CH,0FEh
  @L2a:
    AND    CL,DL
    MOV    DL,CL
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:

    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCL    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    AND    CL,DL
    MOV    DL,CL
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L38:                 { SEC }

  Asm
    OR     CH,01h
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L39:                 { AND abs. y }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    AND    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    AND    CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L3A:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L3B:                 { RLA abs. y - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX

    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    RCL    DL,1
    JC     @L2a
    AND    CH,0FEh
  @L2a:
    AND    CL,DL
    MOV    DL,CL
    OR     DL,DL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:

    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCL    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    AND    CL,DL
    MOV    DL,CL
    OR     DL,DL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L3C:                 { SKW Quasi-Opcode }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BYTE PTR Game.AddCycle,DL
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L3D:                 { AND abs. x }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    AND    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    AND    CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L3E:                 { ROL abs. x }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    ADC    BH,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    RCL    DL,1
    JC     @L2a
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCL    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L3F:                 { RLA abs. x - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    ADC    BH,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    RCL    DL,1
    JC     @L2a
    AND    CH,0FEh
  @L2a:
    AND    CL,DL
    MOV    DL,CL
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCL    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    AND    CL,DL
    MOV    DL,CL
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L40:                 { RTI }

  Asm
    INC    DH
    MOV    BL,DH
    MOV    CH,BYTE PTR AtariSeg[EBX]

    OR     CH,20h
    INC    BL
    MOV    DI,WORD PTR AtariSeg[EBX]

    MOV    WORD PTR Game.Hi3,DI

    AND    EDI,01FFFh         { Atari can only address 8K }
    ADD    EDI,OFFSET AtariSeg
    ADD    DH,2
    JMP    EmulateLoop
  End; { Asm }

L41:                 { EOR ind. x }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    XOR    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    XOR    CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L42:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L43:                 { SRE ind. x - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:
    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:
    OR     CH,3
    SHR    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    XOR    CL,DL
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L44:                 { SKB Quasi-Opcode }

  Asm
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L45:                 { EOR zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,07Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    XOR    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    XOR    CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L46:                 { LSR zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    OR     CH,3
    SHR    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L47:                 { SRE zero page - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    OR     CH,3
    SHR    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    XOR    CL,DL
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L48:                 { PHA }

  Asm
    MOV    BL,DH

    TEST   BYTE PTR Game.BankSwitch[EBX + 100h],0FFh
    JZ     @NoSwitch
    ADD    BX,100h
    CALL   SwitchBank
    SUB    BX,100h
@NoSwitch:
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    MOV    BYTE PTR AtariSeg[EBX],CL
    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    DEC    DH
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L49:                 { EOR immediate }

  Asm
    XOR    CL,BYTE PTR [EDI+1]
    JZ     @L1
    MOV    DL,CL
    AND    CH,7Dh
    AND    DL,80h
    ADD    EDI,2
    ADD    CH,DL
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    OR     CH,02h
    JMP    EmulateLoop
  End; { Asm }

L4A:                 { LSR accum. }

  Asm
    OR     CH,3
    SHR    CL,1
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    INC    EDI
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L4B:                 { ASR immediate - UNDOCUMENTED }

  Asm
    XOR    CL,BYTE PTR [EDI+1]
    OR     CH,3
    SHR    CL,1
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    CH,7Dh
    AND    DL,80h
    ADD    EDI,2
    ADD    CH,DL
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    OR     CH,02h
    JMP    EmulateLoop
  End; { Asm }

L4C:                 { JMP absolute }

  Asm
    MOV    DI,WORD PTR [EDI+1]

    MOV    WORD PTR Game.Hi3,DI

    AND    EDI,1FFFh         { Atari can only address 8K }
    ADD    EDI,OFFSET AtariSeg
    JMP    EmulateLoop
  End; { Asm }

L4D:                 { EOR absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh         { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    XOR    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    XOR    CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L4E:                 { LSR absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    CMP    BX,1000h
    JB     @NotROM
    CMP    BYTE PTR Game.Cart,ctStarpath
    JE     @NotROM
    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JNZ    @NotROM
@ReadOnly:
    OR     CH,3
    MOV    DL,BYTE PTR AtariSeg[EBX]
    SHR    DL,1
    JMP    @L3
    
@NotROM:
    CMP    BX,100h
    JB     @ReadWrite
    CMP    BX,1000h
    JAE    @ReadWrite
    JMP    @ReadOnly

@ReadWrite:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    OR     CH,3
    SHR    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L3:
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L4F:                 { SRE absolute - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    OR     CH,3
    SHR    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    XOR    CL,DL
    MOV    Dl,CL
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L50:                 { BVC }

  Asm
    TEST   CH,040h
    JNZ    @L1
    MOVSX  EBX,BYTE PTR [EDI+1]
    ADD    EDI,2
    PUSH   EAX
    SUB    EDI,OFFSET AtariSeg
    MOV    EAX,EDI
    ADD    EDI,EBX
    INC    DWORD PTR Game.AddCycle
    MOV    EBX,EDI
    ADD    EDI,OFFSET AtariSeg
    CMP    BH,AH
    JE     @L2
    INC    DWORD PTR Game.AddCycle
@L2:
    POP    EAX
    JMP    EmulateLoop
@L1:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L51:                 { EOR ind. y }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    XOR    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    XOR    CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L52:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L53:                 { SRE ind. y - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:
    OR     CH,3
    SHR    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    XOR    CL,DL
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L54:                 { SKB Quasi-Opcode }

  Asm
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L55:                 { EOR z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    XOR    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    XOR    CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L56:                 { LSR z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    OR     CH,3
    SHR    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L57:                 { SRE z. page x - UNDOCUMENTED }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    OR     CH,3
    SHR    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    XOR    CL,DL
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L58:                 { CLI }

  Asm
    AND    CH,0FBh
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L59:                 { EOR abs. y }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    XOR    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    XOR    CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L5A:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L5B:                 { SRE abs. y - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    OR     CH,3
    SHR    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    XOR    CL,DL
    MOV    DL,CL
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L5C:                 { SKW Quasi-Opcode }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BYTE PTR Game.AddCycle,DL
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L5D:                 { EOR abs. x }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    XOR    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    XOR    CL,BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L5E:                 { LSR abs. x }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    ADC    BH,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    OR     CH,3
    SHR    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L5F:                 { SRE abs. x - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    ADC    BH,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    OR     CH,3
    SHR    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    XOR    CL,DL
    MOV    DL,CL
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L60:                 { RTS }

  Asm
    MOV    ESI,EDI

    INC    DH
    MOV    BL,DH
    MOVZX  EDI,WORD PTR AtariSeg[EBX]
    INC    EDI

    MOV    WORD PTR Game.Hi3,DI

    AND    EDI,01FFFh         { Atari can only address 8K }
    ADD    EDI,OFFSET AtariSeg
    TEST   BYTE PTR Game.BankSwitch[EBX + 100h],0FFh
    JZ     @NoSwitch
    ADD    BX,100h
    PUSH   ESI
    CALL   SwitchBank
    POP    ESI
    SUB    BX,100h
@NoSwitch:
    TEST   BYTE PTR Game.BankSwitch[EBX + 101h],0FFh
    JZ     @NoSwitch1
    ADD    BX,101h
    PUSH   ESI
    CALL   SwitchBank
    POP    ESI
    SUB    BX,101h
@NoSwitch1:
    INC    DH

    CMP    BYTE PTR Game.Cart,ctStarpath
    JNE    @NotStarpath
    CMP    ESI,(OFFSET AtariSeg) + 1FF8h
    JNE    @NotStarpath
    CALL   HandleStarpathRTS
@NotStarpath:
    JMP    EmulateLoop
  End; { Asm }

L61:                 { ADC ind. x }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    OR     CH,43h
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF
    ADC    CL,BYTE PTR Game.Input_Byte[EBX]

    PUSH   EAX
    LAHF
    JO     @L1
    AND    CH,0BFh
@L1:
    MOV    DL,AH
    AND    CH,7Ch
    AND    AH,81h
    SHR    DL,5
    OR     CH,AH
    AND    DL,2
    OR     CH,DL
    POP    EAX
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    POPF
    ADC    CL,BYTE PTR AtariSeg[EBX]

    PUSH   EAX
    LAHF
    JO     @L1a
    AND    CH,0BFh
@L1a:
    MOV    DL,AH
    AND    CH,7Ch
    AND    AH,81h
    SHR    DL,5
    OR     CH,AH
    AND    DL,2
    OR     CH,DL
    POP    EAX
    ADD    EDI,2
    JMP    EmulateLoop
  @BCD:
    MOV    DL,CH
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    CMP    BX,80h
    JAE    @NotCrit1
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF

    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    CALL   ADC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit1:
    POPF

    MOV    DL,BYTE PTR AtariSeg[EBX]
    CALL   ADC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L62:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L63:                 { RRA ind. x - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    JMP    @L4
@NotCrit:
    CMP    BX,400h
    JAE    @L3
    AND    BX,2FFh
@L3:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L4:
    MOV    ESI,EBX
    MOV    BL,DL
    RCR    DL,1
    MOV    BH,BL                 { Set the overflow flag  }
    XOR    BH,DL                 { V=(New OR Old) AND 40h }
    AND    BH,40h
    AND    CH,0BFh
    OR     CH,BH
    TEST   CH,8                  { See if we're in decimal mode }
    JNZ    @BCD
    ROL    BL,1                  { Set carry flag = (Old AND 80h) }
    AND    BL,1
    AND    CH,0FEh
    OR     CH,BL
    MOV    BYTE PTR AtariSeg[ESI],DL
    ADD    EDI,2
    JMP    EmulateLoop
@BCD:
    MOV    BH,BL                 { BCD fixup 1 }
    AND    BH,0Fh
    CMP    BH,4
    JLE    @BCD1
    MOV    BH,DL
    ADD    BH,6
    AND    BH,0Fh
    AND    DL,0F0h
    OR     DL,BH
@BCD1:
    AND    CH,0FEh
    CMP    BL,4Fh
    JLE    @BCD2
    ADD    DL,60h
    OR     CH,1
@BCD2:
    MOV    BYTE PTR AtariSeg[ESI],DL
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L64:                 { SKB Quasi-Opcode }

  Asm
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L65:                 { ADC zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    OR     CH,43h
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF
    ADC    CL,BYTE PTR Game.Input_Byte[EBX]

    PUSH   EAX
    LAHF
    JO     @L1
    AND    CH,0BFh
@L1:
    MOV    DL,AH
    AND    CH,7Ch
    AND    AH,81h
    SHR    DL,5
    OR     CH,AH
    AND    DL,2
    OR     CH,DL
    POP    EAX
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    POPF
    ADC    CL,BYTE PTR AtariSeg[EBX]

    PUSH   EAX
    LAHF
    JO     @L1a
    AND    CH,0BFh
@L1a:
    MOV    DL,AH
    AND    CH,7Ch
    AND    AH,81h
    SHR    DL,5
    OR     CH,AH
    AND    DL,2
    OR     CH,DL
    POP    EAX
    ADD    EDI,2
    JMP    EmulateLoop
  @BCD:
    MOV    DL,CH
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    CMP    BX,80h
    JAE    @NotCrit1
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF

    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    CALL   ADC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit1:
    POPF

    MOV    DL,BYTE PTR AtariSeg[EBX]
    CALL   ADC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L66:                 { ROR zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    RCR    DL,1
    JC     @L2a
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCR    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L67:                 { RRA zero page - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    JMP    @L4
@NotCrit:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L4:
    MOV    ESI,EBX
    MOV    BL,DL
    RCR    DL,1
    MOV    BH,BL                 { Set the overflow flag  }
    XOR    BH,DL                 { V=(New OR Old) AND 40h }
    AND    BH,40h
    AND    CH,0BFh
    OR     CH,BH
    TEST   CH,8                  { See if we're in decimal mode }
    JNZ    @BCD
    ROL    BL,1                  { Set carry flag = (Old AND 80h) }
    AND    BL,1
    AND    CH,0FEh
    OR     CH,BL
    MOV    BYTE PTR AtariSeg[ESI],DL
    ADD    EDI,2
    JMP    EmulateLoop
@BCD:
    MOV    BH,BL                 { BCD fixup 1 }
    AND    BH,0Fh
    CMP    BH,4
    JLE    @BCD1
    MOV    BH,DL
    ADD    BH,6
    AND    BH,0Fh
    AND    DL,0F0h
    OR     DL,BH
@BCD1:
    AND    CH,0FEh
    CMP    BL,4Fh
    JLE    @BCD2
    ADD    DL,60h
    OR     CH,1
@BCD2:
    MOV    BYTE PTR AtariSeg[ESI],DL
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L68:                 { PLA }

  Asm
    INC    DH
    AND    CH,7Dh
    MOV    BL,DH

    TEST   BYTE PTR Game.BankSwitch[EBX + 100h],0FFh
    JZ     @NoSwitch
    ADD    BX,100h
    CALL   SwitchBank
    SUB    BX,100h
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    INC    EDI
    JMP    EmulateLoop
@NotCrit:
    MOV    CL,BYTE PTR AtariSeg[EBX]
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    INC    EDI
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L69:                 { ADC immediate }

  Asm
    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    OR     CH,43h
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    ADC    CL,BYTE PTR [EDI+1]

    PUSH   EAX
    LAHF
    JO     @L1
    AND    CH,0BFh
@L1:
    MOV    DL,AH
    AND    CH,7Ch
    AND    AH,81h
    SHR    DL,5
    OR     CH,AH
    AND    DL,2
    OR     CH,DL
    POP    EAX
    ADD    EDI,2
    JMP    EmulateLoop
  @BCD:
    MOV    DL,CH
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }

    MOV    DL,BYTE PTR [EDI+1]
    CALL   ADC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L6A:                 { ROR accum. }

  Asm
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCR    CL,1
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    CH,7Dh
    AND    DL,80h
    INC    EDI
    ADD    CH,DL
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L6B:                 { ARR immediate - UNDOCUMENTED }

  Asm
    TEST   CH,8
    JNZ    @BCD
    AND    CH,3Ch
    AND    CL,BYTE PTR [EDI+1]
    RCR    CL,1
    TEST   CL,CL     { Set the zero flag }
    JNZ    @L1
    OR     CH,2
@L1:
    MOV    DL,CL     { Set the negative flag }
    AND    DL,80h
    OR     CH,DL
    MOV    DL,CL     { Set the carry flag }
    SHR    DL,6
    AND    DL,1
    OR     CH,DL
    MOV    DL,CL     { Set the overflow flag }
    SHL    DL,1
    XOR    DL,CL
    AND    DL,40h
    OR     CH,DL
    INC    EDI
    JMP    EmulateLoop
@BCD:
    AND    CH,3Ch
    MOV    DL,CL
    AND    DL,BYTE PTR [EDI+1]
    MOV    BL,CH     { Set the negative flag }
    ROR    BL,1
    AND    BL,80h
    OR     CH,BL
    MOV    BH,DL     { Set the zero flag -- note that it's reversed }
    SHR    BH,1
    OR     BH,BL
    MOV    CL,BH
    TEST   CL,CL
    JZ     @L2
    OR     CH,2
@L2:
    MOV    BL,DL     { Set the overflow flag }
    XOR    BL,CL
    AND    BL,40h
    OR     CH,BL

    MOV    BH,CL     { BCD fixup 1 -- low nibble }
    MOV    BL,CL
    AND    BX,0F01h
    ADD    BL,BH
    CMP    BL,5
    JLE    @L3
    AND    CL,0F0h
    ADD    BH,6
    AND    BH,0Fh
    OR     CL,BH
@L3:
    MOV    BH,CL     { BCD fixup 2 -- high nibble }
    MOV    BL,CL
    AND    BX,0F010h
    ADD    BL,BH
    CMP    BL,50h
    JLE    @L4
    OR     CH,1
    ADD    CL,60h
@L4:
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L6C:                 { JMP indirect }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh              { Atari can only address 8K }
    CMP    BX,200h
    JAE    @NoChop
    SUB    BH,BH
@NoChop:
    MOV    DL,BYTE PTR AtariSeg[EBX]
    INC    BL
    MOV    BH,BYTE PTR AtariSeg[EBX]
    MOV    BL,DL
    MOV    DI,BX

    MOV    WORD PTR Game.Hi3,DI

    AND    EDI,1FFFh              { Atari can only address 8K }
    ADD    EDI,OFFSET AtariSeg
    JMP    EmulateLoop
  End; { Asm }

L6D:                 { ADC absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    OR     CH,43h
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF
    ADC    CL,BYTE PTR Game.Input_Byte[EBX]

    PUSH   EAX
    LAHF
    JO     @L1
    AND    CH,0BFh
@L1:
    MOV    DL,AH
    AND    CH,7Ch
    AND    AH,81h
    SHR    DL,5
    OR     CH,AH
    AND    DL,2
    OR     CH,DL
    POP    EAX
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    POPF
    ADC    CL,BYTE PTR AtariSeg[EBX]

    PUSH   EAX
    LAHF
    JO     @L1a
    AND    CH,0BFh
@L1a:
    MOV    DL,AH
    AND    CH,7Ch
    AND    AH,81h
    SHR    DL,5
    OR     CH,AH
    AND    DL,2
    OR     CH,DL
    POP    EAX
    ADD    EDI,3
    JMP    EmulateLoop
  @BCD:
    MOV    DL,CH
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    CMP    BX,80h
    JAE    @NotCrit1
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF

    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    CALL   ADC_BCD
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit1:
    POPF

    MOV    DL,BYTE PTR AtariSeg[EBX]
    CALL   ADC_BCD
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L6E:                 { ROR absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    RCR    DL,1
    JC     @L2a
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    CMP    BX,400h
    JAE    @L3
    AND    BX,2FFh
    CMP    BX,SWCHB1
    JNE    @L3
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    RCR    DL,1
    JMP    @L4
@L3:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCR    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L4:
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L6F:                 { RRA absolute - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    JMP    @L4
@NotCrit:
    CMP    BX,400h
    JAE    @L3
    AND    BX,2FFh
@L3:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L4:
    MOV    ESI,EBX
    MOV    BL,DL
    RCR    DL,1
    MOV    BH,BL                 { Set the overflow flag  }
    XOR    BH,DL                 { V=(New OR Old) AND 40h }
    AND    BH,40h
    AND    CH,0BFh
    OR     CH,BH
    TEST   CH,8                  { See if we're in decimal mode }
    JNZ    @BCD
    ROL    BL,1                  { Set carry flag = (Old AND 80h) }
    AND    BL,1
    AND    CH,0FEh
    OR     CH,BL
    MOV    BYTE PTR AtariSeg[ESI],DL
    ADD    EDI,3
    JMP    EmulateLoop
@BCD:
    MOV    BH,BL                 { BCD fixup 1 }
    AND    BH,0Fh
    CMP    BH,4
    JLE    @BCD1
    MOV    BH,DL
    ADD    BH,6
    AND    BH,0Fh
    AND    DL,0F0h
    OR     DL,BH
@BCD1:
    AND    CH,0FEh
    CMP    BL,4Fh
    JLE    @BCD2
    ADD    DL,60h
    OR     CH,1
@BCD2:
    MOV    BYTE PTR AtariSeg[ESI],DL
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L70:                 { BVS }

  Asm
    TEST   CH,40h
    JZ     @L1
    MOVSX  EBX,BYTE PTR [EDI+1]
    ADD    EDI,2
    PUSH   EAX
    SUB    EDI,OFFSET AtariSeg
    MOV    EAX,EDI
    ADD    EDI,EBX
    INC    DWORD PTR Game.AddCycle
    MOV    EBX,EDI
    ADD    EDI,OFFSET AtariSeg
    CMP    BH,AH
    JE     @L2
    INC    DWORD PTR Game.AddCycle
@L2:
    POP    EAX
    JMP    EmulateLoop
@L1:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L71:                 { ADC ind. y }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    OR     CH,43h
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF
    ADC    CL,BYTE PTR Game.Input_Byte[EBX]

    PUSH   EAX
    LAHF
    JO     @L1
    AND    CH,0BFh
@L1:
    MOV    DL,AH
    AND    CH,7Ch
    AND    AH,81h
    SHR    DL,5
    OR     CH,AH
    AND    DL,2
    OR     CH,DL
    POP    EAX
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    POPF
    ADC    CL,BYTE PTR AtariSeg[EBX]

    PUSH   EAX
    LAHF
    JO     @L1a
    AND    CH,0BFh
@L1a:
    MOV    DL,AH
    AND    CH,7Ch
    AND    AH,81h
    SHR    DL,5
    OR     CH,AH
    AND    DL,2
    OR     CH,DL
    POP    EAX
    ADD    EDI,2
    JMP    EmulateLoop
  @BCD:
    MOV    DL,CH
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    CMP    BX,80h
    JAE    @NotCrit1
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF

    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    CALL   ADC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit1:
    POPF

    MOV    DL,BYTE PTR AtariSeg[EBX]
    CALL   ADC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L72:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L73:                 { RRA ind. y - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    JMP    @L4
@NotCrit:
    CMP    BX,400h
    JAE    @L3
    AND    BX,2FFh
@L3:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L4:
    MOV    ESI,EBX
    MOV    BL,DL
    RCR    DL,1
    MOV    BH,BL                 { Set the overflow flag  }
    XOR    BH,DL                 { V=(New OR Old) AND 40h }
    AND    BH,40h
    AND    CH,0BFh
    OR     CH,BH
    TEST   CH,8                  { See if we're in decimal mode }
    JNZ    @BCD
    ROL    BL,1                  { Set carry flag = (Old AND 80h) }
    AND    BL,1
    AND    CH,0FEh
    OR     CH,BL
    MOV    BYTE PTR AtariSeg[ESI],DL
    ADD    EDI,2
    JMP    EmulateLoop
@BCD:
    MOV    BH,BL                 { BCD fixup 1 }
    AND    BH,0Fh
    CMP    BH,4
    JLE    @BCD1
    MOV    BH,DL
    ADD    BH,6
    AND    BH,0Fh
    AND    DL,0F0h
    OR     DL,BH
@BCD1:
    AND    CH,0FEh
    CMP    BL,4Fh
    JLE    @BCD2
    ADD    DL,60h
    OR     CH,1
@BCD2:
    MOV    BYTE PTR AtariSeg[ESI],DL
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L74:                 { SKB Quasi-Opcode }

  Asm
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L75:                 { ADC z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    OR     CH,43h
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF
    ADC    CL,BYTE PTR Game.Input_Byte[EBX]

    PUSH   EAX
    LAHF
    JO     @L1
    AND    CH,0BFh
@L1:
    MOV    DL,AH
    AND    CH,7Ch
    AND    AH,81h
    SHR    DL,5
    OR     CH,AH
    AND    DL,2
    OR     CH,DL
    POP    EAX
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    POPF
    ADC    CL,BYTE PTR AtariSeg[EBX]

    PUSH   EAX
    LAHF
    JO     @L1a
    AND    CH,0BFh
@L1a:
    MOV    DL,AH
    AND    CH,7Ch
    AND    AH,81h
    SHR    DL,5
    OR     CH,AH
    AND    DL,2
    OR     CH,DL
    POP    EAX
    ADD    EDI,2
    JMP    EmulateLoop
  @BCD:
    MOV    DL,CH
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    CMP    BX,80h
    JAE    @NotCrit1
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF

    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    CALL   ADC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit1:
    POPF

    MOV    DL,BYTE PTR AtariSeg[EBX]
    CALL   ADC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L76:                 { ROR z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    RCR    DL,1
    JC     @L2a
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCR    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L77:                 { RRA z. page x - UNDOCUMENTED }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    JMP    @L4
@NotCrit:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L4:
    MOV    ESI,EBX
    MOV    BL,DL
    RCR    DL,1
    MOV    BH,BL                 { Set the overflow flag  }
    XOR    BH,DL                 { V=(New OR Old) AND 40h }
    AND    BH,40h
    AND    CH,0BFh
    OR     CH,BH
    TEST   CH,8                  { See if we're in decimal mode }
    JNZ    @BCD
    ROL    BL,1                  { Set carry flag = (Old AND 80h) }
    AND    BL,1
    AND    CH,0FEh
    OR     CH,BL
    MOV    BYTE PTR AtariSeg[ESI],DL
    ADD    EDI,2
    JMP    EmulateLoop
@BCD:
    MOV    BH,BL                 { BCD fixup 1 }
    AND    BH,0Fh
    CMP    BH,4
    JLE    @BCD1
    MOV    BH,DL
    ADD    BH,6
    AND    BH,0Fh
    AND    DL,0F0h
    OR     DL,BH
@BCD1:
    AND    CH,0FEh
    CMP    BL,4Fh
    JLE    @BCD2
    ADD    DL,60h
    OR     CH,1
@BCD2:
    MOV    BYTE PTR AtariSeg[ESI],DL
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L78:                 { SEI }

  Asm
    OR     CH,04h
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L79:                 { ADC abs. y }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    OR     CH,43h
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF
    ADC    CL,BYTE PTR Game.Input_Byte[EBX]

    PUSH   EAX
    LAHF
    JO     @L1
    AND    CH,0BFh
@L1:
    MOV    DL,AH
    AND    CH,7Ch
    AND    AH,81h
    SHR    DL,5
    OR     CH,AH
    AND    DL,2
    OR     CH,DL
    POP    EAX
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    POPF
    ADC    CL,BYTE PTR AtariSeg[EBX]

    PUSH   EAX
    LAHF
    JO     @L1a
    AND    CH,0BFh
@L1a:
    MOV    DL,AH
    AND    CH,7Ch
    AND    AH,81h
    SHR    DL,5
    OR     CH,AH
    AND    DL,2
    OR     CH,DL
    POP    EAX
    ADD    EDI,3
    JMP    EmulateLoop
  @BCD:
    MOV    DL,CH
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    CMP    BX,80h
    JAE    @NotCrit1
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF

    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    CALL   ADC_BCD
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit1:
    POPF

    MOV    DL,BYTE PTR AtariSeg[EBX]
    CALL   ADC_BCD
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L7A:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L7B:                 { RRA abs. y - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    ADC    BH,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    JMP    @L4
@NotCrit:
    CMP    BX,400h
    JAE    @L3
    AND    BX,2FFh
@L3:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L4:
    MOV    ESI,EBX
    MOV    BL,DL
    RCR    DL,1
    MOV    BH,BL                 { Set the overflow flag  }
    XOR    BH,DL                 { V=(New OR Old) AND 40h }
    AND    BH,40h
    AND    CH,0BFh
    OR     CH,BH
    TEST   CH,8                  { See if we're in decimal mode }
    JNZ    @BCD
    ROL    BL,1                  { Set carry flag = (Old AND 80h) }
    AND    BL,1
    AND    CH,0FEh
    OR     CH,BL
    MOV    BYTE PTR AtariSeg[ESI],DL
    ADD    EDI,3
    JMP    EmulateLoop
@BCD:
    MOV    BH,BL                 { BCD fixup 1 }
    AND    BH,0Fh
    CMP    BH,4
    JLE    @BCD1
    MOV    BH,DL
    ADD    BH,6
    AND    BH,0Fh
    AND    DL,0F0h
    OR     DL,BH
@BCD1:
    AND    CH,0FEh
    CMP    BL,4Fh
    JLE    @BCD2
    ADD    DL,60h
    OR     CH,1
@BCD2:
    MOV    BYTE PTR AtariSeg[ESI],DL
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }


L7C:                 { SKW Quasi-Opcode }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BYTE PTR Game.AddCycle,DL
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L7D:                 { ADC abs. x }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    OR     CH,43h
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF
    ADC    CL,BYTE PTR Game.Input_Byte[EBX]

    PUSH   EAX
    LAHF
    JO     @L1
    AND    CH,0BFh
@L1:
    MOV    DL,AH
    AND    CH,7Ch
    AND    AH,81h
    SHR    DL,5
    OR     CH,AH
    AND    DL,2
    OR     CH,DL
    POP    EAX
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    POPF
    ADC    CL,BYTE PTR AtariSeg[EBX]
    PUSH   EAX
    LAHF
    JO     @L1a
    AND    CH,0BFh
@L1a:
    MOV    DL,AH
    AND    CH,7Ch
    AND    AH,81h
    SHR    DL,5
    OR     CH,AH
    AND    DL,2
    OR     CH,DL
    POP    EAX
    ADD    EDI,3
    JMP    EmulateLoop
  @BCD:
    MOV    DL,CH
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    CMP    BX,80h
    JAE    @NotCrit1
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF

    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    CALL   ADC_BCD
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit1:
    POPF

    MOV    DL,BYTE PTR AtariSeg[EBX]
    CALL   ADC_BCD
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L7E:                 { ROR abs. x }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    ADC    BH,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    RCR    DL,1
    JC     @L2a
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    RCR    BYTE PTR AtariSeg[EBX],1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    JC     @L2
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L7F:                 { RRA abs. x - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    ADC    BH,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    JMP    @L4
@NotCrit:
    CMP    BX,400h
    JAE    @L3
    AND    BX,2FFh
@L3:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L4:
    MOV    ESI,EBX
    MOV    BL,DL
    RCR    DL,1
    MOV    BH,BL                 { Set the overflow flag  }
    XOR    BH,DL                 { V=(New OR Old) AND 40h }
    AND    BH,40h
    AND    CH,0BFh
    OR     CH,BH
    TEST   CH,8                  { See if we're in decimal mode }
    JNZ    @BCD
    ROL    BL,1                  { Set carry flag = (Old AND 80h) }
    AND    BL,1
    AND    CH,0FEh
    OR     CH,BL
    MOV    BYTE PTR AtariSeg[ESI],DL
    ADD    EDI,3
    JMP    EmulateLoop
@BCD:
    MOV    BH,BL                 { BCD fixup 1 }
    AND    BH,0Fh
    CMP    BH,4
    JLE    @BCD1
    MOV    BH,DL
    ADD    BH,6
    AND    BH,0Fh
    AND    DL,0F0h
    OR     DL,BH
@BCD1:
    AND    CH,0FEh
    CMP    BL,4Fh
    JLE    @BCD2
    ADD    DL,60h
    OR     CH,1
@BCD2:
    MOV    BYTE PTR AtariSeg[ESI],DL
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L80:                 { SKB Quasi-Opcode }

  Asm
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L81:                 { STA ind. x }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh        { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
    JMP    @NotTimer
@NotTIA:
    CMP    BX,400h
    JAE    @NotTimer
    CMP    BX,200h
    JB     @NotTimer
    AND    BX,29Fh
    OR     BL,80h
    MOV    BL,BYTE PTR Timer_And[EBX - 280h]
@NotTimer:

    MOV    BYTE PTR AtariSeg[EBX],CL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L82:                 { SKB Quasi-Opcode }

  Asm
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L83:                 { SAX ind. x - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh        { Atari can only address 8K }
    MOV    DL,CL
    AND    DL,AL

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    MOV    BYTE PTR AtariSeg[EBX],DL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L84:                 { STY zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    CMP    BX,02Ch
    JA     @NotCrit
    MOV    BYTE PTR AtariSeg[EBX],AH

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    BYTE PTR AtariSeg[EBX],AH

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch1
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch1:

    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L85:                 { STA zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    CMP    BX,02Ch
    JA     @NotCrit
    MOV    BYTE PTR AtariSeg[EBX],CL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    BYTE PTR AtariSeg[EBX],CL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch1
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch1:

    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L86:                 { STX zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    CMP    BX,02Ch
    JA     @NotCrit
    MOV    BYTE PTR AtariSeg[EBX],AL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    BYTE PTR AtariSeg[EBX],AL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch1
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch1:

    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L87:                 { SAX zero page - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    DL,CL
    AND    DL,AL
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    CMP    BX,02Ch
    JA     @NotCrit
    MOV    BYTE PTR AtariSeg[EBX],DL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    BYTE PTR AtariSeg[EBX],DL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch1
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch1:

    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L88:                 { DEY }

  Asm
    DEC    AH
    JZ     @L1
    MOV    DL,AH
    AND    CH,7Dh
    AND    DL,80h
    INC    EDI
    ADD    CH,DL
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    INC    EDI
    OR     CH,2
    JMP    EmulateLoop
  End; { Asm }

L89:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L8A:                 { TXA }

  Asm
    MOV    CL,AL
    OR     BH,AL   { BH = 0 at start }
    JZ     @L1
    AND    BH,80h
    AND    CH,7Dh
    ADD    CH,BH
    INC    EDI
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    INC    EDI
    OR     CH,2
    JMP    EmulateLoop
  End; { Asm }

L8B:                 { ANE immediate - UNDOCUMENTED }

  Asm
    OR     CL,0EEh
    AND    CL,AL
    AND    CL,BYTE PTR [EDI+1]
    AND    CH,7Dh
    OR     BH,CL
    JZ     @L1
    AND    BH,80h
    ADD    EDI,2
    ADD    CH,BH
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L8C:                 { STY absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    CMP    BX,400h
    JAE    @NotTimer
    CMP    BX,200h
    JB     @NotTimer
    AND    BX,29Fh
    OR     BL,80h
    MOV    BL,BYTE PTR Timer_And[EBX - 280h]
@NotTimer:
    MOV    BYTE PTR AtariSeg[EBX],AH

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L8D:                 { STA absolute }
  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
    JMP    @NotTimer
@NotTIA:
    CMP    BX,400h
    JAE    @NotTimer
    CMP    BX,200h
    JB     @NotTimer
    AND    BX,29Fh
    OR     BL,80h
    MOV    BL,BYTE PTR Timer_And[EBX - 280h]
@NotTimer:

    MOV    BYTE PTR AtariSeg[EBX],CL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L8E:                 { STX absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    CMP    BX,400h
    JAE    @NotTimer
    CMP    BX,200h
    JB     @NotTimer
    AND    BX,29Fh
    OR     BL,80h
    MOV    BL,BYTE PTR Timer_And[EBX - 280h]
@NotTimer:
    MOV    BYTE PTR AtariSeg[EBX],AL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L8F:                 { SAX absolute - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }
    MOV    DL,CL
    AND    DL,AL

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    MOV    BYTE PTR AtariSeg[EBX],DL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L90:                 { BCC }

  Asm
    TEST   CH,01
    JNZ    @L1
    MOVSX  EBX,BYTE PTR [EDI+1]
    ADD    EDI,2
    PUSH   EAX
    SUB    EDI,OFFSET AtariSeg
    MOV    EAX,EDI
    ADD    EDI,EBX
    INC    DWORD PTR Game.AddCycle
    MOV    EBX,EDI
    ADD    EDI,OFFSET AtariSeg
    CMP    BH,AH
    JE     @L2
    INC    DWORD PTR Game.AddCycle
@L2:
    POP    EAX
    JMP    EmulateLoop
@L1:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L91:                 { STA ind. y }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
    JMP    @NotTimer
@NotTIA:
    CMP    BX,400h
    JAE    @NotTimer
    CMP    BX,200h
    JB     @NotTimer
    AND    BX,29Fh
    OR     BL,80h
    MOV    BL,BYTE PTR Timer_And[EBX - 280h]
@NotTimer:

    MOV    BYTE PTR AtariSeg[EBX],CL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L92:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L93:                 { SHA ind. y - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    MOV    DL,BH
    INC    DL
    AND    DL,AL
    AND    DL,CL
    JNC    @L1
    INC    BYTE PTR Game.AddCycle
    MOV    BH,DL
@L1:
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    MOV    BYTE PTR AtariSeg[EBX],CL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L94:                 { STY z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    MOV    BYTE PTR AtariSeg[EBX],AH
    CMP    BX,02Ch
    JA     @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L95:                 { STA z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    MOV    BYTE PTR AtariSeg[EBX],CL
    CMP    BX,02Ch
    JA     @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L96:                 { STX z. page y }

  Asm
    MOV    BL,AH
    ADD    BL,BYTE PTR [EDI+1]
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    MOV    BYTE PTR AtariSeg[EBX],AL
    CMP    BX,02Ch
    JA     @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L97:                 { SAX z. page y - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AH
    MOV    DL,CL
    AND    DL,AL
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    CMP    BX,02Ch
    JA     @NotCrit
    MOV    BYTE PTR AtariSeg[EBX],DL
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    BYTE PTR AtariSeg[EBX],DL
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L98:                 { TYA }

  Asm
    MOV    CL,AH
    OR     BH,AH   { BH = 0 at start }
    JZ     @L1
    AND    BH,80h
    AND    CH,7Dh
    ADD    CH,BH
    INC    EDI
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    INC    EDI
    OR     CH,2
    JMP    EmulateLoop
  End; { Asm }

L99:                 { STA abs. y }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    ADC    BH,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    CMP    BX,1000h
    JB     @NotROM
    CMP    BYTE PTR Game.Cart,ctStarpath
    JE     @NotROM
    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JNZ    @NotROM
    ADD    EDI,3
    JMP    EmulateLoop
@NotROM:

    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
    JMP    @NotTimer
@NotTIA:
    CMP    BX,400h
    JAE    @NotTimer
    CMP    BX,200h
    JB     @NotTimer
    AND    BX,29Fh
    OR     BL,80h
    MOV    BL,BYTE PTR Timer_And[EBX - 280h]
@NotTimer:

    MOV    BYTE PTR AtariSeg[EBX],CL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L9A:                 { TXS }

  Asm
    MOV    DH,AL
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

L9B:                 { SHS ind. y - UNDOCUMENTED }

  Asm
    MOV    DH,AL
    AND    DH,CL
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    MOV    DL,BH
    INC    DL
    AND    DL,DH
    JNC    @L1
    INC    BYTE PTR Game.AddCycle
    MOV    BH,DL
@L1:
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    MOV    BYTE PTR AtariSeg[EBX],CL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

L9C:                 { SHY abs. x - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    MOV    DL,BH
    INC    DL
    AND    DL,AH
    JNC    @L1
    INC    BYTE PTR Game.AddCycle
    MOV    BH,DL
@L1:
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    MOV    BYTE PTR AtariSeg[EBX],CL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L9D:                 { STA abs. x }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    ADC    BH,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
    JMP    @NotTimer
@NotTIA:
    CMP    BX,400h
    JAE    @NotTimer
    CMP    BX,200h
    JB     @NotTimer
    AND    BX,29Fh
    OR     BL,80h
    MOV    BL,BYTE PTR Timer_And[EBX - 280h]
@NotTimer:

    CMP    BX,1000h
    JB     @NotROM
    CMP    BYTE PTR Game.Cart,ctStarpath
    JE     @NotROM
    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JNZ    @NotROM
    ADD    EDI,3
    JMP    EmulateLoop
@NotROM:

    MOV    BYTE PTR AtariSeg[EBX],CL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L9E:                 { SHX abs. y - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    MOV    DL,BH
    INC    DL
    AND    DL,AL
    JNC    @L1
    INC    BYTE PTR Game.AddCycle
    MOV    BH,DL
@L1:
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    MOV    BYTE PTR AtariSeg[EBX],CL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

L9F:                 { SHA abs. y - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    MOV    DL,BH
    INC    DL
    AND    DL,AL
    AND    DL,CL
    JNC    @L1
    INC    BYTE PTR Game.AddCycle
    MOV    BH,DL
@L1:
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
@NotTIA:
    MOV    BYTE PTR AtariSeg[EBX],CL

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    MOV    BYTE PTR WriteOp,1
    CALL   SwitchBank
@NoSwitch:

    TEST   BX,0FC00h
    JNZ    @NotCrit
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
@NotCrit:
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LA0:                 { LDY immediate }

  Asm
    MOV    AH,BYTE PTR [EDI+1]
    AND    CH,7Dh
    OR     BH,AH
    JZ     @L1
    AND    BH,80h
    ADD    EDI,2
    ADD    CH,BH
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LA1:                 { LDA ind. x }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    CL,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LA2:                 { LDX immediate }

  Asm
    MOV    AL,BYTE PTR [EDI+1]
    AND    CH,7Dh
    OR     BH,AL
    JZ     @L1
    AND    BH,80h
    ADD    EDI,2
    ADD    CH,BH
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LA3:                 { LAX ind. x - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    AL,CL

    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    CL,BYTE PTR AtariSeg[EBX]
    MOV    AL,CL
    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LA4:                 { LDY zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    AH,BYTE PTR Game.Input_Byte[EBX]

    AND    CH,7Dh
    OR     AH,AH
    JZ     @L1
    MOV    DL,AH
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    AH,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     AH,AH
    JZ     @L1
    MOV    DL,AH
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LA5:                 { LDA zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    CL,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LA6:                 { LDX zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    AL,BYTE PTR Game.Input_Byte[EBX]

    AND    CH,7Dh
    OR     AL,AL
    JZ     @L1
    MOV    DL,AL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    AL,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     AL,AL
    JZ     @L1
    MOV    DL,AL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LA7:                 { LAX zero page - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    AL,CL

    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    CL,BYTE PTR AtariSeg[EBX]
    MOV    AL,CL    
    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LA8:                 { TAY }

  Asm
    MOV    AH,CL
    AND    CH,7Dh
    OR     BH,AH
    JZ     @L1
    AND    BH,80h
    INC    EDI
    ADD    CH,BH
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

LA9:                 { LDA immediate }

  Asm
    MOV    CL,BYTE PTR [EDI+1]
    AND    CH,7Dh
    OR     BH,CL
    JZ     @L1
    AND    BH,80h
    ADD    EDI,2
    ADD    CH,BH
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LAA:                 { TAX }

  Asm
    MOV    AL,CL
    AND    CH,7Dh
    OR     BH,AL
    JZ     @L1
    AND    BH,80h
    INC    EDI
    ADD    CH,BH
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

LAB:                 { LXA immed + a - UNDOCUMENTED }

  Asm
    ADD    CL,BYTE PTR [EDI+1]
    MOV    AL,CL
    AND    CH,7Dh
    OR     BH,CL
    JZ     @L1
    AND    BH,80h
    ADD    EDI,2
    ADD    CH,BH
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LAC:                 { LDY absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    AH,BYTE PTR Game.Input_Byte[EBX]

    AND    CH,7Dh
    OR     AH,AH
    JZ     @L1
    MOV    DL,AH
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    AH,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     AH,AH
    JZ     @L1
    MOV    DL,AH
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LAD:                 { LDA absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    CL,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LAE:                 { LDX absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    AL,BYTE PTR Game.Input_Byte[EBX]

    AND    CH,7Dh
    OR     AL,AL
    JZ     @L1
    MOV    DL,AL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    AL,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     AL,AL
    JZ     @L1
    MOV    DL,AL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LAF:                 { LAX absolute - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    AL,CL

    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    CL,BYTE PTR AtariSeg[EBX]
    MOV    AL,CL    
    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LB0:                 { BCS }

  Asm
    TEST   CH,01
    JZ     @L1
    MOVSX  EBX,BYTE PTR [EDI+1]
    ADD    EDI,2
    PUSH   EAX
    SUB    EDI,OFFSET AtariSeg
    MOV    EAX,EDI
    ADD    EDI,EBX
    INC    DWORD PTR Game.AddCycle
    MOV    EBX,EDI
    ADD    EDI,OFFSET AtariSeg
    CMP    BH,AH
    JE     @L2
    INC    DWORD PTR Game.AddCycle
@L2:
    POP    EAX
    JMP    EmulateLoop
@L1:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LB1:                 { LDA ind. y }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    PUSHF
    ADC    BH,0
    POPF
    ADC    DWORD PTR Game.AddCycle,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    CL,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LB2:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

LB3:                 { LAX ind. y - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    PUSHF
    ADC    BH,0
    POPF
    ADC    DWORD PTR Game.AddCycle,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    AL,CL

    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    CL,BYTE PTR AtariSeg[EBX]
    MOV    AL,CL    
    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LB4:                 { LDY z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    AH,BYTE PTR Game.Input_Byte[EBX]

    AND    CH,7Dh
    OR     AH,AH
    JZ     @L1
    MOV    DL,AH
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    AH,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     AH,AH
    JZ     @L1
    MOV    DL,AH
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LB5:                 { LDA z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    CL,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LB6:                 { LDX z. page y }

  Asm
    MOV    BL,AH
    ADD    BL,BYTE PTR [EDI+1]
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    AL,BYTE PTR Game.Input_Byte[EBX]

    AND    CH,7Dh
    OR     AL,AL
    JZ     @L1
    MOV    DL,AL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    AL,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     AL,AL
    JZ     @L1
    MOV    DL,AL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LB7:                 { LAX z. page y - UNDOCUMENTED }

  Asm
    MOV    BL,AH
    ADD    BL,BYTE PTR [EDI+1]
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    AL,CL

    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    MOV    CL,BYTE PTR AtariSeg[EBX]
    MOV    AL,CL    
    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LB8:                 { CLV }

  Asm
    AND    CH,0BFh
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

LB9:                 { LDA abs. y }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    CL,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LBA:                 { TSX }

  Asm
    MOV    AL,DH
    AND    CH,7Dh
    OR     BH,AL
    JZ     @L1
    AND    BH,80h
    INC    EDI
    ADD    CH,BH
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

LBB:                 { LAS (abs. y) and s - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX
    AND    CL,DH
    MOV    AL,CL
    MOV    DH,CL

    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    CL,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LBC:                 { LDY abs. x }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    AH,BYTE PTR Game.Input_Byte[EBX]

    AND    CH,7Dh
    OR     AH,AH
    JZ     @L1
    MOV    DL,AH
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    AH,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     AH,AH
    JZ     @L1
    MOV    DL,AH
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LBD:                 { LDA abs. x }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX

    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    CL,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LBE:                 { LDX abs. y }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    AL,BYTE PTR Game.Input_Byte[EBX]

    AND    CH,7Dh
    OR     AL,AL
    JZ     @L1
    MOV    DL,AL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    AL,BYTE PTR AtariSeg[EBX]
    AND    CH,7Dh
    OR     AL,AL
    JZ     @L1
    MOV    DL,AL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LBF:                 { LAX abs. y }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    MOV    CL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    AL,CL

    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    MOV    CL,BYTE PTR AtariSeg[EBX]
    MOV    AL,CL    
    AND    CH,7Dh
    OR     CL,CL
    JZ     @L1
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LC0:                 { CPY immediate }

  Asm
    MOV    DL,AH
    OR     CH,3
    SUB    DL,BYTE PTR [EDI+1]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LC1:                 { CMP ind. x }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,CL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LC2:                 { SKB Quasi-Opcode }

  Asm
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LC3:                 { DCP ind. x - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,CL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    DEC    BYTE PTR Game.Input_Byte[EBX]
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    DEC    BYTE PTR AtariSeg[EBX]
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LC4:                 { CPY zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,AH
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LC5:                 { CMP zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,CL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LC6:                 { DEC zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
    PUSH   EBX
    AND    EBX,0Fh
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EBX
    DEC    DL
    MOV    BYTE PTR AtariSeg[EBX],DL
    JMP    @Continue
@NotTIA:
    DEC    BYTE PTR AtariSeg[EBX]
@Continue:
    PUSHF
    CMP    BX,02Ch
    JA     @NotCrit
    PUSH   EBX
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    POP    EBX
@NotCrit:
    POPF
    JZ     @L1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LC7:                 { DCP zero page - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,CL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    DEC    BYTE PTR Game.Input_Byte[EBX]
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    DEC    BYTE PTR AtariSeg[EBX]
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LC8:                 { INY }

  Asm
    INC    AH
    JZ     @L1
    MOV    DL,AH
    AND    CH,7Dh
    AND    DL,80h
    INC    EDI
    ADD    CH,DL
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    INC    EDI
    OR     CH,2
    JMP    EmulateLoop
  End; { Asm }

LC9:                 { CMP immediate }

  Asm
    MOV    DL,CL
    OR     CH,3
    SUB    DL,BYTE PTR [EDI+1]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LCA:                 { DEX }

  Asm
    DEC    AL
    JZ     @L1
    MOV    DL,AL
    AND    CH,7Dh
    AND    DL,80h
    INC    EDI
    ADD    CH,DL
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    INC    EDI
    OR     CH,2
    JMP    EmulateLoop
  End; { Asm }

LCB:                 { SBX immediate - UNDOCUMENTED }

  Asm
    MOV    DL,CL
    AND    DL,AL
    OR     CH,3
    SUB    DL,BYTE PTR [EDI+1]
    MOV    AL,DL
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LCC:                 { CPY absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,AH
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LCD:                 { CMP absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,CL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LCE:                 { DEC absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
    PUSH   EBX
    AND    EBX,0Fh
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EBX
    DEC    DL
    MOV    BYTE PTR AtariSeg[EBX],DL
    JMP    @Continue
@NotTIA:
    DEC    BYTE PTR AtariSeg[EBX]
@Continue:
    PUSHF
    TEST   BX,0FC00h
    JNZ    @NotCrit
    PUSH   EBX
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    POP    EBX
@NotCrit:
    POPF
    JZ     @L1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LCF:                 { DCP absolute - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,CL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    DEC    BYTE PTR Game.Input_Byte[EBX]
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    DEC    BYTE PTR AtariSeg[EBX]
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LD0:                 { BNE }

  Asm
    TEST   CH,02
    JNZ    @L1
    MOVSX  EBX,BYTE PTR [EDI+1]
    ADD    EDI,2
    PUSH   EAX
    SUB    EDI,OFFSET AtariSeg
    MOV    EAX,EDI
    ADD    EDI,EBX
    INC    DWORD PTR Game.AddCycle
    MOV    EBX,EDI
    ADD    EDI,OFFSET AtariSeg
    CMP    BH,AH
    JE     @L2
    INC    DWORD PTR Game.AddCycle
@L2:
    POP    EAX
    JMP    EmulateLoop
@L1:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LD1:                 { CMP ind. y }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    PUSHF
    ADC    BH,0
    POPF
    ADC    DWORD PTR Game.AddCycle,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,CL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LD2:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

LD3:                 { DCP ind. y - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    PUSHF
    ADC    BH,0
    POPF
    ADC    DWORD PTR Game.AddCycle,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,CL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    DEC    BYTE PTR Game.Input_Byte[EBX]
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    DEC    BYTE PTR AtariSeg[EBX]
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LD4:                 { SKB Quasi-Opcode }

  Asm
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LD5:                 { CMP z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    MOV    DL,CL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LD6:                 { DEC z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
    PUSH   EBX
    AND    EBX,0Fh
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EBX
    DEC    DL
    MOV    BYTE PTR AtariSeg[EBX],DL
    JMP    @Continue
@NotTIA:
    DEC    BYTE PTR AtariSeg[EBX]
@Continue:
    PUSHF
    CMP    BX,02Ch
    JA     @NotCrit
    PUSH   EBX
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    POP    EBX
@NotCrit:
    POPF
    JZ     @L1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LD7:                 { DCP z. page x - UNDOCUMENTED }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    MOV    DL,CL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    DEC    BYTE PTR Game.Input_Byte[EBX]
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    DEC    BYTE PTR AtariSeg[EBX]
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LD8:                 { CLD }

  Asm
    AND    CH,0F7h
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

LD9:                 { CMP abs. y }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,CL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LDA:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

LDB:                 { DCP abs. y - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,CL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    DEC    BYTE PTR Game.Input_Byte[EBX]
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    DEC    BYTE PTR AtariSeg[EBX]
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LDC:                 { SKW Quasi-Opcode }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BYTE PTR Game.AddCycle,DL
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LDD:                 { CMP abs. x }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,CL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LDE:                 { DEC abs. x }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    ADC    BH,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    TEST   BX,0FC00h
    JNZ    @NotCrit
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
    PUSH   EBX
    AND    EBX,0Fh
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EBX
    DEC    DL
    MOV    BYTE PTR AtariSeg[EBX],DL
    JMP    @Continue
@NotTIA:
    DEC    BYTE PTR AtariSeg[EBX]
@Continue:
    JZ     @L1a
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    MOV    DL,BYTE PTR AtariSeg[EBX]
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
  @L1a:
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    DEC    BYTE PTR AtariSeg[EBX]
    JZ     @L1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LDF:                 { DCP abs. x - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,CL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    DEC    BYTE PTR Game.Input_Byte[EBX]
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    DEC    BYTE PTR AtariSeg[EBX]
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LE0:                 { CPX immediate }

  Asm
    MOV    DL,AL
    OR     CH,3
    SUB    DL,BYTE PTR [EDI+1]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LE1:                 { SBC ind. x }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF
    SBB    CL,BYTE PTR Game.Input_Byte[EBX]
    PUSHF
    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     CH,40h
    POPF
    JO     @L4a
    AND    CH,0BFh
  @L4a:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    POPF
    SBB    CL,BYTE PTR AtariSeg[EBX]
    PUSHF
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     CH,40h
    POPF
    JO     @L4
    AND    CH,0BFh
@L4:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  @BCD:
    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    CMP    BX,80h
    JAE    @NotCrit1
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF

    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    CALL   SBC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit1:
    POPF

    MOV    DL,BYTE PTR AtariSeg[EBX]
    CALL   SBC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LE2:                 { SKB Quasi-Opcode }

  Asm
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LE3:                 { ISB ind. x - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    ADD    BL,AL
    MOV    BX,WORD PTR AtariSeg[EBX]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    JMP    @L4
@NotCrit:
    CMP    BX,400h
    JAE    @L3
    AND    BX,2FFh
@L3:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L4:
    AND    CH,03Ch         { Turn sign, overflow, and zero bits off }
    INC    DL
    MOV    BYTE PTR AtariSeg[EBX],DL
    PUSH   EAX
    SUB    EAX,EAX

    MOV    AL,CL
    SUB    AL,DL
    SBB    AH,0
    MOV    BL,CH
    AND    BL,1
    XOR    BL,1
    SUB    AL,BL
    SBB    AH,0
    JNZ    @L1
    OR     CH,2
@L1:
    MOV    BL,AL
    AND    BL,80h
    OR     CH,BL

    MOV    BL,AL
    XOR    BL,CL
    TEST   BL,80h
    JZ     @L2
    MOV    BL,DL
    XOR    BL,CL
    TEST   BL,80h
    JZ     @L2
    OR     CH,40h
@L2:
    TEST   CH,8
    JZ     @NotBCD

    PUSH   ECX
    MOV    BL,CL
    AND    BL,0Fh
    AND    CH,1
    ADD    BL,CH
    MOV    CH,DL
    AND    CH,0Fh
    CMP    BL,CH
    JGE    @L5
    SUB    AX,6
@L5:
    POP    ECX
    CMP    AX,99h
    JLE    @NotBCD
    SUB    AX,60h
@NotBCD:
    TEST   AH,AH
    JNZ    @L6
    OR     CH,1
@L6:
    MOV    CL,AL
    POP    EAX
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LE4:                 { CPX zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,AL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LE5:                 { SBC zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF
    SBB    CL,BYTE PTR Game.Input_Byte[EBX]
    PUSHF
    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     CH,40h
    POPF
    JO     @L4a
    AND    CH,0BFh
  @L4a:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    POPF
    SBB    CL,BYTE PTR AtariSeg[EBX]
    PUSHF
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     CH,40h
    POPF
    JO     @L4
    AND    CH,0BFh
@L4:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  @BCD:
    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    CMP    BX,80h
    JAE    @NotCrit1
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF

    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    CALL   SBC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit1:
    POPF

    MOV    DL,BYTE PTR AtariSeg[EBX]
    CALL   SBC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LE6:                 { INC zero page }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
    PUSH   EBX
    AND    EBX,0Fh
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EBX
    INC    DL
    MOV    BYTE PTR AtariSeg[EBX],DL
    JMP    @Continue
@NotTIA:
    INC    BYTE PTR AtariSeg[EBX]
@Continue:
    PUSHF
    CMP    BX,02Ch
    JA     @NotCrit
    PUSH   EBX
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    POP    EBX
@NotCrit:
    POPF
    JZ     @L1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LE7:                 { ISB zero page - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    JMP    @L4
@NotCrit:
    CMP    BX,400h
    JAE    @L3
    AND    BX,2FFh
@L3:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L4:
    AND    CH,03Ch         { Turn sign, overflow, and zero bits off }
    INC    DL
    MOV    BYTE PTR AtariSeg[EBX],DL
    PUSH   EAX
    SUB    EAX,EAX

    MOV    AL,CL
    SUB    AL,DL
    SBB    AH,0
    MOV    BL,CH
    AND    BL,1
    XOR    BL,1
    SUB    AL,BL
    SBB    AH,0
    JNZ    @L1
    OR     CH,2
@L1:
    MOV    BL,AL
    AND    BL,80h
    OR     CH,BL

    MOV    BL,AL
    XOR    BL,CL
    TEST   BL,80h
    JZ     @L2
    MOV    BL,DL
    XOR    BL,CL
    TEST   BL,80h
    JZ     @L2
    OR     CH,40h
@L2:
    TEST   CH,8
    JZ     @NotBCD

    PUSH   ECX
    MOV    BL,CL
    AND    BL,0Fh
    AND    CH,1
    ADD    BL,CH
    MOV    CH,DL
    AND    CH,0Fh
    CMP    BL,CH
    JGE    @L5
    SUB    AX,6
@L5:
    POP    ECX
    CMP    AX,99h
    JLE    @NotBCD
    SUB    AX,60h
@NotBCD:
    TEST   AH,AH
    JNZ    @L6
    OR     CH,1
@L6:
    MOV    CL,AL
    POP    EAX
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LE8:                 { INX }

  Asm
    INC    AL
    JZ     @L1
    MOV    DL,AL
    AND    CH,7Dh
    AND    DL,80h
    INC    EDI
    ADD    CH,DL
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    INC    EDI
    OR     CH,2
    JMP    EmulateLoop
  End; { Asm }

LE9:                 { SBC immediate }
  Asm
    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    XOR    DL,1
    OR     CH,3
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    SBB    CL,BYTE PTR [EDI+1]
    PUSHF
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     CH,40h
    POPF
    JO     @L4
    AND    CH,0BFh
@L4:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  @BCD:
    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }

    MOV    DL,BYTE PTR [EDI+1]
    CALL   SBC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LEA:                 { NOP }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

LEB:                 { SBC immediate - UNDOCUMENTED }

  Asm
    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    XOR    DL,1
    OR     CH,3
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    SBB    CL,BYTE PTR [EDI+1]
    PUSHF
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     CH,40h
    POPF
    JO     @L4
    AND    CH,0BFh
@L4:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  @BCD:
    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }

    MOV    DL,BYTE PTR [EDI+1]
    CALL   SBC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LEC:                 { CPX absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    MOV    DL,AL
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    CALL   Handle_TIA
    POP    EDX
    POP    ECX
    POP    EBX
    SUB    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EDI
    POP    EAX

    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    SUB    DL,BYTE PTR AtariSeg[EBX]
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     DL,DL
    JZ     @L1
    AND    CH,7Dh
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LED:                 { SBC absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF
    SBB    CL,BYTE PTR Game.Input_Byte[EBX]
    PUSHF
    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     CH,40h
    POPF
    JO     @L4a
    AND    CH,0BFh
  @L4a:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    POPF
    SBB    CL,BYTE PTR AtariSeg[EBX]
    PUSHF
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     CH,40h
    POPF
    JO     @L4
    AND    CH,0BFh
@L4:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  @BCD:
    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    CMP    BX,80h
    JAE    @NotCrit1
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF

    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    CALL   SBC_BCD
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit1:
    POPF

    MOV    DL,BYTE PTR AtariSeg[EBX]
    CALL   SBC_BCD
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LEE:                 { INC absolute }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    CMP    BX,1000h
    JB     @NotROM
    CMP    BYTE PTR Game.Cart,ctStarpath
    JE     @NotROM
    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JNZ    @NotROM
    ADD    EDI,3
    JMP    EmulateLoop
@NotROM:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
    PUSH   EBX
    AND    EBX,0Fh
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EBX
    INC    DL
    MOV    BYTE PTR AtariSeg[EBX],DL
    JMP    @Continue
@NotTIA:
    INC    BYTE PTR AtariSeg[EBX]
@Continue:
    PUSHF
    TEST   BX,0FC00h
    JNZ    @NotCrit
    PUSH   EBX
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    POP    EBX
@NotCrit:
    POPF
    JZ     @L1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,2
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LEF:                 { ISB absolute - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    JMP    @L4
@NotCrit:
    CMP    BX,400h
    JAE    @L3
    AND    BX,2FFh
@L3:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L4:
    AND    CH,03Ch         { Turn sign, overflow, and zero bits off }
    INC    DL
    MOV    BYTE PTR AtariSeg[EBX],DL
    PUSH   EAX
    SUB    EAX,EAX

    MOV    AL,CL
    SUB    AL,DL
    SBB    AH,0
    MOV    BL,CH
    AND    BL,1
    XOR    BL,1
    SUB    AL,BL
    SBB    AH,0
    JNZ    @L1
    OR     CH,2
@L1:
    MOV    BL,AL
    AND    BL,80h
    OR     CH,BL

    MOV    BL,AL
    XOR    BL,CL
    TEST   BL,80h
    JZ     @L2
    MOV    BL,DL
    XOR    BL,CL
    TEST   BL,80h
    JZ     @L2
    OR     CH,40h
@L2:
    TEST   CH,8
    JZ     @NotBCD

    PUSH   ECX
    MOV    BL,CL
    AND    BL,0Fh
    AND    CH,1
    ADD    BL,CH
    MOV    CH,DL
    AND    CH,0Fh
    CMP    BL,CH
    JGE    @L5
    SUB    AX,6
@L5:
    POP    ECX
    CMP    AX,99h
    JLE    @NotBCD
    SUB    AX,60h
@NotBCD:
    TEST   AH,AH
    JNZ    @L6
    OR     CH,1
@L6:
    MOV    CL,AL
    POP    EAX
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LF0:                 { BEQ }

  Asm
    TEST   CH,02
    JZ     @L1
    MOVSX  EBX,BYTE PTR [EDI+1]
    ADD    EDI,2
    PUSH   EAX
    SUB    EDI,OFFSET AtariSeg
    MOV    EAX,EDI
    ADD    EDI,EBX
    INC    DWORD PTR Game.AddCycle
    MOV    EBX,EDI
    ADD    EDI,OFFSET AtariSeg
    CMP    BH,AH
    JE     @L2
    INC    DWORD PTR Game.AddCycle
@L2:
    POP    EAX
    JMP    EmulateLoop
@L1:
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LF1:                 { SBC ind. y }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    PUSHF
    ADC    BH,0
    POPF
    ADC    DWORD PTR Game.AddCycle,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF
    SBB    CL,BYTE PTR Game.Input_Byte[EBX]
    PUSHF
    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     CH,40h
    POPF
    JO     @L4a
    AND    CH,0BFh
  @L4a:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    POPF
    SBB    CL,BYTE PTR AtariSeg[EBX]
    PUSHF
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     CH,40h
    POPF
    JO     @L4
    AND    CH,0BFh
@L4:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  @BCD:
    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    CMP    BX,80h
    JAE    @NotCrit1
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF

    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    CALL   SBC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit1:
    POPF

    MOV    DL,BYTE PTR AtariSeg[EBX]
    CALL   SBC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LF2:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

LF3:                 { ISB ind. Y - UNDOCUMENTED }

  Asm
    MOV    BL,BYTE PTR [EDI+1]
    MOV    BX,WORD PTR AtariSeg[EBX]
    ADD    BL,AH
    PUSHF
    ADC    BH,0
    POPF
    ADC    DWORD PTR Game.AddCycle,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    JMP    @L4
@NotCrit:
    CMP    BX,400h
    JAE    @L3
    AND    BX,2FFh
@L3:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L4:
    AND    CH,03Ch         { Turn sign, overflow, and zero bits off }
    INC    DL
    MOV    BYTE PTR AtariSeg[EBX],DL
    PUSH   EAX
    SUB    EAX,EAX

    MOV    AL,CL
    SUB    AL,DL
    SBB    AH,0
    MOV    BL,CH
    AND    BL,1
    XOR    BL,1
    SUB    AL,BL
    SBB    AH,0
    JNZ    @L1
    OR     CH,2
@L1:
    MOV    BL,AL
    AND    BL,80h
    OR     CH,BL

    MOV    BL,AL
    XOR    BL,CL
    TEST   BL,80h
    JZ     @L2
    MOV    BL,DL
    XOR    BL,CL
    TEST   BL,80h
    JZ     @L2
    OR     CH,40h
@L2:
    TEST   CH,8
    JZ     @NotBCD

    PUSH   ECX
    MOV    BL,CL
    AND    BL,0Fh
    AND    CH,1
    ADD    BL,CH
    MOV    CH,DL
    AND    CH,0Fh
    CMP    BL,CH
    JGE    @L5
    SUB    AX,6
@L5:
    POP    ECX
    CMP    AX,99h
    JLE    @NotBCD
    SUB    AX,60h
@NotBCD:
    TEST   AH,AH
    JNZ    @L6
    OR     CH,1
@L6:
    MOV    CL,AL
    POP    EAX
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LF4:                 { SKB Quasi-Opcode }

  Asm
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LF5:                 { SBC z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF
    SBB    CL,BYTE PTR Game.Input_Byte[EBX]
    PUSHF
    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     CH,40h
    POPF
    JO     @L4a
    AND    CH,0BFh
  @L4a:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit:
    POPF
    SBB    CL,BYTE PTR AtariSeg[EBX]
    PUSHF
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     CH,40h
    POPF
    JO     @L4
    AND    CH,0BFh
@L4:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,2
    JMP    EmulateLoop
  @BCD:
    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    CMP    BX,80h
    JAE    @NotCrit1
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF

    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    CALL   SBC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
@NotCrit1:
    POPF

    MOV    DL,BYTE PTR AtariSeg[EBX]
    CALL   SBC_BCD
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LF6:                 { INC z. page x }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]
    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
    PUSH   EBX
    AND    EBX,0Fh
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EBX
    INC    DL
    MOV    BYTE PTR AtariSeg[EBX],DL
    JMP    @Continue
@NotTIA:
    INC    BYTE PTR AtariSeg[EBX]
@Continue:
    PUSHF
    CMP    BX,02Ch
    JA     @NotCrit
    PUSH   EBX
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    POP    EBX
@NotCrit:
    POPF
    JZ     @L1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,2
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LF7:                 { ISB z. page x - UNDOCUMENTED }

  Asm
    MOV    BL,AL
    ADD    BL,BYTE PTR [EDI+1]

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    JMP    @L4
@NotCrit:
    CMP    BX,400h
    JAE    @L3
    AND    BX,2FFh
@L3:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L4:
    AND    CH,03Ch         { Turn sign, overflow, and zero bits off }
    INC    DL
    MOV    BYTE PTR AtariSeg[EBX],DL
    PUSH   EAX
    SUB    EAX,EAX

    MOV    AL,CL
    SUB    AL,DL
    SBB    AH,0
    MOV    BL,CH
    AND    BL,1
    XOR    BL,1
    SUB    AL,BL
    SBB    AH,0
    JNZ    @L1
    OR     CH,2
@L1:
    MOV    BL,AL
    AND    BL,80h
    OR     CH,BL

    MOV    BL,AL
    XOR    BL,CL
    TEST   BL,80h
    JZ     @L2
    MOV    BL,DL
    XOR    BL,CL
    TEST   BL,80h
    JZ     @L2
    OR     CH,40h
@L2:
    TEST   CH,8
    JZ     @NotBCD

    PUSH   ECX
    MOV    BL,CL
    AND    BL,0Fh
    AND    CH,1
    ADD    BL,CH
    MOV    CH,DL
    AND    CH,0Fh
    CMP    BL,CH
    JGE    @L5
    SUB    AX,6
@L5:
    POP    ECX
    CMP    AX,99h
    JLE    @NotBCD
    SUB    AX,60h
@NotBCD:
    TEST   AH,AH
    JNZ    @L6
    OR     CH,1
@L6:
    MOV    CL,AL
    POP    EAX
    ADD    EDI,2
    JMP    EmulateLoop
  End; { Asm }

LF8:                 { SED }

  Asm
    OR     CH,08h
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

LF9:                 { SBC abs. y }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF
    SBB    CL,BYTE PTR Game.Input_Byte[EBX]
    PUSHF
    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     CH,40h
    POPF
    JO     @L4a
    AND    CH,0BFh
  @L4a:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    POPF
    SBB    CL,BYTE PTR AtariSeg[EBX]
    PUSHF
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     CH,40h
    POPF
    JO     @L4
    AND    CH,0BFh
@L4:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  @BCD:

    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    CMP    BX,80h
    JAE    @NotCrit1
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF

    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    CALL   SBC_BCD

    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit1:
    POPF

    MOV    DL,BYTE PTR AtariSeg[EBX]
    CALL   SBC_BCD

    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LFA:                 { Nothing }

  Asm
    INC    EDI
    JMP    EmulateLoop
  End; { Asm }

LFB:                 { ISB abs. y - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AH
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    JMP    @L4
@NotCrit:
    CMP    BX,400h
    JAE    @L3
    AND    BX,2FFh
@L3:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L4:
    AND    CH,03Ch         { Turn sign, overflow, and zero bits off }
    INC    DL
    MOV    BYTE PTR AtariSeg[EBX],DL
    PUSH   EAX
    SUB    EAX,EAX

    MOV    AL,CL
    SUB    AL,DL
    SBB    AH,0
    MOV    BL,CH
    AND    BL,1
    XOR    BL,1
    SUB    AL,BL
    SBB    AH,0
    JNZ    @L1
    OR     CH,2
@L1:
    MOV    BL,AL
    AND    BL,80h
    OR     CH,BL

    MOV    BL,AL
    XOR    BL,CL
    TEST   BL,80h
    JZ     @L2
    MOV    BL,DL
    XOR    BL,CL
    TEST   BL,80h
    JZ     @L2
    OR     CH,40h
@L2:
    TEST   CH,8
    JZ     @NotBCD

    PUSH   ECX
    MOV    BL,CL
    AND    BL,0Fh
    AND    CH,1
    ADD    BL,CH
    MOV    CH,DL
    AND    CH,0Fh
    CMP    BL,CH
    JGE    @L5
    SUB    AX,6
@L5:
    POP    ECX
    CMP    AX,99h
    JLE    @NotBCD
    SUB    AX,60h
@NotBCD:
    TEST   AH,AH
    JNZ    @L6
    OR     CH,1
@L6:
    MOV    CL,AL
    POP    EAX
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LFC:                 { SKW Quasi-Opcode }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BYTE PTR Game.AddCycle,DL
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LFD:                 { SBC abs. x }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    SETC   DL
    ADD    BH,DL
    ADD    BYTE PTR Game.AddCycle,DL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,284h           { There are multiple timer copies }
    JB     @NotPIA
    CMP    BX,400h
    JAE    @NotPIA
    AND    BX,285h

    CALL   Handle_Timer

@NotPIA:
    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    TEST   CH,8
    JNZ    @BCD
    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    SBB    CL,0
    OR     CH,3
    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    SUB    CL,BYTE PTR Game.Input_Byte[EBX]
    PUSHF
    JNC    @L2a              { Note the difference! }
    AND    CH,0FEh
  @L2a:
    OR     CH,40h
    POPF
    JO     @L4a
    AND    CH,0BFh
  @L4a:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit:
    SUB    CL,BYTE PTR AtariSeg[EBX]
    PUSHF
    JNC    @L2               { Note the difference! }
    AND    CH,0FEh
@L2:
    OR     CH,40h
    POPF
    JO     @L4
    AND    CH,0BFh
@L4:
    OR     CL,CL
    JZ     @L1
    AND    CH,7Dh
    MOV    DL,CL
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    AND    CH,7Fh
    ADD    EDI,3
    JMP    EmulateLoop
  @BCD:

    MOV    DL,CH
    XOR    DL,1
    DB     0C0h,0EAh,1       { SHR   DL,imm8 is only 2 cycles on 486 }
    PUSHF
    CMP    BX,80h
    JAE    @NotCrit1
    AND    BX,0Fh

    PUSH   EAX
    PUSH   EBX
    PUSH   ECX
    PUSH   EDX
    PUSH   EDI
    CALL   Handle_TIA
    POP    EDI
    POP    EDX
    POP    ECX
    POP    EBX
    POP    EAX

    POPF

    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    CALL   SBC_BCD
    ADD    EDI,3
    JMP    EmulateLoop
@NotCrit1:
    POPF

    MOV    DL,BYTE PTR AtariSeg[EBX]
    CALL   SBC_BCD
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LFE:                 { INC abs. x }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    ADC    BH,0
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    AND    CH,7Dh
    CMP    BX,80h
    JAE    @NotTIA
    MOV    BL,BYTE PTR TIA_And[EBX]
    PUSH   EBX
    AND    EBX,0Fh
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    POP    EBX
    INC    DL
    MOV    BYTE PTR AtariSeg[EBX],DL
    JMP    @Continue
@NotTIA:
    INC    BYTE PTR AtariSeg[EBX]
@Continue:
    PUSHF
    TEST   BX,0FC00h
    JNZ    @NotCrit
    PUSH   EBX
    MOV    DWORD PTR Game.Save_BX,EBX
    CALL   Handle_IO
    POP    EBX
@NotCrit:
    POPF
    JZ     @L1
    MOV    DL,BYTE PTR AtariSeg[EBX]
    AND    DL,80h
    ADD    CH,DL
    ADD    EDI,3
    JMP    EmulateLoop
@L1:
    OR     CH,02h
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

LFF:                 { ISB abs. X - UNDOCUMENTED }

  Asm
    MOV    BX,WORD PTR [EDI+1]
    ADD    BL,AL
    AND    EBX,1FFFh          { Atari can only address 8K }

    CMP    BX,200h
    JAE    @NotStack
    SUB    BH,BH
@NotStack:

    TEST   BYTE PTR Game.BankSwitch[EBX],0FFh
    JZ     @NoSwitch
    CALL   SwitchBank
@NoSwitch:

    CMP    BX,80h
    JAE    @NotCrit
    AND    BX,0Fh
    PUSH   EAX
    PUSH   EDX
    PUSH   EDI
    PUSH   EBX
    PUSH   ECX
    CALL   Handle_TIA
    POP    ECX
    POP    EBX
    POP    EDI
    POP    EDX
    POP    EAX
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR Game.Input_Byte[EBX]
    JMP    @L4
@NotCrit:
    CMP    BX,400h
    JAE    @L3
    AND    BX,2FFh
@L3:
    MOV    DL,CH
    OR     CH,3
    SHR    DL,1
    MOV    DL,BYTE PTR AtariSeg[EBX]
@L4:
    AND    CH,03Ch         { Turn sign, overflow, and zero bits off }
    INC    DL
    MOV    BYTE PTR AtariSeg[EBX],DL
    PUSH   EAX
    SUB    EAX,EAX

    MOV    AL,CL
    SUB    AL,DL
    SBB    AH,0
    MOV    BL,CH
    AND    BL,1
    XOR    BL,1
    SUB    AL,BL
    SBB    AH,0
    JNZ    @L1
    OR     CH,2
@L1:
    MOV    BL,AL
    AND    BL,80h
    OR     CH,BL

    MOV    BL,AL
    XOR    BL,CL
    TEST   BL,80h
    JZ     @L2
    MOV    BL,DL
    XOR    BL,CL
    TEST   BL,80h
    JZ     @L2
    OR     CH,40h
@L2:
    TEST   CH,8
    JZ     @NotBCD

    PUSH   ECX
    MOV    BL,CL
    AND    BL,0Fh
    AND    CH,1
    ADD    BL,CH
    MOV    CH,DL
    AND    CH,0Fh
    CMP    BL,CH
    JGE    @L5
    SUB    AX,6
@L5:
    POP    ECX
    CMP    AX,99h
    JLE    @NotBCD
    SUB    AX,60h
@NotBCD:
    TEST   AH,AH
    JNZ    @L6
    OR     CH,1
@L6:
    MOV    CL,AL
    POP    EAX
    ADD    EDI,3
    JMP    EmulateLoop
  End; { Asm }

GetOut:
  _P     := P;
  _A     := A;
  _X     := X;
  _Y     := Y;
  _S     := S;
  _Start := Start;

  Game._6507_PC := Start;
  Game._6507_P  := P;
  Game._6507_A  := A;
  Game._6507_X  := X;
  Game._6507_Y  := Y;
  Game._6507_S  := S;
  If AVIFile.Opened Then frmMain.acVideoRecordToAVI.Execute;
End; { Interpret }

Procedure InitSound;
Begin
  SoundQueue_In  := 0;
  SoundQueue_Out := 0;
  SoundQueue_Num := 0;
  TIA_Sound_Init(Sample_Freq,Playback_Freq);
End; { InitSound }

Procedure InitGameType;
Begin
  Game.Controller  := crJoystick;
//  Game.Palette     := 0;
  Game.CurrentBank := 0;
  Game.BankStart   := $1000;
  Game.BankSize    := 1024;    { Size in dwords }
//  Game.Cart        := ct4k;
//  Game.TigerLimit  := 0;
//  Game.SCLimit     := 0;
  FillChar(AtariSeg,SizeOf(AtariSeg),#0);  { Blank them with nulls }
  FillChar(Game.BankSwitch,SizeOf(Game.BankSwitch),#0);
  Game.MegaBoyNum := 0;
End; // InitGameType

Procedure TfrmMain.UpdateButtonStatuses;
Begin
  If Game.Difficulty1 = 0
   Then acDifficulty1.ImageIndex := 5
   Else acDifficulty1.ImageIndex := 4;

  If Game.Difficulty2 = 0
   Then acDifficulty2.ImageIndex := 5
   Else acDifficulty2.ImageIndex := 4;

  If Game.ColorOrBW <> 0
   Then acColorBW.ImageIndex := 2
   Else acColorBW.ImageIndex := 3;

  If Game.Palette = 0
   Then acNTSCPAL.ImageIndex := 4
   Else acNTSCPAL.ImageIndex := 5;
End; // TfrmMain.UpdateButtonStatuses

Function TfrmMain.EnterFullScreenMode: Boolean;

  Function TryMode(Width,Height: Integer): Boolean;
  Var R: TRect;
  Begin
    // Set the display size

    frmMain.DXDraw1.Display.Width    := Width;
    frmMain.DXDraw1.Display.Height   := Height;
    frmMain.DXDraw1.Display.BitCount := 8;

    // Match the display dimensions

    frmMain.DXDraw1.SurfaceWidth  := frmMain.DXDraw1.Display.Width;
    frmMain.DXDraw1.SurfaceHeight := frmMain.DXDraw1.Display.Height;
    frmMain.DXDraw1.Width         := frmMain.DXDraw1.Display.Width;
    frmMain.DXDraw1.Height        := frmMain.DXDraw1.Display.Height;

    // Save the form size and position

    frmMain.DXDraw1.Finalize;
    frmMain.StoreWindow;

    // Ready the form for fullscreen mode

    frmMain.Top              := 0;              // Move the form to the corner
    frmMain.Left             := 0;
    frmMain.TBDock1.Visible  := False;          // Hide and disable the coolbar
    frmMain.TBDock1.Enabled  := False;
    frmMain.TBDock2.Visible  := False;          // Hide and disable the coolbar
    frmMain.TBDock2.Enabled  := False;

    // Ditch the mouse cursor and switch to fullscreen mode

    frmMain.DXDraw1.Cursor := crNone;
    frmMain.DXDraw1.Options := frmMain.DXDraw1.Options + [doFullScreen];
    frmMain.DXDraw1.Initialize;

    // Blank the display area

    FillChar(ScnBuf,SizeOf(ScnBuf),#0);
    FillChar(ScnBuf2,SizeOf(ScnBuf2),#0);
    R.Left   := 0;
    R.Top    := 0;
    R.Right  := frmMain.DXDraw1.Display.Width;//frmMain.SWidth;
    R.Bottom := frmMain.DXDraw1.Display.Height;//frmMain.SHeight;
    FillChar(SDesc,SizeOf(SDesc),#0);
    SDesc.dwSize := SizeOf(SDesc);
    frmMain.DXDraw1.Primary.Lock(R,SDesc);

    // Were we successful?

    If SDesc.lpSurface <> Nil Then
    Begin
      // Make the form fill the full screen

      frmMain.Width  := SDesc.lPitch;      // Match the screen width
      frmMain.Height := 768;               // Should never be bigger than this

      // Fill the entire surface with black

      FillChar(SDesc.lpSurface^,Integer(SDesc.lPitch) * Integer(SDesc.dwHeight),0);

      // Woohoo :)

      LastFSWidth  := Width;
      LastFSHeight := Height;
      Result       := True;
    End
    Else
    Begin
      ExitFullScreenMode;
      Result := False;
    End;
  End; // TryMode

Begin
  Application.OnDeactivate := frmMain.DeactivateApp;
  Result   := True;
  DoubleUp := False;
  If frmMain.TVScreen Then
  Begin
    If Config.MaxRows > 204 Then
    Begin
      If (LastFSWidth = 0) And (LastFSHeight = 0) Or Not TryMode(LastFSWidth,LastFSHeight) Then
      Begin
        If (Not TryMode(640,Config.MaxRows * 2)) And
           (Not TryMode(1024,768))               And
           (Not TryMode(800,600))                And
           (Not TryMode(640,480))                And
           (Not TryMode(640,400))                Then Result := False;
      End
      Else Result := True;
    End
    Else
    Begin
      If (LastFSWidth = 0) And (LastFSHeight = 0) Or Not TryMode(LastFSWidth,LastFSHeight) Then
      Begin
        If (Not TryMode(640,Config.MaxRows * 2)) And
           (Not TryMode(640,400))                And
           (Not TryMode(1024,768))               And
           (Not TryMode(800,600))                And
           (Not TryMode(640,480))                Then Result := False;
      End
      Else Result := True;
    End;
  End
  Else
  Begin
    If Config.MaxRows > 204 Then
    Begin
      If (LastFSWidth = 0) And (LastFSHeight = 0) Or Not TryMode(LastFSWidth,LastFSHeight) Then
      Begin
        If (Not TryMode(320,Config.MaxRows)) And
           (Not TryMode(320,240))            And
           (Not TryMode(640,480))            And
           (Not TryMode(1024,768))           And
           (Not TryMode(800,600))            And
           (Not TryMode(320,200))            And
           (Not TryMode(640,400))            Then Result := False;
      End
      Else Result := True;
      If Result And (LastFSWidth > 320) Then DoubleUp := True;
    End
    Else
    Begin
      If (LastFSWidth = 0) And (LastFSHeight = 0) Or Not TryMode(LastFSWidth,LastFSHeight) Then
      Begin
        If (Not TryMode(320,Config.MaxRows)) And
           (Not TryMode(320,200))            And
           (Not TryMode(640,400))            And
           (Not TryMode(1024,768))           And
           (Not TryMode(800,600))            And
           (Not TryMode(320,240))            And
           (Not TryMode(640,480))            Then Result := False;
      End
      Else Result := True;
      If Result And (LastFSWidth > 320) Then DoubleUp := True;
    End;
  End;
  If Not Result Then
  Begin
    LastFSWidth  := 0;
    LastFSHeight := 0;
  End;
End; // TfrmMain.EnterFullScreenMode

Procedure TfrmMain.ExitFullScreenMode;
Begin
  ResetClock;
  If UseDirectDraw And DDFullScreen Then
  Begin
    // Unlock the surface

    DXDraw1.Primary.Unlock(SDesc.lpSurface);

    DXDraw1.Finalize;

    TBDock1.Visible  := True;    // Show and enable the coolbar
    TBDock1.Enabled  := True;
    TBDock2.Visible  := True;    // Show and enable the coolbar
    TBDock2.Enabled  := True;
    RestoreWindow;
    DXDraw1.Cursor   := crDefault;
    BorderStyle      := bsSizeable;
    DXDraw1.Options  := DXDraw1.Options - [doFullScreen];
    DXDraw1.Initialize;

    If TVScreen Then
    Begin
      DXDraw1.Display.Width    := 320;
      DXDraw1.Display.Height   := Config.MaxRows;//200;
      DXDraw1.Display.BitCount := 8;
      DXDraw1.SurfaceWidth     := DXDraw1.Display.Width;
      DXDraw1.SurfaceHeight    := DXDraw1.Display.Height;
      DXDraw1.Width            := DXDraw1.Display.Width;
      DXDraw1.Height           := DXDraw1.Display.Height;
    End;
  End;
End; // TfrmMain.ExitFullScreenMode

Procedure Emulate;
Var
  Start     : Word;
  P,A,X,Y,S : Byte;
  B         : Boolean;
  R         : TRect;
  Ctrl      : TControl;
  GoAhead   : Boolean;

  Procedure ExtractWord(Var St: String; Blaster: String; I: Word);
  Var Ch: Char;
  Begin
    St := '';
    Repeat
      Ch := Blaster[I];
      Inc(I);
      If Ch <> ' ' Then St := St + Ch;
    Until (Ch = ' ') Or (I > Length(Blaster));
  End; { ExtractWord }

  Procedure InitWaveTable;
  Var I: Integer;
  Begin
    For I := 0 To 255 Do WaveTable[I] := Round(I * 1.75 * Playback_Freq / 31400);
  End; { InitWaveTable }

Begin
  frmMain.mnuFile.Enabled            := False;
  frmMain.mnuStart.Enabled           := False;
  frmMain.mnuController.Enabled      := False;
  frmMain.mnuInterfaces.Enabled      := False;

  frmMain.acVideoFullScreen.Enabled  := False;
  frmMain.acVideoTVScreen.Enabled    := False;
  frmMain.mnuMode.Enabled            := False;
  frmMain.mnuZoom.Enabled            := False;

  frmMain.acOpen.Enabled             := False;
  frmMain.acStartEmulation.Enabled   := False;
  frmMain.acProfileSettings.Enabled  := False;
  frmMain.acStopEmulation.Enabled    := True;
  frmMain.acStopEmulation.Enabled    := True;
  frmMain.acDifficulty1.Enabled      := True;
  frmMain.acDifficulty2.Enabled      := True;
  frmMain.acSelect.Enabled           := True;
  frmMain.acReset.Enabled            := True;
  frmMain.acColorBW.Enabled          := True;
  frmMain.acNTSCPAL.Enabled          := True;
  frmMain.acVideoRecordToAVI.Enabled := True;

  // If the profile information is overriding the palette, set the palette

  If MenuInfo.ProfileRec <> Nil Then
  Begin
    If MenuInfo.ProfileRec.Palette <> plNone Then Game.Palette := Integer(MenuInfo.ProfileRec.Palette) - 1;
  End;

  frmMain.UpdateButtonStatuses;

  ProcessPf2 := False;

  // Change resolutions if necessary

  If Config.UseDefaultSize Then
  Begin
    If MenuInfo.ProfileRec <> Nil Then
    Begin
      If MenuInfo.ProfileRec.DefaultSize <> 0 Then
      Begin
        Case (MenuInfo.ProfileRec.DefaultSize - 200) Of
           0: frmMain.acVideo320x200.Execute;
           4: frmMain.acVideo320x204.Execute;
          15: frmMain.acVideo320x215.Execute;
          50: frmMain.acVideo320x250.Execute;
         105: frmMain.acVideo320x305.Execute;
        Else
          frmMain.acVideo320x200.Execute;
        End; // Case
      End;
    End;
  End;

  frmMain.Pos200 := MenuInfo.Pos200;
  frmMain.Pos204 := MenuInfo.Pos204;
  frmMain.Pos215 := MenuInfo.Pos215;
  frmMain.Pos250 := MenuInfo.Pos250;
  frmMain.Pos305 := MenuInfo.Pos305;

  Playback_Freq := Config.PlaybackRate;

  InitWaveTable;

  InitSound;

    FillChar(Game.FMFreq,SizeOf(Game.FMFreq),#0);
    FillChar(Game.FMRealScale,SizeOf(Game.FMRealScale),#0);
    FillChar(Game.FMVoc,SizeOf(Game.FMVoc),#0);


    P     := Game._6507_P;
    A     := Game._6507_A;
    X     := Game._6507_X;
    Y     := Game._6507_Y;
    S     := Game._6507_S;
    Start := Game._6507_PC;

    Game.Hi3 := 0;

    SPBoot   := False;

    Case (Config.MaxRows - 200) Of
       0: Game.UserSetPos := frmMain.Pos200;
       4: Game.UserSetPos := frmMain.Pos204;
      15: Game.UserSetPos := frmMain.Pos215;
      50: Game.UserSetPos := frmMain.Pos250;
     105: Game.UserSetPos := frmMain.Pos305;
    Else
      Game.UserSetPos := frmMain.Pos200;
    End; { Case }

    Debugger := frmMain.acUseDebugger.Checked;

    // We must change the border style BEFORE initializing sound, or we end up with no sound

    If frmMain.UseDirectDraw And frmMain.DDFullScreen Then
     frmMain.BorderStyle := bsNone;

    // If zooming to full but still in windowed mode, see if we have to hide stuff

    If (frmMain.Zoom = 0) And Config.HideAllOnZoomFull And Not frmMain.DDFullScreen Then
    Begin
      frmMain.StoreWindow;
      frmMain.BorderStyle      := bsNone;
      frmMain.TBDock1.Visible  := False;          // Hide and disable the coolbar
      frmMain.TBDock1.Enabled  := False;
      frmMain.TBDock2.Visible  := False;          // Hide and disable the coolbar
      frmMain.TBDock2.Enabled  := False;
    End;

    If Game.OldStart <> 0 Then
    Begin
      Game.OldByte  := AtariSeg[Game.OldStart];
      If Debugger Then AtariSeg[Game.OldStart] := BreakInstruction;
    End
    Else Game.OldByte  := AtariSeg[Start];
    If Config.DoSound Then
    Begin
      InitSound;

      ProcessPf2 := (Game.Cart = ctPitfall2);

      Tia_sound_init(sample_freq,playback_freq);

      BufPlaying := 0;
      BufToFill  := 0;
      FillChar(Pf2Buf,SizeOf(Pf2Buf),#0);
      FillChar(SmallSoundBuf,SizeOf(SmallSoundBuf),#0);

      FillChar(Old_WaveLen,SizeOf(Old_WaveLen),#255);
      FillChar(Old_Pulse,SizeOf(Old_Pulse),#255);
      FillChar(Old_Phase,SizeOf(Old_Phase),#255);
      FillChar(Old_Signal,SizeOf(Old_Signal),#255);
      FillChar(Old_Wave,SizeOf(Old_Wave),#255);

      // Empty the sound buffer

      frmMain.Secondary.Lock(0,SndBufSize,SoundBufPtr,SoundBufSize,SoundBufPtr2,SoundBufSize2,DSBLOCK_ENTIREBUFFER);
      FillChar(SoundBufPtr^,SoundBufSize,#0);
      frmMain.Secondary.Unlock(SoundBufPtr,SoundBufSize,SoundBufPtr2,SoundBufSize2);

      // Start the DirectSound buffers playing

      frmMain.DXSound1.Primary.Play(DSBPLAY_LOOPING);
      frmMain.Secondary.Play(DSBPLAY_LOOPING);
    End;
    Game.MaxRows := Config.MaxRows;
    Time0   := GetTickCount;
    TimeErr := 0;

    NewPalette;

    MaxScan := 250;
    If ((Game.Palette <> 0) And (Config.MaxRows >= 215)) Or
       (Config.MaxRows > 215) Then MaxScan := 275;
    If Config.MaxRows >= 250 Then MaxScan := 330;

    frmMain.SetImageSizes(True);

    InterfaceHandler.ActivateInterfaces;

    // Blank the window area

    If frmMain.UseDirectDraw Then
    Begin
      If Not frmMain.DDFullScreen Then
      Begin
        R.Left   := 0;
        R.Top    := 0;
        R.Right  := frmMain.DXDraw1.Surface.Width;
        R.Bottom := frmMain.DXDraw1.Surface.Height;
        frmMain.DXDraw1.Surface.Canvas.Brush.Color := clBlack;
        frmMain.DXDraw1.Surface.Canvas.FillRect(R);
        If UsingKaillera Then
        Begin
          R.Left   := 0;
          R.Top    := 0;
          R.Right  := frmKaillera.DXDraw1.Surface.Width;
          R.Bottom := frmKaillera.DXDraw1.Surface.Height;
          frmKaillera.DXDraw1.Surface.Canvas.Brush.Color := clBlack;
          frmKaillera.DXDraw1.Surface.Canvas.FillRect(R);
        End;
      End;
    End
    Else
    Begin
      R.Left   := 0;
      R.Top    := 0;
      R.Right  := frmMain.Image1.Width;
      R.Bottom := frmMain.Image1.Height;
      frmMain.Image1.Canvas.Brush.Color := clBlack;
      frmMain.Image1.Canvas.FillRect(R);
    End;
    FillChar(ScnBuf,SizeOf(ScnBuf),#0);
    FillChar(ScnBuf2,SizeOf(ScnBuf2),#0);
    FillChar(DebugScnBuf,SizeOf(DebugScnBuf),#0);

    Menu := Nil;
    GoAhead := True;
    If frmMain.UseDirectDraw And frmMain.DDFullScreen Then GoAhead := frmMain.EnterFullScreenMode;
    If GoAhead Then
    Begin
      // Hide the mouse cursor

      If frmMain.UseDirectDraw And frmMain.DDFullScreen Then ShowCursor(False);

      Ctrl := GetCaptureControl;
      SetCaptureControl(frmMain);
      ResetClock;

      OldPos    := -1;
      LastWrite := 0;

      // Set a flag that will tell the emulator to ignore any breakpoint expression for
      // the very first instruction, since the expression is evaluated before the
      // instruction is executed.

      DebuggerBegin := True;

      Emulating := 2;
      Interpret(Start,P,A,X,Y,S);
      Emulating := 0;

      SetCaptureControl(Ctrl);

      ShowCursor(True);                  // Show the mouse cursor

      // Switch back to windowed mode

      frmMain.ExitFullScreenMode;
    End;

    // Stop the sound

    If Config.DoSound Then
    Begin
      frmMain.Secondary.Stop;
      frmMain.DXSound1.Primary.Stop;
    End;

    // If zooming to full but still in windowed mode, see if we have to unhide stuff

    If (frmMain.Zoom = 0) And Config.HideAllOnZoomFull And Not frmMain.DDFullScreen Then
    Begin
      frmMain.TBDock1.Visible  := True;    // Show and enable the coolbar
      frmMain.TBDock1.Enabled  := True;
      frmMain.TBDock2.Visible  := True;    // Show and enable the coolbar
      frmMain.TBDock2.Enabled  := True;
      frmMain.RestoreWindow;
      frmMain.BorderStyle      := bsSizeable;
      frmMain.Refresh;
    End;

    frmMain.SetImageSizes(False);

    InterfaceHandler.DeactivateInterfaces;

    // Temporarily turn the full screen flag off and re-display

    B := frmMain.DDFullScreen;
    frmMain.DDFullScreen := False;
    frmMain.Display;
    frmMain.DDFullScreen := B;

    If Config.DoSound Then ProcessPf2 := False;
    If Game.OldStart <> 0 Then AtariSeg[Game.OldStart] := Game.OldByte;
    HaltLine := 999;

    frmMain.UpdateDebugger;

    { Get rid of the break expresion PCollection }

    Debugger := frmMain.acUseDebugger.Checked;

    I := Game.VUserAdd;
    If Game.UserSetPos <> NoPosSet Then Inc(I,Game.UserSetPos);
    Case (Config.MaxRows - 200) Of
       0: MenuInfo.Pos200 := I;
       4: MenuInfo.Pos204 := I;
      15: MenuInfo.Pos215 := I;
      50: MenuInfo.Pos250 := I;
     105: MenuInfo.Pos305 := I;
    Else
      MenuInfo.Pos200 := I;
    End; { Case }

  frmMain.mnuFile.Enabled            := True;
  frmMain.mnuStart.Enabled           := True;
  frmMain.mnuController.Enabled      := True;
  frmMain.mnuInterfaces.Enabled      := True;

  frmMain.acVideoFullScreen.Enabled  := True;
  frmMain.acVideoTVScreen.Enabled    := True;
  frmMain.mnuMode.Enabled            := True;
  frmMain.mnuZoom.Enabled            := True;

  frmMain.acOpen.Enabled             := True;
  frmMain.acStartEmulation.Enabled   := True;
  frmMain.acProfileSettings.Enabled  := True;
  frmMain.acStopEmulation.Enabled    := False;
  frmMain.acDifficulty1.Enabled      := False;
  frmMain.acDifficulty2.Enabled      := False;
  frmMain.acSelect.Enabled           := False;
  frmMain.acReset.Enabled            := False;
  frmMain.acColorBW.Enabled          := False;
  frmMain.acNTSCPAL.Enabled          := False;
  frmMain.acVideoRecordToAVI.Enabled := False;
End; { Emulate }

// -------------------------------------------------------------

procedure TfrmMain.FormShow(Sender: TObject);
Var
  I    : Integer;
  Intf : TInterface;
  Ver  : Array[0..15] Of Char;

begin
  // Every time we change the border style FormShow gets called. We only want
  // it to be called once.

  If Not Showed Then
  Begin
    UsingKaillera := False;
    kailleraGetVersion(PChar(@Ver[0]));
    frmMenu.InitConfig(Config,128,31400,HandTIA.Version);
    Caption := 'PCAE ' + HandTIA.Version;
    Exiting := True;
    acUseDebugger.Checked := Debugger;
    Case Config.GameResolution Of
      gr320x200,gr160x200A,gr160x200B: acVideo320x200.Checked := True;
      gr320x204,gr160x204A,gr160x204B: acVideo320x204.Checked := True;
                gr160x215A,gr160x215B: acVideo320x215.Checked := True;
                gr160x250A,gr160x250B: acVideo320x250.Checked := True;
                gr160x305A,gr160x305B: acVideo320x305.Checked := True;
    Else
      acVideo320x200.Checked := True;
    End; // Case
    SetImageSizes(False);
    acStopEmulation.Enabled      := False;
    acVideoRecordToAVI.Enabled   := False;
    acStopEmulation.Enabled      := False;
    acDisassemble.Enabled        := False;
    acSaveScreenshot.Enabled     := False;
    acStartEmulation.Enabled     := False;
    acResetEmulation.Enabled     := False;
    acVideoTVScreen.Enabled      := DDFullScreen;
    acVideoFullScreen.Checked    := DDFullScreen;
    acVideoTVScreen.Checked      := TVScreen;
    acDifficulty1.Enabled        := False;
    acDifficulty2.Enabled        := False;
    acSelect.Enabled             := False;
    acReset.Enabled              := False;
    acColorBW.Enabled            := False;
    acNTSCPAL.Enabled            := False;
    acProfileSettings.Enabled    := False;
    acShowManual.Enabled         := False;

    // See which interfaces are enabled

    For I := 0 To InterfaceHandler.Stack.Count - 1 Do
    Begin
      Intf := TInterface(InterfaceHandler.Stack.Objects[I]);
      If UpperCase(Intf.Name) = 'MOUSE'    Then acEnableMouse.Checked      := Intf.Enabled;
      If UpperCase(Intf.Name) = 'KEYBOARD' Then acEnableKeyboard.Checked   := Intf.Enabled;
      If UpperCase(Intf.Name) = 'DIGITAL'  Then acEnableController.Checked := Intf.Enabled;
    End; // For I

    // Set the zoom mode

    Case Config.ZoomMode Of
      0: acVideoZoomFull.Checked := True;
      2: acVideoZoom2x.Checked := True;
      3: acVideoZoom3x.Checked := True;
      4: acVideoZoom4x.Checked := True;
    Else
      acVideoZoom1x.Checked := True;
    End; // Case

    // Grow the window if necessary to accommodate the play window

    If DXDraw1.Width > ClientWidth Then ClientWidth := DXDraw1.Width;
    If DXDraw1.Top + DXDraw1.Height > ClientHeight Then ClientHeight := DXDraw1.Top + DXDraw1.Height;

    // Initialize the sound buffer

    DXSound1.Driver := TDXSound.Drivers[0].GUID;
    DXSound1.Initialize;
    Showed := True;
  End;
end;

Procedure TfrmMain.Display;
Var
  B     : Boolean;
  P     : Pointer;
  DDFS  : Boolean;
  Cnt   : Integer;
  P1    : ^Byte;
  I     : Integer;
  WAdd  : LongInt;
  WAdd1 : LongInt;
  R     : TRect;

  Procedure ShowObjLoc(X: Integer);
  Var P: ^Byte;
  Begin
    If X >= 0 Then
    Begin
      P := Pointer(LongInt(ScnPtr) + (Config.MaxRows - Game.TIA_Scan) * 160 + X);
      P^ := 0;
    End;
  End; // ShowObjectLoc

Begin
  B    := UseMMX;
  DDFS := DDFullScreen And UseDirectDraw;
  Application.ProcessMessages;
  P := ScnPtr2;

  // Show beam position with a crosshair in white and show object locations in black

  If ShowCrosshair Then
  Begin
    If (Game.TIA_Scan >= 0) And (Game.TIA_Scan <= 199) Then
    Begin
      Cnt := Game.TIA_Count;
      If Cnt < 0 Then Cnt := 0;
      P1 := Pointer(LongInt(ScnPtr) + (Config.MaxRows - Game.TIA_Scan) * 160);
      FillChar(P1^,160,#15);
      P1 := Pointer(LongInt(ScnPtr) + Cnt);
      For I := 0 To Config.MaxRows - 1 Do
      Begin
        P1^ := 15;
        Inc(LongInt(P1),160);
      End;
    End;
    ShowObjLoc(Game.ObjectLoc[Index_Player0Set]);
    ShowObjLoc(Game.ObjectLoc[Index_Player1Set]);
    ShowObjLoc(Game.ObjectLoc[Index_Missile0Set]);
    ShowObjLoc(Game.ObjectLoc[Index_Missile1Set]);
    ShowObjLoc(Game.ObjectLoc[Index_BallSet]);
  End;

  If DDFS Then
  Begin
    R.Left   := 0;
    R.Top    := 0;
    R.Right  := frmMain.DXDraw1.Display.Width;
    R.Bottom := frmMain.DXDraw1.Display.Height;
    P        := SDesc.lpSurface;
    If TVScreen Then
    Begin
      WAdd := SDesc.lPitch - 640;
      Asm
        PUSH  ESI
        PUSH  EDI
        PUSH  EBX
        PUSH  EBP
        MOV   EBX,DWORD PTR WAdd
        MOV   ESI,DWORD PTR ScnPtr
        MOV   EDI,DWORD PTR P
        ADD   ESI,DWORD PTR LocalBufSize
        SUB   ESI,160

        MOVZX EBP,WORD PTR Config.MaxRows
@LTV5:
        PUSH  EBP
        MOV   EBP,40

        // Move a line of dot data

@LTV4:
        MOV   EAX,DWORD PTR [ESI]
        ADD   ESI,4

        MOV   ECX,4
@LTV1:
        MOV   DL,AL
        MOV   DH,AL
        ROL   EDX,16
        MOV   DL,AL
        MOV   DH,AL
        MOV   DWORD PTR [EDI],EDX
        ROR   EAX,8
        ADD   EDI,4
        DEC   ECX
        JNZ   @LTV1

        DEC   EBP
        JNZ   @LTV4
        ADD   EDI,EBX                 // Added JD 3-30-00

        // Create a blank line

        SUB   EAX,EAX
        MOV   ECX,160
@LTV2:
        MOV   DWORD PTR [EDI],EAX
        ADD   EDI,4
        DEC   ECX
        JNZ   @LTV2
        ADD   EDI,EBX                 // Added JD 3-30-00

        // Move to the next line

        POP   EBP
        SUB   ESI,2 * ScnBufWidth
        DEC   EBP
        JNZ   @LTV5

        POP   EBP
        POP   EBX
        POP   EDI
        POP   ESI
      End; { Asm }
    End
    Else
    Begin
      If DoubleUp Then
      Begin
        WAdd  := SDesc.lPitch - 640;
        WAdd1 := SDesc.lPitch;
        Asm
          PUSH  ESI
          PUSH  EDI
          PUSH  EBX
          PUSH  EBP
          MOV   EBX,DWORD PTR WAdd
          MOV   EDX,DWORD PTR WAdd1
          MOV   ESI,DWORD PTR ScnPtr
          MOV   EDI,DWORD PTR P
          ADD   ESI,DWORD PTR LocalBufSize
          SUB   ESI,160
          TEST  BYTE PTR B,0FFh
          JZ    @L1
          PUSH  EBP
          MOVZX EBP,WORD PTR Config.MaxRows
@L6:
          PUSH  EBP
          MOV   EBP,20
    { --------------------------------------------------------------------------- }
    { MMX available                                                               }
    { --------------------------------------------------------------------------- }
@L2:
          DB    0Fh,6Fh,06h             { MOVQ        MM0,[ESI]      }
          ADD   ESI,8
          DB    0Fh,6Fh,0C8h            { MOVQ        MM1,MM0        }
          DB    0Fh,6Fh,0D0h            { MOVQ        MM2,MM0        }
          DB    0Fh,60h,0C8h            { PUNPCKLBW   MM1,MM0        }
          DB    0Fh,68h,0D0h            { PUNPCKHBW   MM2,MM0        }

          DB    0Fh,6Fh,0D9h            { MOVQ        MM3,MM1        }
          DB    0Fh,6Fh,0E1h            { MOVQ        MM4,MM1        }
          DB    0Fh,6Fh,0EAh            { MOVQ        MM5,MM2        }
          DB    0Fh,6Fh,0F2h            { MOVQ        MM6,MM2        }

          DB    0Fh,60h,0D9h            { PUNPCKLBW   MM3,MM1        }
          DB    0Fh,68h,0E1h            { PUNPCKHBW   MM4,MM1        }
          DB    0Fh,60h,0EAh            { PUNPCKLBW   MM5,MM2        }
          DB    0Fh,68h,0F2h            { PUNPCKHBW   MM6,MM2        }

          DB    0Fh,7Fh,1Fh             { MOVQ        [EDI],MM3      }
          DB    0Fh,7Fh,67h,08h         { MOVQ        [EDI + 8],MM4  }
          DB    0Fh,7Fh,6Fh,10h         { MOVQ        [EDI + 16],MM5 }
          DB    0Fh,7Fh,77h,18h         { MOVQ        [EDI + 24],MM6 }

          DB    0Fh,7Fh,1Ch,3Ah         { MOVQ        [EDI + EDX],MM3      }
          DB    0Fh,7Fh,64h,3Ah,08h     { MOVQ        [EDI + EDX + 8],MM4  }
          DB    0Fh,7Fh,6Ch,3Ah,10h     { MOVQ        [EDI + EDX + 16],MM5 }
          DB    0Fh,7Fh,74h,3Ah,18h     { MOVQ        [EDI + EDX + 24],MM6 }

          ADD   EDI,32
          DEC   EBP
          JNZ   @L2
          POP   EBP
          SUB   ESI,2 * ScnBufWidth
          ADD   EDI,EBX                 // Added JD 3-30-00
          ADD   EDI,EDX
          DEC   EBP
          JNZ   @L6
          DB    0Fh,77h                 { EMMS                      }

          POP   EBP

          JMP   @L3
    { --------------------------------------------------------------------------- }
    { MMX not available                                                           }
    { --------------------------------------------------------------------------- }
@L1:
          MOVZX EBP,WORD PTR Config.MaxRows
@L5:
          PUSH  EBP
          MOV   EBP,40
          PUSH  EBX
@L4:
          MOV   EAX,DWORD PTR [ESI]
          ADD   ESI,4

          MOV   BH,AL
          MOV   BL,AL
          MOV   ECX,EBX
          SHL   EBX,16
          MOV   BX,CX
          MOV   DWORD PTR [EDI],EBX
          MOV   DWORD PTR [EDI + EDX],EBX

          MOV   BH,AH
          MOV   BL,AH
          MOV   ECX,EBX
          SHL   EBX,16
          MOV   BX,CX
          MOV   DWORD PTR [EDI + 4],EBX
          MOV   DWORD PTR [EDI + EDX + 4],EBX

          SHR   EAX,16

          MOV   BH,AL
          MOV   BL,AL
          MOV   ECX,EBX
          SHL   EBX,16
          MOV   BX,CX
          MOV   DWORD PTR [EDI + 8],EBX
          MOV   DWORD PTR [EDI + EDX + 8],EBX

          MOV   BH,AH
          MOV   BL,AH
          MOV   ECX,EBX
          SHL   EBX,16
          MOV   BX,CX
          MOV   DWORD PTR [EDI + 12],EBX
          MOV   DWORD PTR [EDI + EDX + 12],EBX

          ADD   EDI,16
          DEC   EBP
          JNZ   @L4
          POP   EBX
          POP   EBP
          SUB   ESI,2 * ScnBufWidth
          ADD   EDI,EBX                 // Added JD 3-30-00
          ADD   EDI,EDX
          DEC   EBP
          JNZ   @L5
@L3:
          POP   EBP
          POP   EBX
          POP   EDI
          POP   ESI
        End; { Asm }
      End
      Else
      Begin
        WAdd := SDesc.lPitch - 320;
        Asm
          PUSH  ESI
          PUSH  EDI
          PUSH  EBX
          PUSH  EBP
          MOV   EBX,DWORD PTR WAdd
          MOV   ESI,DWORD PTR ScnPtr
          MOV   EDI,DWORD PTR P
          ADD   ESI,DWORD PTR LocalBufSize
          SUB   ESI,160
          TEST  BYTE PTR B,0FFh
          JZ    @L1
          PUSH  EBP
          MOVZX EBP,WORD PTR Config.MaxRows
@L6:
          PUSH  EBP
          MOV   EBP,20
    { --------------------------------------------------------------------------- }
    { MMX available                                                               }
    { --------------------------------------------------------------------------- }
@L2:
          DB    0Fh,6Fh,06h             { MOVQ        MM0,[ESI]     }
          ADD   ESI,8
          DB    0Fh,6Fh,0C8h            { MOVQ        MM1,MM0       }
          DB    0Fh,6Fh,0D0h            { MOVQ        MM2,MM0       }
          DB    0Fh,60h,0C8h            { PUNPCKLBW   MM1,MM0       }
          DB    0Fh,68h,0D0h            { PUNPCKHBW   MM2,MM0       }
          DB    0Fh,7Fh,0Fh             { MOVQ        [EDI],MM1     }
          DB    0Fh,7Fh,57h,08h         { MOVQ        [EDI + 8],MM2 }
          ADD   EDI,16
          DEC   EBP
          JNZ   @L2
          POP   EBP
          SUB   ESI,2 * ScnBufWidth
          ADD   EDI,EBX                 // Added JD 3-30-00
          DEC   EBP
          JNZ   @L6
          DB    0Fh,77h                 { EMMS                      }

          POP   EBP

          JMP   @L3
    { --------------------------------------------------------------------------- }
    { MMX not available                                                           }
    { --------------------------------------------------------------------------- }
@L1:
          MOVZX EBP,WORD PTR Config.MaxRows
@L5:
          PUSH  EBP
          MOV   EBP,40
          PUSH  EBX
@L4:
          MOV   EAX,DWORD PTR [ESI]     { U }
          ADD   ESI,4                         { V }
          MOV   EBX,EAX                 { U }
          MOV   DL,AH                         { V }
          SHR   EBX,16                  { U }
          MOV   AH,AL                         { V }
          MOV   DH,DL                   { U }
          MOV   CL,BH                         { V }
          SHL   EDX,16                  { U }
          MOV   BH,BL                         { V }
          MOV   CH,CL                   { U }
          MOV   DX,AX                         { V }
          SHL   ECX,16                  { U }
          MOV   DWORD PTR [EDI],EDX           { V }
          OR    ECX,EBX                 { U }
          MOV   DWORD PTR [EDI + 4],ECX       { V }
          ADD   EDI,8                   { U }
          DEC   EBP                           { V }
          JNZ   @L4                     { U }
          POP   EBX
          POP   EBP
          SUB   ESI,2 * ScnBufWidth
          ADD   EDI,EBX                 // Added JD 3-30-00
          DEC   EBP
          JNZ   @L5
@L3:
          POP   EBP
          POP   EBX
          POP   EDI
          POP   ESI
        End; { Asm }
      End;
    End;
  End
  Else
  Begin
    Asm
      PUSH  ESI
      PUSH  EDI
      PUSH  EBX
      PUSH  EBP
      MOV   ESI,DWORD PTR ScnPtr
      MOV   EDI,DWORD PTR P
      TEST  BYTE PTR B,0FFh
      JZ    @L1

      MOV   EBP,DWORD PTR LocalBufSize
      SHR   EBP,3
{ --------------------------------------------------------------------------- }
{ MMX available                                                               }
{ --------------------------------------------------------------------------- }
@L2:
      DB    0Fh,6Fh,06h             { MOVQ        MM0,[ESI]     }
      ADD   ESI,8
      DB    0Fh,6Fh,0C8h            { MOVQ        MM1,MM0       }
      DB    0Fh,6Fh,0D0h            { MOVQ        MM2,MM0       }
      DB    0Fh,60h,0C8h            { PUNPCKLBW   MM1,MM0       }
      DB    0Fh,68h,0D0h            { PUNPCKHBW   MM2,MM0       }
      DB    0Fh,7Fh,0Fh             { MOVQ        [EDI],MM1     }
      DB    0Fh,7Fh,57h,08h         { MOVQ        [EDI + 8],MM2 }
      ADD   EDI,16
      DEC   EBP
      JNZ   @L2
      DB    0Fh,77h                 { EMMS                      }
      JMP   @L3
{ --------------------------------------------------------------------------- }
{ MMX not available                                                           }
{ --------------------------------------------------------------------------- }
@L1:

      MOV   EBP,DWORD PTR LocalBufSize
      SHR   EBP,2
@L4:
      MOV   EAX,DWORD PTR [ESI]     { U }
      ADD   ESI,4                         { V }
      MOV   EBX,EAX                 { U }
      MOV   DL,AH                         { V }
      SHR   EBX,16                  { U }
      MOV   AH,AL                         { V }
      MOV   DH,DL                   { U }
      MOV   CL,BH                         { V }
      SHL   EDX,16                  { U }
      MOV   BH,BL                         { V }
      MOV   CH,CL                   { U }
      MOV   DX,AX                         { V }
      SHL   ECX,16                  { U }
      MOV   DWORD PTR [EDI],EDX           { V }
      OR    ECX,EBX                 { U }
      MOV   DWORD PTR [EDI + 4],ECX       { V }
      ADD   EDI,8                   { U }
      DEC   EBP                           { V }
      JNZ   @L4                     { U }
@L3:
      POP   EBP
      POP   EBX
      POP   EDI
      POP   ESI
    End; { Asm }
  End;
  If UseDirectDraw Then
  Begin
    If DDFullScreen Then
    Begin
      // Do nothing; data was written directly

      If Config.ShowFPS Then
      Begin
        DXDraw1.Primary.Canvas.Font.Color  := clLime;
        DXDraw1.Primary.Canvas.Font.Name   := 'Arial';
        DXDraw1.Primary.Canvas.Font.Size   := 12;
        DXDraw1.Primary.Canvas.Brush.Style := bsClear;
        DXDraw1.Primary.Canvas.TextOut(10,10,Format('%f',[FPS]) + ' fps');
        DXDraw1.Primary.Canvas.Release;
      End;

    End
    Else
    Begin
      If DXDraw1.CanDraw Then
      Begin
        If UsingKaillera Then
        Begin
          SetDIBitsToDevice(frmKaillera.DXDraw1.Surface.Canvas.Handle,0,0,Config.MaxCols,Config.MaxRows,0,0,0,ScnBufHeight,ScnPtr2,BI1.B,DIB_RGB_COLORS);

          If Config.ShowFPS Then
          Begin
            frmKaillera.DXDraw1.Surface.Canvas.Font.Color  := clLime;
            frmKaillera.DXDraw1.Surface.Canvas.Font.Name   := 'Arial';
            frmKaillera.DXDraw1.Surface.Canvas.Font.Size   := 12;
            frmKaillera.DXDraw1.Surface.Canvas.Brush.Style := bsClear;
            frmKaillera.DXDraw1.Surface.Canvas.TextOut(10,10,Format('%f',[FPS]) + ' fps');
          End;

          frmKaillera.DXDraw1.Surface.Canvas.Release;
          frmKaillera.DXDraw1.Flip;
        End
        Else
        Begin
          SetDIBitsToDevice(DXDraw1.Surface.Canvas.Handle,0,0,Config.MaxCols,Config.MaxRows,0,0,0,ScnBufHeight,ScnPtr2,BI1.B,DIB_RGB_COLORS);

          If Config.ShowFPS Then
          Begin
            DXDraw1.Surface.Canvas.Font.Color  := clLime;
            DXDraw1.Surface.Canvas.Font.Name   := 'Arial';
            DXDraw1.Surface.Canvas.Font.Size   := 12;
            DXDraw1.Surface.Canvas.Brush.Style := bsClear;
            DXDraw1.Surface.Canvas.TextOut(10,10,Format('%f',[FPS]) + ' fps');
          End;

          DXDraw1.Surface.Canvas.Release;
          DXDraw1.Flip;
        End;
      End;
    End;
  End
  Else
  Begin
    SetDIBitsToDevice(Image1.Canvas.Handle,0,0,ScnBufWidth,ScnBufHeight,0,0,0,SHeight,ScnPtr2,BI1.B,DIB_RGB_COLORS);
    If Config.ShowFPS Then
    Begin
      Image1.Canvas.Font.Color  := clLime;
      Image1.Canvas.Font.Name   := 'Arial';
      Image1.Canvas.Font.Size   := 12;
      Image1.Canvas.Brush.Style := bsClear;
      Image1.Canvas.TextOut(10,10,Format('%f',[FPS]) + ' fps');
    End;
  End;
  If Image1.Visible Then Image1.Repaint;
  Application.ProcessMessages;
End;

procedure TfrmMain.FormCreate(Sender: TObject);
Var
  F   : File;
  B   : Boolean;
  St  : String;
  INI : TINIFile;

  Procedure ErrorFileNotFound(Const Path,St: String);
  Begin
    ShowMessage('Sorry, but PCAE was unable to find file ' + St + ' in' + #13#10 +
                'directory ' + ExpandFileName(Path) + #13#10 +
                #13#10 +
                'You should make sure that PCAE was run from the' + #13#10 +
                'right directory and that ' + St + ' is present.');
  End; { ErrorFileNotFound }

begin
  TBIniLoadPositions(Self, ExtractFilePath(Application.EXEName) + 'pcaewin.ini', 'Toolbars');
  INI := TINIFile.Create(ExtractFilePath(Application.EXEName) + 'pcaewin.ini');
  Try
    MRUList.LoadFromIni(INI, 'RecentFiles');
  Finally
    INI.Free;
  End;


//  Surface := Nil;
  St := 'PCAE ' + HandTIA.Version;
  KInfo.AppName               := StrAlloc(Length(St) + 1);
  StrPCopy(KInfo.AppName,St);
  KInfo.GameList              := ConcatAllNames;
  KInfo.GameCallBack          := @KailleraGameCallBack;
  KInfo.ChatReceivedCallBack  := @KailleraChatReceivedCallBack;
  KInfo.ClientDroppedCallBack := @KailleraClientDroppedCallBack;
  KInfo.MoreInfoCallBack      := @KailleraMoreInfoCallBack;
  KailleraSetInfo(KInfo);


  Showed := False;

  // Load NTSC palette

  If FileExists(ExtractFilePath(Application.ExeName) + 'PCAE.PA0') Then
  Begin
    AssignFile(F,ExtractFilePath(Application.ExeName) + 'PCAE.PA0');
    Reset(F,1);
    BlockRead(F,Pal,128 * SizeOf(RGB));
    CloseFile(F);
  End
  Else
  Begin
    ErrorFileNotFound(ExtractFilePath(Application.ExeName),'PCAE.PA0');
    Close;
  End;

  // Load PAL palette

  If FileExists(ExtractFilePath(Application.ExeName) + 'PCAE.PA1') Then
  Begin
    AssignFile(F,ExtractFilePath(Application.ExeName) + 'PCAE.PA1');
    Reset(F,1);
    BlockRead(F,Pal[128],128 * SizeOf(RGB));
    CloseFile(F);
  End
  Else
  Begin
    ErrorFileNotFound(ExtractFilePath(Application.ExeName),'PCAE.PA1');
    Close;
  End;

  Debugger      := False;
  UseDirectDraw := True; // False;
  DDFullScreen  := False;
  TVScreen      := False;
  DoubleUp      := False;
  LastFSWidth   := 0;
  LastFSHeight  := 0;
  SWidth        := 2 * ScnBufWidth;
  SHeight       := ScnBufHeight;
  Zoom          := 1;
  ShowCrosshair := False;
  Scaled        := False;

  // Determine if MMX is available

  UseMMX := False;
  B      := False;

  { Find out if this processor supports MMX }

  Asm
//    CLI

    { Find out if the CPUID instruction is available }

    PUSHAD
    PUSHFD
    POP   ECX                 { Get original EFLAGS }
    MOV   EAX,ECX
    XOR   EAX,200000h         { Flip ID bit in EFLAGS }
    PUSH  EAX                 { Save new EFLAGS value on stack }
    POPFD                     { Replace current EFLAGS value }
    PUSHFD                    { Get new EFLAGS }
    POP   EAX                 { Store new EFLAGS in EAX }
    XOR   EAX,ECX             { Can't toggle ID bit, }
    JE    @NoMMX              { Processor = 80486 or lower }

    { See if MMX is available }

    MOV   EAX,1               { Get feature flag info }
    DB    0Fh,0A2h            { CPUID }
    TEST  EDX,0800000h        { See if MMX is available }
    JZ    @NoMMX
    MOV   B,1

@NoMMX:
    PUSH  ECX
    POPFD
    POPAD
//    STI
  End; { Asm }
  UseMMX := B;
end;

procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Exiting := True;
  frmMenu.SaveConfiguration(Config,HandTIA.Version);
  Zoom := 1;
end;

Procedure TfrmMain.SetImageSizes(Starting: Boolean);
Begin
  LocalBufSize := (Config.MaxCols * Config.MaxRows) Div 2;
  If Zoom > 0 Then
  Begin
    SWidth  := Config.MaxCols * Zoom;
    SHeight := Config.MaxRows * Zoom;
  End
  Else
  Begin
    If ClientWidth > 0 Then SWidth  := ClientWidth;
    If ClientHeight > 0 Then
    Begin
      If Config.HideAllOnZoomFull And Starting And Not DDFullScreen
       Then SHeight := ClientHeight
       Else SHeight := ClientHeight - Max(TBDock1.Top + TBDock1.Height,TBDock2.Top + TBDock2.Height);
    End;
  End;
  If UseDirectDraw Then
  Begin
    If DDFullScreen Then
    Begin
{
      DXDraw1.Width            := DXDraw1.Display.Width;
      DXDraw1.Height           := DXDraw1.Display.Height;
      DXDraw1.SurfaceWidth     := DXDraw1.Display.Width;
      DXDraw1.SurfaceHeight    := DXDraw1.Display.Height;
}
{
      DXDraw1.Width            := Config.MaxCols;
      DXDraw1.Height           := Config.MaxRows;
      DXDraw1.SurfaceWidth     := Config.MaxCols;
      DXDraw1.SurfaceHeight    := Config.MaxRows;
      DXDraw1.Display.BitCount := 8;
}
(*
      DXDraw1.Display.Width    := 640;//320;
{      If Config.MaxCols > 200
       Then DXDraw1.Display.Height := 240
       Else} DXDraw1.Display.Height := 480;//200;
*)
    End
    Else
    Begin
      DXDraw1.Width         := SWidth;
      DXDraw1.Height        := SHeight;
      DXDraw1.SurfaceWidth  := Config.MaxCols;//SWidth;
      DXDraw1.SurfaceHeight := Config.MaxRows;//SHeight;

      frmKaillera.DXDraw1.Width         := Config.MaxCols;
      frmKaillera.DXDraw1.Height        := Config.MaxRows;
      frmKaillera.DXDraw1.SurfaceWidth  := Config.MaxCols;//SWidth;
      frmKaillera.DXDraw1.SurfaceHeight := Config.MaxRows;//SHeight;
    End;
  End
  Else
  Begin
    Image1.Width  := SWidth;
    Image1.Height := SHeight;
  End;
  Image1.Visible  := Not UseDirectDraw;
  DXDraw1.Visible := UseDirectDraw;
  Image1.Left     := 0;
  DXDraw1.Left    := 0;
  If (Zoom = 0) And Config.HideAllOnZoomFull And Starting And Not DDFullScreen Then
  Begin
    Image1.Top  := 0;
    DXDraw1.Top := 0;
  End
  Else
  Begin
    Image1.Top  := Max(TBDock1.Top + TBDock1.Height,TBDock2.Top + TBDock2.Height);
    DXDraw1.Top := Max(TBDock1.Top + TBDock1.Height,TBDock2.Top + TBDock2.Height);
  End;
End; // TfrmMain.SetImageSizes

Procedure TfrmMain.LoadGameFromAnywhere(FileName: String);
Var
  Zip         : Boolean;
  ZipFileName : String;
  Path        : String;

Begin
  If FileName <> '' Then
  Begin
    Path := Config.GamePath;
    If (Path <> '') And (Path[Length(Path)] <> '\') Then Path := Path + '\';
    If FileExistsZip(Path,FileName,False,Zip) Then
    Begin
      If Zip Then ZipFileName := ZipCachePath + ZipCacheName Else ZipFileName := '';
      LoadGame(Path + FileName,ZipFileName,'');
    End;
  End;
End; // TfrmMain.LoadGameFromAnywhere

Procedure TfrmMain.LoadGame(FileName,ZipFileName,Title: String);
Var
  F         : TFileStream;
  Loaded    : LongInt;
  I,J       : Integer;
  Start     : Word;
  ZipStream : TZipStream;
  Zip       : Boolean;
  Size      : Integer;
  Stream    : TStream;

  Procedure LoadROM(Address,Amount: Word);
  Begin
    Stream.ReadBuffer(AtariSeg[Address],Amount);
  End; { LoadROM }

Begin
  If FileName <> '' Then
  Begin
    ROMFileName := Trim(UpperCase(FileName));
    ZipFileName := Trim(UpperCase(ZipFileName));
    If (ROMFileName <> '') And
       (FileExists(ROMFileName) Or
        ((ZipFileName <> '') And FileExists(ZipFileName)))  Then
    Begin
      If Exiting Then
      Begin
        acStartEmulation.Enabled   := True;
        acStopEmulation.Enabled    := False;
        acVideoRecordToAvi.Enabled := False;
        acShowManual.Enabled       := True;
        acDisassemble.Enabled      := True;
        acSaveScreenshot.Enabled   := True;
        acProfileSettings.Enabled  := True;
      End;
      acResetEmulation.Enabled := True;
      Caption := 'PCAE ' + HandTIA.Version + ' - ' + Title + ' [' +
       ExtractFileName(FileName) + ']';
      InitGameType;
      If ExtractFileExt(ROMFileName) = '.PAL'
       Then Game.Palette := 1
       Else Game.Palette := 0;
      Case Game.Cart Of
           ct8k: SetBankInfo('8',Game);
          ct16k: SetBankInfo('6',Game);
    ctSuperChip: SetBankInfo('R',Game);
   ctParkerBros: SetBankInfo('P',Game);
     ctMNetwork: SetBankInfo('M',Game);
     ctStarpath: SetBankInfo('S',Game);
          ctCBS: SetBankInfo('C',Game);
  ctTigerVision: SetBankInfo('T',Game);
     ctPitfall2: SetBankInfo('2',Game);
   ctActivision: SetBankInfo('A',Game);
      ctMegaBoy: SetBankInfo('G',Game);
     ctCommaVid: SetBankInfo('V',Game);
    ctCompumate: SetBankInfo('O',Game);
      End; // Case

      If Trim(ExtractFileName(ZipFileName)) <> '' Then
      Begin
        ZipMaster1.ZipFilename := ZipFileName;
        ZipStream := ZipMaster1.ExtractFileToStream(ExtractFileName(FileName));
        Zip       := True;
        Stream    := ZipStream;
      End
      Else
      Begin
        F      := TFileStream.Create(ROMFileName,fmOpenRead);
        Stream := F;
        Zip  := False;
      End;
      Game.ROMSize := Stream.Size;
      If Game.ROMSize < 4096 Then
      Begin
        I := 0;
        While I * Game.ROMSize < 4096 Do
        Begin
          Stream.Position := 0;
          If (I + 1) * Game.ROMSize <= 4096
           Then Loaded := Game.ROMSize
           Else Loaded := 4096 - I * Game.ROMSize;
          LoadROM($1000 + I * Game.ROMSize,Loaded);
          Inc(I);
        End; { While }
      End
      Else LoadROM($1000,4096);
      If (Game.ROMSize = 8192) And (Game.Cart = ct8k) Then
      Begin
        Stream.Position := 4096;
        LoadROM($1000,4096);
      End;
      If Game.Cart = ct32In1 Then
      Begin
        Stream.Position := Game.MegaBoyNum * 2048;
        LoadROM($1000,2048);
        Stream.Position := Game.MegaBoyNum * 2048;
        LoadROM($1800,2048);
      End;
      If (Game.ROMSize >= 8192) And (Game.Cart = ctParkerBros) Then
      Begin
        Stream.Position := 7168;
        LoadROM($1C00,1024);
        Game.BankSize := 256;    { Size in dwords }
      End;
      If Game.Cart = ctTigerVision Then
      Begin
        Stream.Position := Game.ROMSize - 2048;
        Game.TigerLimit := (Game.ROMSize - 2048) Shr 11;
        LoadROM($1800,2048);
      End;

      If (Game.ROMSize = 16384) And (Game.Cart = ctMNetwork) Then
      Begin
        Stream.Position := 14 * 1024;
        LoadROM($1800,2048);
        Game.BankSize := 512;    { Size in dwords }
      End;

      { Load 2nd 4k for SuperChip }

      If Game.Cart = ctSuperChip Then
      Begin
        Stream.Position := 4096;
        LoadROM($1000,4096);
        I := Game.ROMSize Shr 12;
        Case I Of
           0..2: J := $1FF8;
           3..4: J := $1FF6;
           5..8: J := $1FF4;
          9..15: J := $1FEC;
        Else
          J := $1FF8;
        End; { Case }
        For I := J To J + (Game.ROMSize Shr 12) - 1 Do Game.BankSwitch[I] := $40 + (I - J);
      End;

      { Load Compumate }

      If Game.Cart = ctCompumate Then
      Begin
        Stream.Position := $3000;
        LoadROM($1000,4096);
      End;

      InitStarpath;

      Stream.Position := 0;
      If Game.Cart <> ctStarpath
       Then Stream.ReadBuffer(ROMBackup,Game.ROMSize)
       Else LoadStarpath(Stream,Game.ROMSize);
      If (Game.Cart In [ctMegaBoy,ct32In1]) And (Stream.Size = Game.ROMSize + 16) Then Stream.ReadBuffer(Game.MegaBoy,16); //BlockRead(F,Game.MegaBoy,16);
      If Zip Then ZipStream.Clear Else F.Free;
      If Game.Cart <> ctStarPath
       Then Start := AtariSegW($1FFC) And $1FFF
       Else Start := ROMBackupW($2000) And $1FFF;
      If (Game.Cart = ctPitfall2) And (Game.ROMSize = 8192 + 2048 + 255) Then
       FillDump(ROMBackup);

      If Game.Cart = ctStarPath Then
      Begin
        SPSearch := 0;
        Asm
          PUSHAD
          MOV   EDI,OFFSET ROMBackup
          MOV   BL,BYTE PTR [EDI+2002h]

          MOV   BYTE PTR AtariSeg[80h],BL

          MOV   DL,BL
          MOV   WORD PTR Game.StarpathLastAddr,0
          SHR   BL,1
          AND   EBX,0Eh

          MOVZX EAX,WORD PTR SP1[EBX]
          MOV   ECX,200h

          MOV   ESI,OFFSET ROMBackup
          MOV   EDI,(OFFSET AtariSeg)+1000h
          ADD   ESI,EAX
          CLD
          REP   MOVSD

          MOVZX EAX,WORD PTR SP2[EBX]
          MOV   ECX,200h

          MOV   ESI,OFFSET ROMBackup
          MOV   EDI,(OFFSET AtariSeg)+1800h
          ADD   ESI,EAX
          CLD
          REP   MOVSD

          MOV   BYTE PTR Game.SPBankNum,DL
          POPAD
        End; { Asm }
      End;
      Game._6507_PC := Start;
      Game.OldByte  := AtariSeg[Start];
      Game.OldStart := 0;
      InitEmulator;
      UpdateDebugger;
      frmMain.UpdateButtonStatuses;
      If Trim(ExtractFileName(ZipFileName)) <> '' Then DeleteFile(FileName);
      MRUList.Add(ExtractFileName(FileName));
    End;
  End;
End; // TfrmMain.LoadGame

Procedure TfrmMain.UpdateDebugger;
Begin
  If frmMain.acUseDebugger.Checked Then
  Begin
    If Not frmDebugger.Visible Then frmDebugger.Show;
    frmDebugger.InitDebugger;  // Force initialization
    frmDebugger.Repaint;
  End;
End; // TfrmMain.UpdateDebugger

procedure TfrmMain.DXSound1Initialize(Sender: TObject);
Var
  WaveFormat : TWaveFormatEx;
  DSBD       : DSBUFFERDESC;

begin
  {  31400Hz, 8bit, Mono  }

  MakePCMWaveFormatEx(WaveFormat, Playback_Freq, 8, 1);
  DXSound1.Primary.SetFormat(WaveFormat);
//  DXSound1.Primary.SetSize(WaveFormat,256);
  DXSound1.Primary.Volume := 0;

  Secondary := TDirectSoundBuffer.Create(DXSound1.DSound);
  FillChar(DSBD,SizeOf(DSBD),#0);
  DSBD.dwSize        := SizeOf(DSBD);
  DSBD.dwFlags       := DSBCAPS_GETCURRENTPOSITION2 + DSBCAPS_GLOBALFOCUS;
  DSBD.dwBufferBytes := SndBufSize;
  DSBD.lpwfxFormat   := @WaveFormat;
  Secondary.CreateBuffer(DSBD);
  Secondary.Volume   := 0;
end;

procedure TfrmMain.DXSound1Finalize(Sender: TObject);
begin
  Secondary.Free;
end;

procedure TfrmMain.CoolBar1Resize(Sender: TObject);
begin
  frmMain.SetImageSizes(Emulating > 0);
end;

procedure TfrmMain.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Case Button Of
    mbLeft: _MouseB := _MouseB Or 1;
   mbRight: _MouseB := _MouseB Or 2;
  mbMiddle: _MouseB := _MouseB Or 4;
  End; { Case }
end;

procedure TfrmMain.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Case Button Of
    mbLeft: _MouseB := _MouseB And Not 1;
   mbRight: _MouseB := _MouseB And Not 2;
  mbMiddle: _MouseB := _MouseB And Not 4;
  End; { Case }
end;

Procedure TfrmMain.DeactivateApp(Sender: TObject);
Begin
  If UseDirectDraw    And
     DDFullScreen     And
     (Emulating <> 0) And
     (doFullScreen In DXDraw1.Options) Then
     Begin
       If Emulating > 1 Then Dec(Emulating) Else Exiting := True;
     End;
End; // TfrmMain.DeactivateApp

procedure TfrmMain.FormResize(Sender: TObject);
begin
  If Zoom = 0 Then SetImageSizes(Emulating > 0);
end;

procedure TfrmMain.acOpenExecute(Sender: TObject);
begin
  If Config.AlternateGameMenu
   Then frmAltMenu.ShowModal
   Else frmMenu.ShowModal;
  LoadGame(MenuInfo.FileName,MenuInfo.ZipFileName,MenuInfo.Title);
end;

procedure TfrmMain.acPreferencesExecute(Sender: TObject);
begin
  frmPrefs.ShowModal;
end;

procedure TfrmMain.acProfileSettingsExecute(Sender: TObject);
Var
  F : TFileType;
  I : Integer;
  M : TMenuInfo;
  T : TFileType;

begin
  T := TFileType.Create;
  M := MenuInfo;
  If M.ProfileRec <> Nil Then
  Begin
    T.Name         := M.ProfileRec.Name;
    T.RealName     := M.ProfileRec.RealName;
    T.Cart         := M.ProfileRec.Cart;
    T.Cont         := M.ProfileRec.Cont;
    T.Pos200       := M.ProfileRec.Pos200;
    T.Pos204       := M.ProfileRec.Pos204;
    T.Pos215       := M.ProfileRec.Pos215;
    T.Pos250       := M.ProfileRec.Pos250;
    T.Pos305       := M.ProfileRec.Pos305;
    T.Manufacturer := M.ProfileRec.Manufacturer;
    T.Year         := M.ProfileRec.Year;
    T.DefaultSize  := M.ProfileRec.DefaultSize;
    T.Palette      := M.ProfileRec.Palette;
  End
  Else
  Begin
    T.Name         := M.FileName;
    T.RealName     := M.Title;
    T.Cart         := ct4k;
    T.Cont         := crJoystick;
    T.Pos200       := 0;
    T.Pos204       := 0;
    T.Pos215       := 0;
    T.Pos250       := 0;
    T.Pos305       := 0;
    T.Manufacturer := '';
    T.Year         := 1977;
    T.DefaultSize  := 0;
    T.Palette      := plNone;
  End;
  I := Game.VUserAdd;
  If Game.UserSetPos <> NoPosSet Then Inc(I,Game.UserSetPos);
  If I = 0 Then I := NoPosSet;
  F := TFileType.Create;
  F.Pos200 := MenuInfo.Pos200;
  F.Pos204 := MenuInfo.Pos204;
  F.Pos215 := MenuInfo.Pos215;
  F.Pos250 := MenuInfo.Pos250;
  F.Pos305 := MenuInfo.Pos305;
  Case (Config.MaxRows - 200) Of
     0: MenuInfo.Pos200 := I;
     4: MenuInfo.Pos204 := I;
    15: MenuInfo.Pos215 := I;
    50: MenuInfo.Pos250 := I;
   105: MenuInfo.Pos305 := I;
  Else
    MenuInfo.Pos200 := I;
  End; { Case }
  frmProfileSettings.ShowModal;
  MenuInfo.Pos200 := F.Pos200;
  MenuInfo.Pos204 := F.Pos204;
  MenuInfo.Pos215 := F.Pos215;
  MenuInfo.Pos250 := F.Pos250;
  MenuInfo.Pos305 := F.Pos305;
  F.Free;
  Caption := 'PCAE ' + HandTIA.Version + ' - ' + MenuInfo.Title + ' [' +
   ExtractFileName(MenuInfo.FileName) + ']';
  If (MenuInfo.ProfileRec <> Nil) And (M.ProfileRec <> Nil) Then
  Begin
    If T.Cart <> MenuInfo.ProfileRec.Cart Then
     LoadGame(MenuInfo.FileName,MenuInfo.ZipFileName,MenuInfo.Title);
  End
  Else If (M.ProfileRec = Nil) And (MenuInfo.ProfileRec <> Nil) Then
   LoadGame(MenuInfo.FileName,MenuInfo.ZipFileName,MenuInfo.Title);
  T.Free;
end;

procedure TfrmMain.acUseDebuggerExecute(Sender: TObject);
begin
  Debugger := acUseDebugger.Checked;
  If Debugger And Not frmDebugger.Visible Then frmDebugger.Show;
  If Not Debugger Then ShowCrosshair := False;
end;

procedure TfrmMain.acRebuildGameProfileExecute(Sender: TObject);
begin
  MakeProfile(ExtractFilePath(Application.ExeName));
end;

procedure TfrmMain.acDisassembleExecute(Sender: TObject);
Var F,E: String;
begin
  dlgSave.Filter     := 'Assembler files (*.asm)|*.ASM';
  dlgSave.DefaultExt := 'ASM';
  F := ExtractFileName(ROMFileName);
  E := ExtractFileExt(ROMFileName);
  F := Copy(F,1,Length(F) - Length(E));
  dlgSave.FileName := F + '.' + 'ASM';
  If dlgSave.Execute Then
  Begin
    ListingFileName := dlgSave.FileName;
    Disassemble(Game.Bankswitch,Game.Cart,Game.ROMSize);
  End;
end;

procedure TfrmMain.acSaveScreenshotExecute(Sender: TObject);
Var
  BMP  : TBitmap;
  X,Y  : Integer;
  Addr : Integer;
  C    : TColor;
  B    : Byte;
  F,E  : String;
  S    : TFileStream;
  Img  : TJPEGImage;

begin
  dlgSave.DefaultExt := 'JPG';
  dlgSave.Filter     := 'Image files|*.JPG;*.BMP';
  dlgSave.InitialDir := Config.ScreenShotPath;
  F := ExtractFileName(ROMFileName);
  E := ExtractFileExt(ROMFileName);
  F := Copy(F,1,Length(F) - Length(E));
  dlgSave.FileName := F + '.' + 'JPG';
  If dlgSave.Execute Then
  Begin
    BMP             := TBitmap.Create;
    BMP.Width       := Config.MaxCols;
    BMP.Height      := Config.MaxRows;
    BMP.PixelFormat := pf24Bit;
    Addr            := (Config.MaxRows - 1) * 160;
    C               := 0;
    For Y := 0 To Config.MaxRows - 1 Do
    Begin
      For X := 0 To 159 Do
      Begin
        B := ScnBuf[Addr] Shr 1;
        If Game.Palette <> 0 Then Inc(B,128);
        TRGBQUAD(C).rgbBlue  := Pal[B].R;   // Don't ask me why, but these have to be reversed
        TRGBQUAD(C).rgbGreen := Pal[B].G;
        TRGBQUAD(C).rgbRed   := Pal[B].B;
        BMP.Canvas.Pixels[X * 2,Y]     := C;
        BMP.Canvas.Pixels[X * 2 + 1,Y] := C;
        Inc(Addr);
      End; // For X
      Dec(Addr,320);
    End; // For Y
    If Copy(dlgSave.FileName,Length(dlgSave.FileName) - 3,4) = '.JPG' Then
    Begin
      Img := TJPEGImage.Create;
      Img.Assign(BMP);
      S := TFileStream.Create(dlgSave.FileName,fmCreate);
      Img.SaveToStream(S);
      S.Free;
      Img.Free;
    End
    Else BMP.SaveToFile(dlgSave.FileName);
    BMP.Free;
  End;
end;

procedure TfrmMain.acLoadSavedGameExecute(Sender: TObject);
begin
  RestoreStatus;
end;

procedure TfrmMain.acSaveGameExecute(Sender: TObject);
begin
  SaveStatus;
end;

procedure TfrmMain.acExitExecute(Sender: TObject);
begin
  Close;
end;

procedure TfrmMain.acStartEmulationExecute(Sender: TObject);
begin
  If Debugger Then frmDebugger.btnGoClick(Self) Else Emulate;
end;

procedure TfrmMain.acStopEmulationExecute(Sender: TObject);
begin
  Exiting := True;
end;

procedure TfrmMain.acResetEmulationExecute(Sender: TObject);
Var Running: Boolean;
begin
  Running := (Emulating > 0);
  If Running Then
  Begin
    acStopEmulation.Execute;
    Application.ProcessMessages;
  End;
  LoadGame(MenuInfo.FileName,MenuInfo.ZipFileName,MenuInfo.Title);
  If Running Then acStartEmulation.Execute;
end;

procedure TfrmMain.acControllerJoystickExecute(Sender: TObject);
begin
  Game.Controller := crJoystick;
end;

procedure TfrmMain.acControllerPaddleExecute(Sender: TObject);
begin
  Game.Controller := crPaddle;
end;

procedure TfrmMain.acControllerKeyboardExecute(Sender: TObject);
begin
  Game.Controller := crKeyboard;
end;

procedure TfrmMain.acControllerIndy500Execute(Sender: TObject);
begin
  Game.Controller := crDriving;
end;

procedure TfrmMain.acControllerVTPExecute(Sender: TObject);
begin
  Game.Controller := crVTP;
end;

procedure TfrmMain.acControllerBoosterGripExecute(Sender: TObject);
begin
  Game.Controller := crBooster;
end;

procedure TfrmMain.acConfigureInterfacesExecute(Sender: TObject);
begin
  InterfaceHandler.DeactivateInterfaces;
  frmConfigure.ShowModal;
  frmMenu.SaveConfiguration(Config,HandTIA.Version);
  InterfaceHandler.ActivateInterfaces;
end;

procedure TfrmMain.acEnableMouseExecute(Sender: TObject);
Var Intf: TInterface;
begin
  If InterfaceHandler.Stack.Count > 0 Then
  Begin
    InterfaceHandler.DeactivateInterfaces;
    Intf                  := TInterface(InterfaceHandler.Stack.Objects[0]);
    Intf.Enabled          := Not Intf.Enabled;
    acEnableMouse.Checked := Intf.Enabled;
    InterfaceHandler.ActivateInterfaces;
    frmMenu.SaveConfiguration(Config,HandTIA.Version);
  End;
end;

procedure TfrmMain.acEnableKeyboardExecute(Sender: TObject);
Var Intf: TInterface;
begin
  If InterfaceHandler.Stack.Count > 1 Then
  Begin
    InterfaceHandler.DeactivateInterfaces;
    Intf                     := TInterface(InterfaceHandler.Stack.Objects[1]);
    Intf.Enabled             := Not Intf.Enabled;
    acEnableKeyboard.Checked := Intf.Enabled;
    InterfaceHandler.ActivateInterfaces;
    frmMenu.SaveConfiguration(Config,HandTIA.Version);
  End;
end;

procedure TfrmMain.acEnableControllerExecute(Sender: TObject);
Var Intf: TInterface;
begin
  If InterfaceHandler.Stack.Count > 2 Then
  Begin
    InterfaceHandler.DeactivateInterfaces;
    Intf                       := TInterface(InterfaceHandler.Stack.Objects[2]);
    Intf.Enabled               := Not Intf.Enabled;
    acEnableController.Checked := Intf.Enabled;
    InterfaceHandler.ActivateInterfaces;
    frmMenu.SaveConfiguration(Config,HandTIA.Version);
  End;
end;

procedure TfrmMain.acVideoFullScreenExecute(Sender: TObject);
begin
  If UseDirectDraw Then DDFullScreen := acVideoFullScreen.Checked;
  acVideoTVScreen.Enabled := DDFullScreen;
  frmMenu.SaveConfiguration(Config,HandTIA.Version);
end;

procedure TfrmMain.acVideoTVScreenExecute(Sender: TObject);
begin
  LastFSWidth  := 0;
  LastFSHeight := 0;
  If UseDirectDraw Then TVScreen := acVideoTVScreen.Checked;
  frmMenu.SaveConfiguration(Config,HandTIA.Version);
end;

procedure TfrmMain.acVideo320x200Execute(Sender: TObject);
begin
  Config.MaxCols         := 320;
  Config.MaxRows         := 200;
  Config.GameResolution  := gr160x200A;
  frmMenu.SaveConfiguration(Config,HandTIA.Version);
  SetImageSizes(False);
end;

procedure TfrmMain.acVideo320x204Execute(Sender: TObject);
begin
  Config.MaxCols         := 320;
  Config.MaxRows         := 204;
  Config.GameResolution  := gr160x204A;
  frmMenu.SaveConfiguration(Config,HandTIA.Version);
  SetImageSizes(False);
end;

procedure TfrmMain.acVideo320x215Execute(Sender: TObject);
begin
  Config.MaxCols         := 320;
  Config.MaxRows         := 215;
  Config.GameResolution  := gr160x215A;
  frmMenu.SaveConfiguration(Config,HandTIA.Version);
  SetImageSizes(False);
end;

procedure TfrmMain.acVideo320x250Execute(Sender: TObject);
begin
  Config.MaxCols         := 320;
  Config.MaxRows         := 250;
  Config.GameResolution  := gr160x250A;
  frmMenu.SaveConfiguration(Config,HandTIA.Version);
  SetImageSizes(False);
end;

procedure TfrmMain.acVideo320x305Execute(Sender: TObject);
begin
  Config.MaxCols         := 320;
  Config.MaxRows         := 305;
  Config.GameResolution  := gr160x305A;
  frmMenu.SaveConfiguration(Config,HandTIA.Version);
  SetImageSizes(False);
end;

procedure TfrmMain.acVideoZoom1xExecute(Sender: TObject);
begin
  Config.ZoomMode := 1;
  Zoom            := 1;
  SetImageSizes(False);
end;

procedure TfrmMain.acVideoZoom2xExecute(Sender: TObject);
begin
  Config.ZoomMode := 2;
  Zoom            := 2;
  SetImageSizes(False);
end;

procedure TfrmMain.acVideoZoom4xExecute(Sender: TObject);
begin
  Config.ZoomMode := 4;
  Zoom            := 4;
  SetImageSizes(False);
end;

procedure TfrmMain.acVideoZoom3xExecute(Sender: TObject);
begin
  Config.ZoomMode := 3;
  Zoom            := 3;
  SetImageSizes(False);
end;

procedure TfrmMain.acVideoZoomFullExecute(Sender: TObject);
begin
  Config.ZoomMode := 0;
  Zoom            := 0;
  SetImageSizes(False);
end;

procedure TfrmMain.acVideoRecordToAVIExecute(Sender: TObject);
Var
  F  : File;
  St : String;

begin
  If Not AVIFile.Opened Then
  Begin
    dlgSave.Filter := 'AVI video files (*.avi)|*.AVI';
    If dlgSave.Execute Then
    Begin
      St := dlgSave.FileName;
      If St <> '' Then
      Begin
        If CreateFile(F,St) Then
        Begin
          CloseFile(F);
          acVideoRecordToAVI.ImageIndex := 9;
          AVIFile.Open(St,Config.MaxCols Div 2,Game.MaxRows,acRLE,exHorz2x,Pal);
          acVideoRecordToAVI.Checked    := True;
        End;
      End;
    End;
  End
  Else
  Begin
    AVIFile.Close;
    acVideoRecordToAVI.ImageIndex := 8;
    acVideoRecordToAVI.Checked    := False;
  End;
end;

procedure TfrmMain.acHelpAboutExecute(Sender: TObject);
begin
  frmAbout.ShowModal;
end;

procedure TfrmMain.acNetPlayExecute(Sender: TObject);
begin
  If Emulating > 0 Then
  Begin
    acStopEmulation.Execute;
    Application.ProcessMessages;
    acResetEmulation.Execute;
    Application.ProcessMessages;
  End;
  frmKaillera.Show;
  KailleraSelectServerDialog(Handle);
  frmKaillera.Hide;
end;

procedure TfrmMain.acShowManualExecute(Sender: TObject);
Var
  MP   : String;
  St   : String;

  Procedure OpenManual(FileName: String; RTF: Boolean);
  Var Flags: OLEVariant;
  Begin
    Try
      Flags := 0;
      frmManual.wbManual.Navigate('file://' + FileName, Flags, Flags, Flags, Flags);
      frmManual.ShowModal;
    Except
      ShowMessage('There was a problem opening the manual.'#13#10 +
                  'Make sure you have Internet Explorer available'#13#10 +
                  'and that it has the necessary plugins.');
    End;
  End; // OpenManual

begin
  If MenuInfo.FileName <> '' Then
  Begin
    St := RemoveFileExt(ExtractFileName(MenuInfo.FileName));
    MP := Config.ManualPath;
    If (MP <> '') And Not (MP[Length(MP)] In [':','\']) Then MP := MP + '\';

         If FileExists(MP + St + '.TXT')  Then OpenManual(MP + St + '.TXT',False)
    Else If FileExists(MP + St + '.RTF')  Then OpenManual(MP + St + '.RTF',True)
    Else If FileExists(MP + St + '.PDF')  Then OpenManual(MP + St + '.PDF',True)
    Else If FileExists(MP + St + '.HTM')  Then OpenManual(MP + St + '.HTM',True)
    Else If FileExists(MP + St + '.HTML') Then OpenManual(MP + St + '.HTML',True);
    ResetClock;
  End;
end;

procedure TfrmMain.acDifficulty1Execute(Sender: TObject);
begin
  Game.Difficulty1 := Game.Difficulty1 Xor $40;
  Difficulty1Change := False;
  If Game.Difficulty1 = 0
   Then acDifficulty1.ImageIndex := 5
   Else acDifficulty1.ImageIndex := 4;
end;

procedure TfrmMain.acDifficulty2Execute(Sender: TObject);
begin
  Game.Difficulty2 := Game.Difficulty2 Xor $80;
  Difficulty2Change := False;
  If Game.Difficulty2 = 0
   Then acDifficulty2.ImageIndex := 5
   Else acDifficulty2.ImageIndex := 4;
end;

procedure TfrmMain.acSelectExecute(Sender: TObject);
begin
  AtariSeg[SWCHB1] := (1{SwReset} Or
//                       SwSelect Or
                       Game.ColorOrBW Or
                       Game.Difficulty1 Or
                       Game.Difficulty2) And $CF;
  AtariSeg[SWCHB2] := AtariSeg[SWCHB1];
  SelectChange := False;
end;

procedure TfrmMain.acResetExecute(Sender: TObject);
begin
  AtariSeg[SWCHB1] := (//SwReset Or
                       2{SwSelect} Or
                       Game.ColorOrBW Or
                       Game.Difficulty1 Or
                       Game.Difficulty2) And $CF;
  AtariSeg[SWCHB2] := AtariSeg[SWCHB1];
  ResetChange := False;
end;

procedure TfrmMain.acColorBWExecute(Sender: TObject);
begin
  Game.ColorOrBW := Game.ColorOrBW Xor 8;
  ColorOrBWChange := False;
  If Game.ColorOrBW <> 0
   Then acColorBW.ImageIndex := 2
   Else acColorBW.ImageIndex := 3;
end;

procedure TfrmMain.acNTSCPalExecute(Sender: TObject);
begin
  Game.Palette := Game.Palette Xor 1;
  PaletteChange := False;
  If Game.Palette = 0
   Then acNTSCPAL.ImageIndex := 4
   Else acNTSCPAL.ImageIndex := 5;
  NewPalette;
end;

procedure TfrmMain.TBDock2Resize(Sender: TObject);
begin
  SetImageSizes(False);
end;

procedure TfrmMain.TBDock1Resize(Sender: TObject);
begin
  SetImageSizes(False);
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
Var INI: TINIFile;
begin
  TBIniSavePositions(Self, ExtractFilePath(Application.EXEName) + 'pcaewin.ini', 'Toolbars');
  INI := TIniFile.Create(ExtractFilePath(Application.EXEName) + 'pcaewin.ini');
  Try
    MRUList.SaveToIni(INI, 'RecentFiles');
  Finally
    INI.Free;
  End;
end;

procedure TfrmMain.MRUListClick(Sender: TObject; const Filename: String);
begin
  LoadGameFromAnywhere(ExtractFileName(FileName));
end;

Initialization
  ilInit;
  AVIFile.Init;
  Emulating := 0;
  If FileExists(ExtractFilePath(Application.ExeName) + 'PCAEWIN.LOG') Then
   DeleteFile(ExtractFilePath(Application.ExeName) + 'PCAEWIN.LOG');
  Handle_IO_Latch_Ptr := @Handle_IO_Latch;
  FillChar(ExtraAdd,SizeOf(ExtraAdd),#0);
  For I := -53 To 7 Do ExtraAdd[I] := (I + 53) Shr 2;

  // Set up the masks

  Asm
//    CLI
    SUB   EDX,EDX
@L1:
    MOV   EAX,EDX
    MOV   ECX,EDX
    RCR   AL,1
    RCL   AH,1
    RCR   AL,1
    RCL   AH,1
    RCR   AL,1
    RCL   AH,1
    RCR   AL,1
    RCL   AH,1
    RCR   AL,1
    RCL   AH,1
    RCR   AL,1
    RCL   AH,1
    RCR   AL,1
    RCL   AH,1
    RCR   AL,1
    RCL   AH,1
    MOV   BYTE PTR BitSwap[ECX],AH
    INC   EDX
    CMP   EDX,256
    JL    @L1
//    STI
  End; { Asm }
  For I := 0 To 228 Do Div3[I] := I Div 3;
  FileMode := 0;
  InitGameType;
end.

// ----------------------------------------------------------------------
// PCAE and PCAEWin - PC Atari Emulator - Atari 2600 emulator
// Copyright (C) 2000 John Dullea
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ----------------------------------------------------------------------
