unit frmDebuggerunt;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Profile, AtariDis, SPUnit,
  ExtCtrls, StdCtrls, Buttons;

Const
  LatchQueueSize    = 16;
  GameScreenSize    = 160 * 200;
  Index_Player0Set  = 1;
  Index_Player1Set  = 2;
  Index_Missile0Set = 4;
  Index_Missile1Set = 8;
  Index_BallSet     = 16;

type
  TIA_RegList = Packed Array[0..$3F] Of Byte;
  TGameRes    = (gr320x200,gr320x204,
                 gr160x200A,gr160x204A,gr160x215A,gr160x250A,gr160x305A,
                 gr160x200B,gr160x204B,gr160x215B,gr160x250B,gr160x305B);
  TSave = Packed Record
    TIA_Regs                       : TIA_RegList;
    TIA_Count                      : SmallInt;
    Old_TIA_Count                  : SmallInt;
    TIA_Scan                       : SmallInt;
    ObjectLoc                      : Packed Array[0..16] Of LongInt;
    ObjectPix                      : Packed Array[0..16] Of LongInt;
    Player0Size                    : LongInt;
    Player1Size                    : LongInt;
    Player0Size160                 : LongInt;
    Player1Size160                 : LongInt;
    Player0Size128                 : LongInt;
    Player1Size128                 : LongInt;
    Missile0Size                   : LongInt;
    Missile1Size                   : LongInt;
    Missile0Size160                : LongInt;
    Missile1Size160                : LongInt;
    Missile0SizeNum                : LongInt;
    Missile1SizeNum                : LongInt;
    Addr                           : LongInt;
    ColorLum                       : Packed Array[0..3] Of Word;
    BallSize                       : LongInt;
    BallSize160                    : LongInt;
    CLW                            : LongInt;
    CRW                            : LongInt;
    Input_Byte                     : Packed Array[0..$F] Of Byte;
    DispJump                       : LongInt;
    DoHMOVE                        : Boolean;
    LineStart                      : SmallInt;
    LastScan                       : LongInt;
    NewScan                        : LongInt;
    TopVBLANK                      : Boolean;
    TIA_Latch_Value                : Packed Array[0..LatchQueueSize - 1] Of SmallInt;
    TIA_Latch_Reg                  : Packed Array[0..LatchQueueSize - 1] Of Byte;
    TIA_Latch_Count                : Packed Array[0..LatchQueueSize - 1] Of SmallInt;
    TIA_Latch_Scan                 : Packed Array[0..LatchQueueSize - 1] Of SmallInt;
    TIA_Latch_Queue                : SmallInt;
    TIA_Latch_RegCount             : Packed Array[0..$2C] Of SmallInt;
    MaxRows                        : Word;
    Missile0Wrap                   : LongInt;
    Missile1Wrap                   : LongInt;

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

    _Player0Size                   : LongInt;
    _Player1Size                   : LongInt;
    ResetPlayer0Size128            : LongInt;
    ResetPlayer1Size128            : LongInt;
    OldMissile0SizeNum             : LongInt;
    OldMissile1SizeNum             : LongInt;
    OldPlayer0Size128              : LongInt;
    OldPlayer1Size128              : LongInt;
    Missile0Adjust                 : LongInt;
    Missile1Adjust                 : LongInt;
    AddCycle                       : LongInt;
    TimerInterval                  : LongInt;
    TimerValue                     : LongInt;
    TimerShift                     : LongInt;
    TimerX                         : LongInt;
    OrigTimer                      : LongInt;
    TimerElapsed                   : LongInt;
    ReadTime                       : LongInt;
    Write_TIA                      : LongInt;
    ObjectSet                      : LongInt;
    Save_BX                        : LongInt;
    ColorOrBW                      : LongInt;
    Difficulty1                    : LongInt;
    Difficulty2                    : LongInt;
    PaddleGround0                  : LongInt;
    PaddleGround1                  : LongInt;
    PaddleGround2                  : LongInt;
    PaddleGround3                  : LongInt;
    OldPaddleGround0               : LongInt;
    OldPaddleGround1               : LongInt;
    OldPaddleGround2               : LongInt;
    OldPaddleGround3               : LongInt;
    KeyColumn                      : LongInt;
    Indy500                        : Packed Array[0..1] Of Word;
    OldObjectLoc                   : Packed Array[0..16] Of LongInt;
    NewObjectLoc                   : Packed Array[0..16] Of LongInt;
    MegaBoy                        : Packed Array[0..15] Of Byte;
    ROMSize                        : LongInt;
    TimerDone                      : Boolean;
    GRP0Latch                      : Byte;
    GRP1Latch                      : Byte;
    MegaBoyNum                     : Word;
    OldNUSIZ0                      : Byte;
    OldNUSIZ1                      : Byte;
    OldHMxx                        : Packed Array[0..4] Of Byte;
    ResetOffset                    : Packed Array[0..4] Of LongInt;
    ResetOfs                       : Word;
    LastVBLANK                     : SmallInt;
    BallLatch                      : Byte;
    TIA_Latch_ResetPlayer0Size128  : LongInt;
    TIA_Latch_ResetPlayer1Size128  : LongInt;
    TIA_Latch_Missile0SizeNum      : LongInt;
    TIA_Latch_Missile1SizeNum      : LongInt;
    Latched                        : Boolean;
    M0Bug                          : Boolean;
    M0BugCount                     : Byte;
    FixTimer                       : Byte;
    FixTimerNum                    : Byte;
    VBLANKOff                      : Boolean;
    Palette                        : Byte;
    Controller                     : TController;
    FMRealScale                    : Packed Array[0..8] Of Word;
    FMVoc                          : Packed Array[0..8] Of Byte;
    FMFreq                         : Packed Array[0..8] Of Word;
    BankSwitch                     : TBankSwitch;
    VAddAdjust                     : SmallInt;
    VAdd                           : SmallInt;
    VUserAdd                       : SmallInt;
    CurrentBank                    : Byte;
    BankStart                      : Word;
    BankSize                       : Word;
    OldStart                       : Word;
    _CTRLPF                        : Byte;
    OldByte                        : Byte;
    SPBankNum                      : Byte;
    StarpathWriteValue             : Byte;
    StarpathWrite                  : Boolean;
    OldDoHMOVE                     : Boolean;
    HMOVECount                     : LongInt;
    Cart                           : TCart;
    TigerLimit                     : Byte;
    SCLimit                        : Byte;
    MNetworkRAM                    : Byte;
    StarpathLastAddr               : Word;
    Hi3                            : Word;
    _6507_P                        : Byte;
    _6507_A                        : Byte;
    _6507_X                        : Byte;
    _6507_Y                        : Byte;
    _6507_S                        : Byte;
    _6507_PC                       : Word;
    UserSetPos                     : SmallInt;
    ObjectMove                     : Packed Array[0..16] Of LongInt;
    MissedHMOVE                    : Packed Array[0..32] Of Boolean;

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

    SPBank   : Byte;
    SPSearch : Word;
    SPBoot   : Boolean;

    WaveLen : Packed Array[1..4] Of Byte; { The fourth byte is unused in these arrays }
    Pulse   : Packed Array[1..4] Of Byte;
    Phase   : Packed Array[1..4] Of Byte;
    Signal  : Packed Array[1..4] Of Byte;
    Wave    : Packed Array[1..4] Of Byte;

    LineDelay      : Word;
    LineDelayFirst : Boolean;
    LineDelayMax   : Word;
  End;
  TfrmDebugger = class(TForm)
    dlgSave: TSaveDialog;
    pnlButtons: TPanel;
    bvlInstructions: TBevel;
    bvlFlags: TBevel;
    bvlRegs: TBevel;
    bvlScreenData: TBevel;
    bvlTIARegs: TBevel;
    bvlInputRegs: TBevel;
    bvlObjectLoc: TBevel;
    bvlData: TBevel;
    btnGo: TBitBtn;
    btnTrace: TBitBtn;
    btnSkip: TBitBtn;
    btnReg: TBitBtn;
    btnMem: TBitBtn;
    btnExpression: TBitBtn;
    btnHere: TBitBtn;
    btnLine: TBitBtn;
    btnSave: TBitBtn;
    btnBeam: TBitBtn;
    btnStop: TBitBtn;
    sbInstructions: TScrollBar;
    btnPC: TSpeedButton;
    btnTop: TSpeedButton;
    btnTIARef: TBitBtn;
    btnExpRef: TBitBtn;
    procedure FormPaint(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormResize(Sender: TObject);
    procedure btnTraceClick(Sender: TObject);
    procedure btnGoClick(Sender: TObject);
    procedure btnSkipClick(Sender: TObject);
    procedure btnHereClick(Sender: TObject);
    procedure btnLineClick(Sender: TObject);
    procedure btnMemClick(Sender: TObject);
    procedure btnSaveClick(Sender: TObject);
    procedure btnBeamClick(Sender: TObject);
    procedure btnStopClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure sbInstructionsScroll(Sender: TObject;
      ScrollCode: TScrollCode; var ScrollPos: Integer);
    procedure btnPCClick(Sender: TObject);
    procedure btnTopClick(Sender: TObject);
    procedure btnRegClick(Sender: TObject);
    procedure btnTIARefClick(Sender: TObject);
    procedure btnExpRefClick(Sender: TObject);
    procedure btnExpressionClick(Sender: TObject);
  private
    { Private declarations }
    DataTop  : Word;
    Opcode   : Byte;
    Addr     : Word;
    OTyp     : String[3];
    Operand  : String;
    Color    : Word;
    TopAddr  : Word;
//    Ch       : Char;
    _DLines  : Word;
    St       : String;
//    HaltNum  : Integer;
//    Code     : Integer;
//    HexVal   : LongInt;
//    HexAddr  : LongInt;
    OutFile  : File;
//    ExpError : Boolean;
    ShowBeam : Boolean;
    Procedure FBox(X1,Y1,X2,Y2: Integer; Col: Byte);
    Procedure Display;
{    Procedure WriteOut(X,Y: Integer; St: String; Col: Word);}
    Procedure WriteOut(B: TBevel; X,Y: Integer; St: String; Col: Word);
    Procedure WriteOutBold(B: TBevel; X,Y: Integer; St: String; Col: Word);
    Procedure FillInBevel(B: TBevel; Col: Byte);
{    Procedure WriteSmOut(X,Y: Integer; St: String; Col: Word);}
    Function  TransWordWrite(Addr: Word): String;
    Function  TransWordRead(Addr: Word): String;
    Function  TransByteRead(Addr: Word): String;
    Function  TransByteWrite(Addr: Word): String;
    Function  TransWord(Addr: Word): String;
    Function  TransByte(Addr: Word): String;
    Function  BufW(Addr: Word): Word;
  public
    { Public declarations }
    Procedure InitDebugger;
  end;

var
  frmDebugger   : TfrmDebugger;
  ScreenPalette : Array[0..255] Of TColor;

implementation

{$R *.DFM}

Uses HexWrite,HandTIA,frmMainUnt,Equation,frmTIARefUnt,frmExpRefUnt;

Const
  NormTextColor = 0;
  HiTextColor   = 30;
  PCTextColor   = 246;
  HelpTextColor = 10;
  HelpHiColor   = 28;
  LineColor     = 14;
  BackColor     = 4;
  DisasmColor   = 174;
  TopAsmColor   = 200;  // 190;
  FlagsColor    = 250;{254;}
  RegsColor     = 108;{110;}
  DataColor     = 158;
  ScrDatColor   = 90;
  TIA_Color     = 152;
  Input_Color   = 154;
  ObjLoc_Color  = 156;
  TextBGColor   = 148;
  PopupColor    = 10;
  HelpColor     = 132;

  TextStart     = 2;
  TextHeight    = 8;
  DisasmLines   = 16;
//  HRDisasmLines = 32;
  DataLines     = 8;
  SmFontSize    = 1024;

Var
  BreakExp    : String;

Procedure TfrmDebugger.FBox(X1,Y1,X2,Y2: Integer; Col: Byte);
Begin
  Canvas.Pen.Color   := ScreenPalette[Col];
  Canvas.Brush.Color := ScreenPalette[Col];
  Canvas.Brush.Style := bsSolid;
  Canvas.Rectangle(X1,Y1,X2 + 1,Y2 + 1);
End; { TfrmDebugger.FBox }


Procedure TfrmDebugger.WriteOut(B: TBevel; X,Y: Integer; St: String; Col: Word);
Begin
  X := (X - 1) * Canvas.TextWidth('M')   + B.Left + 1;
  Y := (Y - 1) * Canvas.TextHeight('Mg') + B.Top  + 1;
  Canvas.Font.Color  := ScreenPalette[Lo(Col)];
  Canvas.Brush.Color := ScreenPalette[Hi(Col)];
  Canvas.TextOut(X,Y,St);
End; // TfrmDebugger.WriteOut


Procedure TfrmDebugger.WriteOutBold(B: TBevel; X,Y: Integer; St: String; Col: Word);
Begin
  X := (X - 1) * Canvas.TextWidth('M')   + B.Left + 1;
  Y := (Y - 1) * Canvas.TextHeight('Mg') + B.Top  + 1;
  Canvas.Font.Style := [fsBold];
  Canvas.Font.Color  := ScreenPalette[Lo(Col)];
  Canvas.Brush.Color := ScreenPalette[Hi(Col)];
  Canvas.TextOut(X,Y,St);
  Canvas.Font.Style := [];
End; // TfrmDebugger.WriteOutBold


Procedure TfrmDebugger.FillInBevel(B: TBevel; Col: Byte);
Begin
  FBox(B.Left + 1,B.Top + 1,B.Left + B.Width - 2,B.Top + B.Height - 2,Col);
End; // TfrmDebugger.FillInBevel

(*
Procedure TfrmDebugger.WriteOut(X,Y: Integer; St: String; Col: Word);
Begin
  X := Round(X * Canvas.TextWidth('M') / 8);
  Y := Round(Y * Canvas.TextHeight('Mg') / 8);
  Canvas.Font.Color  := ScreenPalette[Lo(Col)];
  Canvas.Brush.Color := ScreenPalette[Hi(Col)];
  Canvas.TextOut(X,Y,St);
End; // TfrmDebugger.WriteOut

Procedure TfrmDebugger.WriteSmOut(X,Y: Integer; St: String; Col: Word);
Begin
  WriteOut(X,Y,St,Col);
End; // TfrmDebugger.WriteSmOut
*)
Procedure TfrmDebugger.Display;
Var I,J: Integer;

  Procedure ShowBasicInfo;
  Var I: Integer;
  Begin
    WriteOut(bvlFlags,1,1,'NV BDIZC',NormTextColor + (FlagsColor Shl 8));

    WriteOut(bvlRegs,1,1,'PC=    h',NormTextColor + (RegsColor Shl 8));
    WriteOut(bvlRegs,2,2,'P=  h  ',NormTextColor + (RegsColor Shl 8));
    WriteOut(bvlRegs,2,3,'A=  h  ',NormTextColor + (RegsColor Shl 8));
    WriteOut(bvlRegs,2,4,'X=  h  ',NormTextColor + (RegsColor Shl 8));
    WriteOut(bvlRegs,2,5,'Y=  h  ',NormTextColor + (RegsColor Shl 8));
    WriteOut(bvlRegs,2,6,'S=  h  ',NormTextColor + (RegsColor Shl 8));

    WriteOut(bvlScreenData,1,1,'Scan=',NormTextColor + (ScrDatColor Shl 8));
    WriteOut(bvlScreenData,1,2,'HPix=',NormTextColor + (ScrDatColor Shl 8));
    WriteOut(bvlScreenData,1,3,'Bank=',NormTextColor + (ScrDatColor Shl 8));
    WriteOut(bvlScreenData,1,4,'Addr=    h',NormTextColor + (ScrDatColor Shl 8));
    WriteOut(bvlScreenData,1,5,'GRP0=  h',NormTextColor + (ScrDatColor Shl 8));
    WriteOut(bvlScreenData,1,6,'GRP1=  h',NormTextColor + (ScrDatColor Shl 8));

    { Display flag data }

    For I := 0 To 7 Do
    Begin
      If (Game._6507_P And (1 Shl I)) <> 0
       Then WriteOutBold(bvlFlags,8 - I,2,'1',HiTextColor + (FlagsColor Shl 8))
       Else WriteOutBold(bvlFlags,8 - I,2,'0',HiTextColor + (FlagsColor Shl 8));
    End; { For I }

    { Display reg data }

    WriteOutBold(bvlRegs,4,1,HexWord(Game._6507_PC),HiTextColor + (RegsColor Shl 8));
    WriteOutBold(bvlRegs,4,2,HexByte(Game._6507_P) ,HiTextColor + (RegsColor Shl 8));
    WriteOutBold(bvlRegs,4,3,HexByte(Game._6507_A) ,HiTextColor + (RegsColor Shl 8));
    WriteOutBold(bvlRegs,4,4,HexByte(Game._6507_X) ,HiTextColor + (RegsColor Shl 8));
    WriteOutBold(bvlRegs,4,5,HexByte(Game._6507_Y) ,HiTextColor + (RegsColor Shl 8));
    WriteOutBold(bvlRegs,4,6,HexByte(Game._6507_S) ,HiTextColor + (RegsColor Shl 8));

    { Display screen info data }

    WriteOutBold(bvlScreenData,6,1,IntToStr(Game.TIA_Scan)  ,HiTextColor + (ScrDatColor Shl 8));
    WriteOutBold(bvlScreenData,6,2,IntToStr(Game.TIA_Count) ,HiTextColor + (ScrDatColor Shl 8));
    WriteOutBold(bvlScreenData,6,3,IntToStr(Game.CurrentBank)  ,HiTextColor + (ScrDatColor Shl 8));
    WriteOutBold(bvlScreenData,6,4,HexWord(Game.Addr),HiTextColor + (ScrDatColor Shl 8));
    WriteOutBold(bvlScreenData,6,5,HexByte(Game.TIA_Regs[GRP0]),HiTextColor + (ScrDatColor Shl 8));
    WriteOutBold(bvlScreenData,6,6,HexByte(Game.TIA_Regs[GRP1]),HiTextColor + (ScrDatColor Shl 8));

    WriteOutBold(bvlTIARegs,1,1,'TIA register contents',NormTextColor + (TIA_Color Shl 8));
    WriteOutBold(bvlInputRegs,1,1,'Input register contents',NormTextColor + (Input_Color Shl 8));
    WriteOutBold(bvlObjectLoc,1,1,'Horizontal object positions',NormTextColor + (ObjLoc_Color Shl 8));
    WriteOutBold(bvlData,1,1,'2600 RAM area',NormTextColor + (DataColor Shl 8));
  End; // ShowBasicInfo

Begin
  FillInBevel(bvlInstructions,DisasmColor);
  FillInBevel(bvlFlags,FlagsColor);
  FillInBevel(bvlRegs,RegsColor);
  FillInBevel(bvlScreenData,ScrDatColor);
  FillInBevel(bvlTIARegs,TIA_Color);
  FillInBevel(bvlInputRegs,Input_Color);
  FillInBevel(bvlObjectLoc,ObjLoc_Color);
  FillInBevel(bvlData,DataColor);
  
  ShowBasicInfo;

//  WriteOut(254,127,'F1-Help',FlagsColor + (BackColor Shl 8));

  { Display TIA registers }

  For I := 0 To $2C Do
  Begin
    If (I And $F) = 0 Then
     WriteOutBold(bvlTIARegs,1,2 + (I Shr 4),HexWord(I),NormTextColor + (TIA_Color Shl 8));
    WriteOut(bvlTIARegs,6 + (I And $F) * 3,2 + (I Shr 4),
     HexByte(Game.TIA_Regs[I]),NormTextColor + (TIA_Color Shl 8));
    If (I And $F) = 7 Then
     WriteOut(bvlTIARegs,8 + (I And $F) * 3,2 + (I Shr 4),'-',NormTextColor + (TIA_Color Shl 8));
  End; { For I }

  { Display input registers }

  For I := 0 To $F Do
  Begin
    If (I And $F) = 0 Then
     WriteOutBold(bvlInputRegs,1,2 + (I Shr 4),HexWord(I),NormTextColor + (Input_Color Shl 8));
    WriteOut(bvlInputRegs,6 + (I And $F) * 3,2 + (I Shr 4),
     HexByte(Game.Input_Byte[I]),NormTextColor + (Input_Color Shl 8));
    If (I And $F) = 7 Then
     WriteOut(bvlInputRegs,8 + (I And $F) * 3,2 + (I Shr 4),'-',NormTextColor + (Input_Color Shl 8));
  End; { For I }

  { Display object locations }

  If AtariSeg[GRP0] <> 0 Then
  Begin
    WriteOut(bvlObjectLoc,1,2,'P0',NormTextColor + (ObjLoc_Color Shl 8));
    WriteOutBold(bvlObjectLoc,4,2,IntToStr(Game.ObjectLoc[Index_Player0Set] And $FFFF),
     ScrDatColor + (ObjLoc_Color Shl 8));
  End
  Else
  Begin
    WriteOut(bvlObjectLoc,1,2,'P0',NormTextColor + (ObjLoc_Color Shl 8));
    WriteOutBold(bvlObjectLoc,4,2,IntToStr(Game.ObjectLoc[Index_Player0Set] And $FFFF),
     NormTextColor + (ObjLoc_Color Shl 8));
  End;

  If AtariSeg[GRP1] <> 0 Then
  Begin
    WriteOut(bvlObjectLoc,12,2,'P1',NormTextColor + (ObjLoc_Color Shl 8));
    WriteOutBold(bvlObjectLoc,15,2,IntToStr(Game.ObjectLoc[Index_Player1Set] And $FFFF),
     ScrDatColor + (ObjLoc_Color Shl 8));
  End
  Else
  Begin
    WriteOut(bvlObjectLoc,12,2,'P1',NormTextColor + (ObjLoc_Color Shl 8));
    WriteOutBold(bvlObjectLoc,15,2,IntToStr(Game.ObjectLoc[Index_Player1Set] And $FFFF),
     NormTextColor + (ObjLoc_Color Shl 8));
  End;

  If (AtariSeg[ENAM0] And 2) <> 0 Then
  Begin
    WriteOut(bvlObjectLoc,23,2,'M0',NormTextColor + (ObjLoc_Color Shl 8));
    WriteOutBold(bvlObjectLoc,26,2,IntToStr(Game.ObjectLoc[Index_Missile0Set] And $FFFF),
     ScrDatColor + (ObjLoc_Color Shl 8));
  End
  Else
  Begin
    WriteOut(bvlObjectLoc,23,2,'M0',NormTextColor + (ObjLoc_Color Shl 8));
    WriteOutBold(bvlObjectLoc,26,2,IntToStr(Game.ObjectLoc[Index_Missile0Set] And $FFFF),
     NormTextColor + (ObjLoc_Color Shl 8));
  End;

  If (AtariSeg[ENAM1] And 2) <> 0 Then
  Begin
    WriteOut(bvlObjectLoc,34,2,'M1',NormTextColor + (ObjLoc_Color Shl 8));
    WriteOutBold(bvlObjectLoc,37,2,IntToStr(Game.ObjectLoc[Index_Missile1Set] And $FFFF),
     ScrDatColor + (ObjLoc_Color Shl 8));
  End
  Else
  Begin
    WriteOut(bvlObjectLoc,34,2,'M1',NormTextColor + (ObjLoc_Color Shl 8));
    WriteOutBold(bvlObjectLoc,37,2,IntToStr(Game.ObjectLoc[Index_Missile1Set] And $FFFF),
     NormTextColor + (ObjLoc_Color Shl 8));
  End;

  If (AtariSeg[ENABL] And 2) <> 0 Then
  Begin
    WriteOut(bvlObjectLoc,45,2,'BL',NormTextColor + (ObjLoc_Color Shl 8));
    WriteOutBold(bvlObjectLoc,48,2,IntToStr(Game.ObjectLoc[Index_BallSet] And $FFFF),
     ScrDatColor + (ObjLoc_Color Shl 8));
  End
  Else
  Begin
    WriteOut(bvlObjectLoc,45,2,'BL',NormTextColor + (ObjLoc_Color Shl 8));
    WriteOutBold(bvlObjectLoc,48,2,IntToStr(Game.ObjectLoc[Index_BallSet] And $FFFF),
     NormTextColor + (ObjLoc_Color Shl 8));
  End;

  { Display data area }

  For I := 0 To DataLines - 1 Do
  Begin
    WriteOutBold(bvlData,1,2 + I,HexWord(DataTop + I * $10),NormTextColor + (DataColor Shl 8));
    For J := 0 To $F Do
    Begin
      WriteOut(bvlData,6 + J * 3,2 + I, HexByte(AtariSeg[DataTop + I * $10 + J]),
       NormTextColor + (DataColor Shl 8));
      If (J And $F) = 7 Then
       WriteOut(bvlData,8 + (J And $F) * 3,2 + I,'-',NormTextColor + (DataColor Shl 8));
    End; { For J }
  End; { For I }
{
  WriteOut(254,135,IntToStr(MemAvail),FlagsColor + (BackColor Shl 8));

  WriteOut(254,145,IntToStr(SN1),FlagsColor + (BackColor Shl 8));
  WriteOut(254,155,IntToStr(SN2),FlagsColor + (BackColor Shl 8));
  WriteOut(254,165,IntToStr(SN3),FlagsColor + (BackColor Shl 8));
  WriteOut(254,175,IntToStr(SN4),FlagsColor + (BackColor Shl 8));
}
End; { TfrmDebugger.Display }


Function TfrmDebugger.TransWordWrite(Addr: Word): String;
Begin
  If (Addr < $80) Or ((Addr >= $100) And (Addr < $180)) Then Addr := Addr And $3F;
  Case Addr Of
    0..$2C: TransWordWrite := TIA_Name[Addr];
{  $280..$297: TransWordWrite := PIA_Name[Addr];
$380..$397: TransWordWrite := PIA_Name[Addr - $100];}
  $200..$3FF: TransWordWrite := PIA_Name[$200 Or Timer_And[Addr And $1F]];
  Else TransWordWrite := HexWord(Addr);
  End; { Case }
End; { TfrmDebugger.TransWordWrite }


Function TfrmDebugger.TransWordRead(Addr: Word): String;
Begin
  Case Addr Of
    0..$7F,$100..$17F: TransWordRead := TIA_Read_Name[Addr And $F];
  $200..$3FF: TransWordRead := PIA_Name[$200 Or Timer_And[Addr And $1F]];
{  $280..$297: TransWordRead := PIA_Name[Addr];
$380..$397: TransWordRead := PIA_Name[Addr - $100];}
   Else TransWordRead := HexWord(Addr);
   End; { Case }
End; { TfrmDebugger.TransWordRead }


Function TfrmDebugger.TransByteRead(Addr: Word): String;
Begin
  Case Addr Of
    0..$7F,$100..$17F: TransByteRead := TIA_Read_Name[Addr And $F];
  $200..$3FF: TransByteRead := PIA_Name[$200 Or Timer_And[Addr And $1F]];
{  $280..$297: TransByteRead := PIA_Name[Addr];
$380..$397: TransByteRead := PIA_Name[Addr - $100];}
   Else TransByteRead := HexByte(Addr);
   End; { Case }
End; { TfrmDebugger.TransByteRead }


Function TfrmDebugger.TransByteWrite(Addr: Word): String;
Begin
  If (Addr < $80) Or ((Addr >= $100) And (Addr < $180)) Then Addr := Addr And $3F;
  Case Addr Of
    0..$2C: TransByteWrite := TIA_Name[Addr];
  Else TransByteWrite := HexByte(Addr);
  End; { Case }
End; { TfrmDebugger.TransByteWrite }


Function TfrmDebugger.TransWord(Addr: Word): String;
Var Instr: String[3];
Begin
  Instr := Mnem[Opcode];
  If (Addr < $80) And (Copy(Instr,1,2) = 'RO')
   Then TransWord := TransWordRead(Addr)
   Else
    If (Instr           = 'ADC') Or
       (Instr           = 'DEC') Or
       (Instr           = 'INC') Or
       (Instr           = 'SBC') Or
       (Copy(Instr,1,2) = 'PH')  Or
       (Copy(Instr,1,2) = 'RO')  Or
       (Copy(Instr,1,2) = 'ST')
     Then TransWord := TransWordWrite(Addr)
     Else TransWord := TransWordRead(Addr);
End; { TfrmDebugger.TransWord }


Function TfrmDebugger.TransByte(Addr: Word): String;
Var Instr: String[3];
Begin
  Instr := Mnem[Opcode];
  If (Addr < $80) And (Copy(Instr,1,2) = 'RO')
   Then TransByte := TransByteRead(Addr)
   Else
    If (Instr           = 'ADC') Or
       (Instr           = 'DEC') Or
       (Instr           = 'INC') Or
       (Instr           = 'SBC') Or
       (Copy(Instr,1,2) = 'PH')  Or
       (Copy(Instr,1,2) = 'RO')  Or
       (Copy(Instr,1,2) = 'ST')
     Then TransByte := TransByteWrite(Addr)
     Else TransByte := TransByteRead(Addr);
End; { TfrmDebugger.TransByte }

Function TfrmDebugger.BufW(Addr: Word): Word;
Var L,H: Word;
Begin
  L := AtariSeg[Addr];
  H := AtariSeg[Addr + 1];
  BufW := L + (H Shl 8);
End; // TfrmDebugger.BufW

(*
  Procedure DisplayHelp;
  Var
    I  : Integer;
    St : String;

  Begin
    Temp := HiRes;
    If HiRes Then Set320By200Mode;
    HiRes := False;
    FBox(0,0,319,199,HelpColor);

    Color := HelpHiColor + (HelpColor Shl 8);
    WriteOut(0,0,  'F1',Color);
    WriteOut(0,8,  'D',Color);
    WriteOut(0,16, 'E',Color);
    WriteOut(0,24, 'G',Color);
    WriteOut(0,32, 'H',Color);
    WriteOut(0,40, 'L',Color);
    WriteOut(0,48, 'R',Color);
    WriteOut(0,56, 'S',Color);
    WriteOut(0,64, 'T',Color);
    WriteOut(0,72, 'X',Color);
    WriteOut(0,80, 'Z',Color);
    WriteOut(0,88, '<Space>',Color);
    WriteOut(0,96, '-',Color);
    WriteOut(0,104,'=',Color);

    WriteOut(0,120,'<Up>',Color);
    WriteOut(0,128,'<Down>',Color);
    WriteOut(0,136,'<PgUp>',Color);
    WriteOut(0,144,'<PgDn>',Color);
    WriteOut(0,152,'<Home>',Color);
    WriteOut(0,160,'<End>',Color);
    WriteOut(0,168,'<Ins>',Color);

    Color := HelpTextColor + (HelpColor Shl 8);
    WriteOut(56,0,  ' - Help',Color);
    WriteOut(56,8,  ' - Toggle 320x400 mode',Color);
    WriteOut(56,16, ' - Enter data at addr. (not TIA)',Color);
    WriteOut(56,24, ' - Begin execution of code',Color);
    WriteOut(56,32, ' - Execute to hilighted position',Color);
    WriteOut(56,40, ' - Execute until scan line',Color);
    WriteOut(56,48, ' - Change 6507 register',Color);
    WriteOut(56,56, ' - Execute over next instruction',Color);
    WriteOut(56,64, ' - Execute next instruction',Color);
    WriteOut(56,72, ' - Enter break expression',Color);
    WriteOut(56,80, ' - Save 4k ROM to disk',Color);
    WriteOut(56,88, ' - Toggle game screen display',Color);
    WriteOut(56,96, ' - (game screen) show object pos.',Color);
    WriteOut(56,104,' - (game screen) show CRT pos.',Color);

    WriteOut(56,120,' - Move up one byte',Color);
    WriteOut(56,128,' - Move down one instruction',Color);
    WriteOut(56,136,' - Move up one screen',Color);
    WriteOut(56,144,' - Move down one screen',Color);
    WriteOut(56,152,' - Move to 1000h',Color);
    WriteOut(56,160,' - Move to 1FFFh',Color);
    WriteOut(56,168,' - Move to current instruction',Color);

    Color := ScrDatColor + (HelpColor Shl 8);
    WriteOut(0,184,'Hit <Space> for more, or',Color);
    WriteOut(0,192,'any other key to return',Color);

    Ch1 := ReadKey;
    If Ch1 = #32 Then
    Begin
      FBox(0,0,319,199,HelpColor);
      Color := HelpHiColor + (HelpColor Shl 8);
      For I := 0 To $2C Do
      Begin
        St := HexByte(I);
        While Length(St) < 2 Do St := '0' + St;
        If I < $17
         Then WriteOut(8,I * 8,St,Color)
         Else WriteOut(160,(I - $17) * 8,St,Color);
      End;
      Color := HelpTextColor + (HelpColor Shl 8);
      For I := 0 To $2C Do
      Begin
        If I < $17
         Then WriteOut(32,I * 8,'- ' + TIA_Name[I],Color)
         Else WriteOut(184,(I - $17) * 8,'- ' + TIA_Name[I],Color);
      End;
      Color := ScrDatColor + (HelpColor Shl 8);
      WriteOut(0,184,'Hit <Space> for more, or',Color);
      WriteOut(0,192,'any other key to return',Color);
      Ch1 := ReadKey;
      If Ch1 = #32 Then
      Begin
        FBox(0,0,319,199,HelpColor);
        Color := HelpHiColor + (HelpColor Shl 8);
        WriteOut(0,0,  ' "E" command syntax:',Color);
        WriteOut(0,32, ' "R" command syntax:',Color);
        WriteOut(0,72, ' Break expression arguments:',Color);
        Color := HelpTextColor + (HelpColor Shl 8);
        WriteOut(0,8,  '  <address>=<value>',Color);
        WriteOut(0,16, '  e.g. 125F=28 places 28h into [125Fh]',Color);

        WriteOut(0,40, '  <register>=<value>',Color);
        WriteOut(0,48, '  e.g. A=28 places 28h into reg. A',Color);
        WriteOut(0,56, '  Available registers: PC P A X Y S',Color);

        WriteOut(0,80, '  CX .......... CRT beam X position',Color);
        WriteOut(0,88, '  CY .......... CRT beam Y position',Color);
        WriteOut(0,96, '  P0 .......... Player 0 position',Color);
        WriteOut(0,104,'  P1 .......... Player 1 position',Color);
        WriteOut(0,112,'  M0 .......... Missile 0 position',Color);
        WriteOut(0,120,'  M1 .......... Missile 1 position',Color);
        WriteOut(0,128,'  BL .......... Ball position',Color);
        WriteOut(0,136,'  A ........... Register A contents',Color);
        WriteOut(0,144,'  X ........... Register X contents',Color);
        WriteOut(0,152,'  Y ........... Register Y contents',Color);
        WriteOut(0,160,'  P ........... Register P contents',Color);
        WriteOut(0,168,'  S ........... Register S contents',Color);
        WriteOut(0,176,'  [address] ... Memory contents',Color);
        Color := ScrDatColor + (HelpColor Shl 8);
        WriteOut(0,184,'Hit <Space> for more, or',Color);
        WriteOut(0,192,'any other key to return',Color);
        Ch1 := ReadKey;
        If Ch1 = #32 Then
        Begin
          FBox(0,0,319,199,HelpColor);
          Color := HelpHiColor + (HelpColor Shl 8);
          WriteOut(0,0,  ' Break expression operators:',Color);
          Color := HelpTextColor + (HelpColor Shl 8);
          WriteOut(0,8,  '  + ......... Addition',Color);
          WriteOut(0,16, '  - ......... Subtraction',Color);
          WriteOut(0,24, '  * ......... Multiplication',Color);
          WriteOut(0,32, '  / ......... Integer Division',Color);
          WriteOut(0,40, '  % ......... Modulo',Color);

          WriteOut(0,56, '  && ........ Boolean and',Color);
          WriteOut(0,64, '  || ........ Boolean or',Color);
          WriteOut(0,72, '  ^^ ........ Boolean xor',Color);
          WriteOut(0,80, '  ! or ~ .... Boolean not',Color);

          WriteOut(0,96, '  & ......... Bitwise and',Color);
          WriteOut(0,104,'  | ......... Bitwise or',Color);
          WriteOut(0,112,'  ^ ......... Bitwise xor',Color);

          WriteOut(0,128,'  = or == ... Bool/num equality',Color);
          WriteOut(0,136,'  <> or != .. Bool/num inequality',Color);
          WriteOut(0,144,'  < ......... Less than',Color);
          WriteOut(0,152,'  > ......... Greater than',Color);
          WriteOut(0,160,'  <= ........ Less than or equal',Color);
          WriteOut(0,168,'  >= ........ Greater than or equal',Color);

          WriteOut(0,184,'  ( or ) .... Parentheses',Color);
          ReadKey;
        End;
      End;
    End;
    HiRes := Temp;
    If HiRes Then Set320By400Mode;
  End; { DisplayHelp }
*)

procedure TfrmDebugger.FormPaint(Sender: TObject);
Var I,J,K,H: Integer;
begin
  Display;

  H := Canvas.TextHeight('Mg');

  // Set scrollbar position

  I := TopAddr And $1FFF;
  If I < 0 Then I := 0;
  If I > sbInstructions.Max Then I := sbInstructions.Max;
  sbInstructions.Position := I;

  { Display instructions }

  Addr := TopAddr And $1FFF;
  _DLines := (bvlInstructions.Height - 2) Div H;
//  _DLines := HRDisasmLines;
  For I := 0 To _DLines - 1 Do
  Begin
    If Addr = (Game._6507_PC And $1FFF) Then
    Begin
      Color := PCTextColor + (HiTextColor Shl 8);
      FBox(bvlInstructions.Left + 1,bvlInstructions.Top + I * H + 1,
           bvlInstructions.Left + bvlInstructions.Width - 2,
           bvlInstructions.Top + I * H + 1 + H,HiTextColor);
    End
    Else
    Begin
      If I = 0 Then
      Begin
        Color := NormTextColor + (TopAsmColor Shl 8);
        FBox(bvlInstructions.Left + 1,bvlInstructions.Top + I * H + 1,
             bvlInstructions.Left + bvlInstructions.Width - 2,
             bvlInstructions.Top + I * H + 1 + H,TopAsmColor);
      End
      Else
      Begin
        Color := NormTextColor + (DisasmColor Shl 8);
        FBox(bvlInstructions.Left + 1,bvlInstructions.Top + I * H + 1,
             bvlInstructions.Left + bvlInstructions.Width - 2,
             bvlInstructions.Top + I * H + 1 + H,DisasmColor);
      End;
    End;
    Opcode := AtariSeg[Addr And $1FFF];

    WriteOutBold(bvlInstructions,1,1 + I,HexWord(Addr And $1FFF),Color);

    For J := 0 To Bytes[Opcode] - 1 Do
     WriteOut(bvlInstructions,7 + J * 2,1 + I,HexByte(AtariSeg[(Addr + J) And $1FFF]),Color);

    { Write cycles }

    WriteOut(bvlInstructions,15,1 + I,Mnem[Opcode],Color);
(*
    WriteSmOut(2,2 + I * 8,HexWord(Addr),Color);

    For J := 0 To Bytes[Opcode] - 1 Do
    Begin
      WriteSmOut(44 + J * 12,2 + I * 8,
       HexByte(AtariSeg[Addr + J]),Color);
    End; { For J }

    { Write cycles }

    WriteSmOut(88,2 + I * 8,Mnem[Opcode],Color);
*)
    OTyp    := ATyp[Opcode];
    Operand := '';
    If OTyp = 'ABS' Then Operand := TransWord(BufW(Addr + 1) And $1FFF);
    If OTyp = 'A.X' Then Operand := TransWord(BufW(Addr + 1) And $1FFF) + ',X';
    If OTyp = 'A.Y' Then Operand := TransWord(BufW(Addr + 1) And $1FFF) + ',Y';
    If OTyp = 'ASY' Then Operand := '(' + TransWord(BufW(Addr + 1) And $1FFF) + ',Y) & S';
    If OTyp = 'IND' Then Operand := '(' + HexWord(BufW(Addr + 1) And $1FFF) + ')';
    If OTyp = 'I.X' Then Operand := '(' + HexByte(AtariSeg[(Addr + 1) And $1FFF]) + ',X)';
    If OTyp = 'I.Y' Then Operand := '(' + HexByte(AtariSeg[(Addr + 1) And $1FFF]) + '),Y';
    If OTyp = 'ACC' Then Operand := 'A';
    If OTyp = 'IMM' Then Operand := '#' + HexByte(AtariSeg[(Addr + 1) And $1FFF]);
    If OTyp = 'Z.P' Then Operand := TransByte(AtariSeg[(Addr + 1) And $1FFF]);
    If OTyp = 'Z.X' Then Operand := TransByte(AtariSeg[(Addr + 1) And $1FFF]) + ',X';
    If OTyp = 'Z.Y' Then Operand := TransByte(AtariSeg[(Addr + 1) And $1FFF]) + ',Y';
    If OTyp = 'I+A' Then Operand := '#' + HexByte(AtariSeg[(Addr + 1) And $1FFF]) + ' + A';
    If OTyp = 'REL' Then
    Begin
      K := AtariSeg[(Addr + 1) And $1FFF];
      J := Addr;
      Asm
        MOV   CX,WORD PTR J
        ADD   CX,2
        MOV   AL,BYTE PTR K
        CBW
        ADD   CX,AX
        MOV   WORD PTR J,CX
      End; { Asm }
      Operand := HexWord(J);
    End;
    WriteOut(bvlInstructions,21,1 + I,Operand,Color);
//    WriteSmOut(136,2 + I * 8,Operand,Color);

    Inc(Addr,Bytes[Opcode]);
  End; { For I }
end;

Procedure TfrmDebugger.InitDebugger;
Type
  TRGBA = Packed Record
    R,G,B,A: Byte;
  End;

Var
  I : Integer;
  C : TRGBA;

Begin
  Font.Name := FontName;
  Font.Size := FontSize;
  TopAddr := Game._6507_PC;
  DataTop := $80;

  // Fill in ScreenPalette

  C.A := 0;
  For I := 0 To 127 Do
  Begin
    C.R := Pal[I].R;
    C.G := Pal[I].G;
    C.B := Pal[I].B;
    ScreenPalette[I * 2]     := TColor(C);
    ScreenPalette[I * 2 + 1] := TColor(C);
  End; // For I
End; // TfrmDebugger.InitDebugger

procedure TfrmDebugger.FormShow(Sender: TObject);
begin
  Caption := 'PCAE ' + Version;
  InitDebugger;
  btnStop.Enabled := False;
end;

procedure TfrmDebugger.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  If ShowBeam Then Move(DebugScnBuf,ScnBuf,SizeOf(ScnBuf));
  Debugger                     := False;
  frmMain.ShowCrosshair        := False;
  frmMain.UseDebugger1.Checked := Debugger;
  frmMain.Display;
end;

procedure TfrmDebugger.FormResize(Sender: TObject);
Var W,H: Integer;
begin

  // Get character dimensions

  W := Canvas.TextWidth('M');
  H := Canvas.TextHeight('Mg');

  // There are a minimum required width and height.  Don't allow anything smaller.

  If ClientWidth < 53 * W + 10 Then ClientWidth := 53 * W + 10;
  If ClientHeight < 31 * H + 14 + pnlButtons.Height Then ClientHeight := 31 * H + 14 + pnlButtons.Height;

  // Set positions

  bvlFlags.Width         := 10 * W + 2;
  bvlRegs.Width          := bvlFlags.Width;
  bvlScreenData.Width    := bvlFlags.Width;

  bvlFlags.Height        := 2 * H + 2;
  bvlRegs.Height         := 6 * H + 2;
  bvlScreenData.Height   := 6 * H + 2;

  bvlRegs.Top            := bvlFlags.Height;
  bvlScreenData.Top      := bvlRegs.Top + bvlRegs.Height;

  bvlFlags.Left          := ClientWidth - bvlRegs.Width;
  bvlRegs.Left           := bvlFlags.Left;
  bvlScreenData.Left     := bvlFlags.Left;

  bvlinstructions.Width  := bvlFlags.Left - sbInstructions.Width;
  sbInstructions.Left    := bvlInstructions.Width;
  btnPC.Left             := sbInstructions.Left;
  btnTop.Left            := sbInstructions.Left;

  bvlTIARegs.Width       := ClientWidth;
  bvlInputRegs.Width     := ClientWidth;
  bvlObjectLoc.Width     := ClientWidth;
  bvlData.Width          := ClientWidth;

  bvlTIARegs.Height      := 4 * H + 2;
  bvlInputRegs.Height    := 2 * H + 2;
  bvlObjectLoc.Height    := 2 * H + 2;
  bvlData.Height         := 9 * H + 2;

  bvlData.Top            := pnlButtons.Top - bvlData.Height;
  bvlObjectLoc.Top       := bvlData.Top - bvlObjectLoc.Height;
  bvlInputRegs.Top       := bvlObjectLoc.Top - bvlInputRegs.Height;
  bvlTIARegs.Top         := bvlInputRegs.Top - bvlTIARegs.Height;
  bvlInstructions.Height := bvlTIARegs.Top - bvlInstructions.Top;
  sbInstructions.Height  := bvlInstructions.Height - btnPC.Height - btnTop.Height;
  btnPC.Top              := sbInstructions.Height + btnTop.Height;
end;

procedure TfrmDebugger.btnTraceClick(Sender: TObject);
begin
  If ShowBeam Then Move(DebugScnBuf,ScnBuf,SizeOf(ScnBuf));
  Opcode := AtariSeg[Game._6507_PC];
  OTyp   := ATyp[Opcode];
  If Mnem[Opcode] = 'JSR' Then
  Begin
    Game.OldStart := BufW(Game._6507_PC + 1) And $1FFF;
  End
  Else
   If Mnem[Opcode] = 'JMP' Then
   Begin
     If OTyp = 'ABS'
      Then Game.OldStart := BufW(Game._6507_PC + 1) And $1FFF
      Else Game.OldStart := BufW(BufW(Game._6507_PC + 1) And $1FFF) And $1FFF;
   End
   Else
    If Mnem[Opcode] = 'BPL' Then
    Begin
      If (Game._6507_P And $80) = 0
       Then Game.OldStart := Game._6507_PC + ShortInt(AtariSeg[Game._6507_PC + 1] + 2)
       Else Game.OldStart := Game._6507_PC + Bytes[Opcode];
    End
    Else
     If Mnem[Opcode] = 'BMI' Then
     Begin
       If (Game._6507_P And $80) <> 0
        Then Game.OldStart := Game._6507_PC + ShortInt(AtariSeg[Game._6507_PC + 1] + 2)
        Else Game.OldStart := Game._6507_PC + Bytes[Opcode];
     End
     Else
      If Mnem[Opcode] = 'BVC' Then
      Begin
        If (Game._6507_P And $40) = 0
         Then Game.OldStart := Game._6507_PC + ShortInt(AtariSeg[Game._6507_PC + 1] + 2)
         Else Game.OldStart := Game._6507_PC + Bytes[Opcode];
      End
      Else
       If Mnem[Opcode] = 'BVS' Then
       Begin
         If (Game._6507_P And $40) <> 0
          Then Game.OldStart := Game._6507_PC + ShortInt(AtariSeg[Game._6507_PC + 1] + 2)
          Else Game.OldStart := Game._6507_PC + Bytes[Opcode];
       End
       Else
        If Mnem[Opcode] = 'BCC' Then
        Begin
          If (Game._6507_P And 1) = 0
           Then Game.OldStart := Game._6507_PC + ShortInt(AtariSeg[Game._6507_PC + 1] + 2)
           Else Game.OldStart := Game._6507_PC + Bytes[Opcode];
        End
        Else
         If Mnem[Opcode] = 'BCS' Then
         Begin
           If (Game._6507_P And 1) <> 0
            Then Game.OldStart := Game._6507_PC + ShortInt(AtariSeg[Game._6507_PC + 1] + 2)
            Else Game.OldStart := Game._6507_PC + Bytes[Opcode];
         End
         Else
          If Mnem[Opcode] = 'BNE' Then
          Begin
            If (Game._6507_P And 2) = 0
             Then Game.OldStart := Game._6507_PC + ShortInt(AtariSeg[Game._6507_PC + 1] + 2)
             Else Game.OldStart := Game._6507_PC + Bytes[Opcode];
          End
          Else
           If Mnem[Opcode] = 'BEQ' Then
           Begin
             If (Game._6507_P And 2) <> 0
              Then Game.OldStart := Game._6507_PC + ShortInt(AtariSeg[Game._6507_PC + 1] + 2)
              Else Game.OldStart := Game._6507_PC + Bytes[Opcode];
           End
           Else
            If Mnem[Opcode] = 'RTS' Then Game.OldStart := (BufW(Game._6507_S + 1) + 1) And $1FFF
            Else
             If Mnem[Opcode] = 'BRK' Then Game.OldStart := BufW($1FFE) And $1FFF
             Else
              If Mnem[Opcode] = 'RTI' Then Game.OldStart := BufW(Game._6507_S + 2) And $1FFF
              Else Game.OldStart := Game._6507_PC + Bytes[Opcode];
  frmMain.ShowCrosshair := False;
  Emulate;
  If ShowBeam Then Move(ScnBuf,DebugScnBuf,SizeOf(DebugScnBuf));
  frmMain.ShowCrosshair := ShowBeam;
  frmMain.Display;
end;

procedure TfrmDebugger.btnGoClick(Sender: TObject);
begin
  Game.OldStart := 0;
  If ShowBeam Then Move(DebugScnBuf,ScnBuf,SizeOf(ScnBuf));
  frmMain.ShowCrosshair  := False;
  btnGo.Enabled          := False;
  btnTrace.Enabled       := False;
  btnSkip.Enabled        := False;
  btnHere.Enabled        := False;
  btnLine.Enabled        := False;
  btnExpression.Enabled  := False;
  btnReg.Enabled         := False;
  btnMem.Enabled         := False;
  btnSave.Enabled        := False;
  btnBeam.Enabled        := False;
  btnStop.Enabled        := True;
  sbInstructions.Enabled := False;
  Emulate;
  If ShowBeam Then Move(ScnBuf,DebugScnBuf,SizeOf(DebugScnBuf));
  frmMain.ShowCrosshair := ShowBeam;
  frmMain.Display;
  btnGo.Enabled          := True;
  btnTrace.Enabled       := True;
  btnSkip.Enabled        := True;
  btnHere.Enabled        := True;
  btnLine.Enabled        := True;
  btnExpression.Enabled  := True;
  btnReg.Enabled         := True;
  btnMem.Enabled         := True;
  btnSave.Enabled        := True;
  btnBeam.Enabled        := True;
  btnStop.Enabled        := False;
  sbInstructions.Enabled := True;
end;

procedure TfrmDebugger.btnSkipClick(Sender: TObject);
begin
  If ShowBeam Then Move(DebugScnBuf,ScnBuf,SizeOf(ScnBuf));
  Opcode := AtariSeg[Game._6507_PC];
  OTyp   := ATyp[Opcode];
  If (Mnem[Opcode] = 'JSR') Or (Mnem[Opcode] = 'BRK') Then
  Begin
    Game.OldStart := Game._6507_PC + Bytes[Opcode];
    frmMain.ShowCrosshair := False;
    Emulate;
    If ShowBeam Then Move(ScnBuf,DebugScnBuf,SizeOf(DebugScnBuf));
    frmMain.ShowCrosshair := ShowBeam;
    frmMain.Display;
  End
  Else btnTraceClick(Self);
end;

procedure TfrmDebugger.btnHereClick(Sender: TObject);
begin
  If ShowBeam Then Move(DebugScnBuf,ScnBuf,SizeOf(ScnBuf));
  Opcode        := AtariSeg[TopAddr];
  Game.OldStart := TopAddr;
  frmMain.ShowCrosshair := False;
  Emulate;
  If ShowBeam Then Move(ScnBuf,DebugScnBuf,SizeOf(DebugScnBuf));
  frmMain.ShowCrosshair := ShowBeam;
  frmMain.Display;
end;

procedure TfrmDebugger.btnLineClick(Sender: TObject);
Var
  HaltNum,Code : Integer;
  St           : String;

begin
  St := Trim(InputBox('Break on scan line','Enter breakpoint scan line',''));
  If St <> '' Then
  Begin
    Val(St,HaltNum,Code);
    If (Code = 0) Or ((Code = 0) And ((HaltNum < -40) Or (HaltNum > 350))) Then
    Begin
      If ShowBeam Then Move(DebugScnBuf,ScnBuf,SizeOf(ScnBuf));
      HaltLine      := HaltNum;
      Game.OldStart := 0;
      frmMain.ShowCrosshair := False;
      Emulate;
      If ShowBeam Then Move(ScnBuf,DebugScnBuf,SizeOf(DebugScnBuf));
      frmMain.ShowCrosshair := ShowBeam;
      frmMain.Display;
    End
    Else Application.MessageBox('You must enter a number between -40 and 350','Error',MB_OK);
  End;
end;

procedure TfrmDebugger.btnMemClick(Sender: TObject);
Var
  St                  : String;
  HexAddr,Code,HexVal : Integer;

begin
  St := Trim(InputBox('Change memory contents','Enter new data in the form "address=value"',''));
  If St <> '' Then
  Begin
    Code := Pos('=',St);
    If Code <> 0 Then
    Begin
      HexAddr := ValHex(Trim(Copy(St,1,Code - 1)));
      If (HexAddr >= 0) And ((HexAddr And $1FFF) >= $80) Then
      Begin
        HexAddr := HexAddr And $1FFF;
        St   := Trim(Copy(St,Code + 1,Length(St) - Code));
        Code := Pos(' ',St);
        If (Code = 0) And (St <> '') Then Code := Length(St) + 1;
        While Code <> 0 Do
        Begin
          HexVal := ValHex(Trim(Copy(St,1,Code - 1)));
          If HexVal >= 0 Then AtariSeg[HexAddr] := HexVal And $FF;
          Inc(HexAddr);
          St   := Trim(Copy(St,Code + 1,Length(St) - Code));
          Code := Pos(' ',St);
          If (Code = 0) And (St <> '') Then Code := Length(St) + 1;
        End; { While }
        Repaint;
      End;
    End;
  End;
end;

procedure TfrmDebugger.btnSaveClick(Sender: TObject);
begin
  If dlgSave.Execute Then
  Begin
    St := Trim(dlgSave.FileName);
    If St <> '' Then
    Begin
    {$I-}
      AssignFile(OutFile,St);
      ReWrite(OutFile,1);
    {$I+}
      If IOResult = 0 Then
      Begin
        BlockWrite(OutFile,AtariSeg[$1000],$1000);
        CloseFile(OutFile);
      End;
    End;
  End;
end;

procedure TfrmDebugger.btnBeamClick(Sender: TObject);
begin
  If Not ShowBeam Then Move(ScnBuf,DebugScnBuf,SizeOf(DebugScnBuf));
  ShowBeam := Not ShowBeam;
  If Not ShowBeam Then Move(DebugScnBuf,ScnBuf,SizeOf(ScnBuf));
  frmMain.ShowCrosshair := ShowBeam;
  frmMain.Display;
end;

procedure TfrmDebugger.btnStopClick(Sender: TObject);
begin
  Exiting := True;
end;

procedure TfrmDebugger.FormCreate(Sender: TObject);
begin
  ShowBeam := False;
  Scaled   := False;  
end;

procedure TfrmDebugger.sbInstructionsScroll(Sender: TObject;
  ScrollCode: TScrollCode; var ScrollPos: Integer);
Var I,J,K: Integer;
begin
  Case ScrollCode Of
    scLineUp: If TopAddr > 0 Then Dec(TopAddr);
  scLineDown: Begin
                Opcode := AtariSeg[TopAddr];
                Inc(TopAddr,Bytes[Opcode]);
              End;
    scPageUp: Begin
                I := TopAddr;
                Repeat
                  J := 0;
                  K := I;
                  While K < TopAddr Do
                  Begin
                    Inc(J);
                    Opcode := AtariSeg[K And $1FFF];
                    Inc(K,Bytes[Opcode]);
                  End; { While }
                  If J < _DLines - 1 Then Dec(I);
                Until J >= _Dlines - 1;
                TopAddr := I;
              End;
  scPageDown: TopAddr := Addr;
  scPosition,scTrack: TopAddr := ScrollPos;
       scTop: TopAddr := 0;
    scBottom: TopAddr := $1FFF;       
  End; // Case

//  TopAddr := sbInstructions.Position + $1000;
//  If TopAddr < 0     Then TopAddr := 0;
  If TopAddr > $1FFF Then TopAddr := $1FFF;
  Repaint;
end;

procedure TfrmDebugger.btnPCClick(Sender: TObject);
begin
  TopAddr := Game._6507_PC;
  Repaint;
end;

procedure TfrmDebugger.btnTopClick(Sender: TObject);
begin
  TopAddr := $1000;
  Repaint;
end;

procedure TfrmDebugger.btnRegClick(Sender: TObject);
Var
  St          : String;
  Code,HexVal : Integer;

begin
  St   := UpperCase(Trim(InputBox('Change register contents','Enter new value in the form reg=value','')));
  Code := Pos(' ',St);
  While Code <> 0 Do
  Begin
    Delete(St,Code,1);
    Code := Pos(' ',St);
  End; { While }
  If St <> '' Then
  Begin
    If Copy(St,1,3) = 'PC=' Then
    Begin
      HexVal := ValHex(Copy(St,4,Length(St) - 3));
      If HexVal >= 0 Then
      Begin
        Game._6507_PC := HexVal And $1FFF;
        Repaint;
      End;
    End;
    If Copy(St,1,2) = 'P=' Then
    Begin
      HexVal := ValHex(Copy(St,3,Length(St) - 2));
      If HexVal >= 0 Then
      Begin
        Game._6507_P := HexVal And $FF;
        Repaint;
      End;
    End;
    If Copy(St,1,2) = 'A=' Then
    Begin
      HexVal := ValHex(Copy(St,3,Length(St) - 2));
      If HexVal >= 0 Then
      Begin
        Game._6507_A := HexVal And $FF;
        Repaint;
      End;
    End;
    If Copy(St,1,2) = 'X=' Then
    Begin
      HexVal := ValHex(Copy(St,3,Length(St) - 2));
      If HexVal >= 0 Then
      Begin
        Game._6507_X := HexVal And $FF;
        Repaint;
      End;
    End;
    If Copy(St,1,2) = 'Y=' Then
    Begin
      HexVal := ValHex(Copy(St,3,Length(St) - 2));
      If HexVal >= 0 Then
      Begin
        Game._6507_Y := HexVal And $FF;
        Repaint;
      End;
    End;
    If Copy(St,1,2) = 'S=' Then
    Begin
      HexVal := ValHex(Copy(St,3,Length(St) - 2));
      If HexVal >= 0 Then
      Begin
        Game._6507_S := HexVal And $FF;
        Repaint;
      End;
    End;
  End;
end;

procedure TfrmDebugger.btnTIARefClick(Sender: TObject);
begin
  frmTIARef.Show;
end;

procedure TfrmDebugger.btnExpRefClick(Sender: TObject);
begin
  frmExpRef.Show;
end;

procedure TfrmDebugger.btnExpressionClick(Sender: TObject);
Var ExpError: Boolean;
begin
  St := Trim(InputBox('Break on expression','Enter breakpoint expression',BreakExp));

  { Get rid of the last break expression collection, if any }

  If BreakExpColl <> Nil Then
  Begin
    BreakExpColl.Free;
    BreakExpColl := Nil;
  End;
  ExpError := False;
  If St <> '' Then
  Begin
    BreakExpColl := PostFix(St);
    If BreakExpColl <> Nil Then
    Begin

      { Try to evaluate it to make sure it's ok (ignore the result) }

      Evaluate(BreakExpColl,AtariSeg,0,0,0,0,0,0,0,0,0,0,0,0,0,ExpError);
      If ExpError Then
      Begin
        BreakExpColl.Free;
        BreakExpColl := Nil;
        St := '';
      End;
    End
    Else
    Begin
      St       := '';
      ExpError := True;
    End;
  End;
  BreakExp := St;  { Remember the last one }
  If ExpError Then ShowMessage('Error in expression');
end;

Initialization
  BreakExp := '';
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.
// ----------------------------------------------------------------------
