Unit SPUnit;
{ DEFINE LOG}
{ DEFINE P2LOG}
Interface

Uses AtariDis;

Const
  playback_freq : Word = 31400;
  Cycles : Packed Array[0..255] Of Byte =
   (7,6,0,8,3,3,5,5, 3,2,2,2,4,4,6,6,  { 00-0F }
    2,5,0,8,4,4,6,6, 2,4,2,7,4,4,7,7,  { 10-1F }
    6,6,0,8,3,3,5,5, 4,2,2,2,4,4,6,6,  { 20-2F }
    2,5,0,8,4,4,6,6, 2,4,2,7,4,4,7,7,  { 30-3F }
    6,6,0,8,3,3,5,5, 3,2,2,2,3,4,6,6,  { 40-4F }
    2,5,0,8,4,4,6,6, 2,4,2,7,4,4,7,7,  { 50-5F }
    6,6,0,8,3,3,5,5, 4,2,2,2,5,4,6,6,  { 60-6F }
    2,5,0,8,4,4,6,6, 2,4,2,7,4,4,7,7,  { 70-7F }
    2,6,2,6,3,3,3,3, 2,2,2,2,4,4,4,4,  { 80-8F }
    2,6,0,6,4,4,4,4, 2,5,2,5,5,5,5,5,  { 90-9F }
    2,6,2,6,3,3,3,3, 2,2,2,2,4,4,4,4,  { A0-AF }
    2,5,0,5,4,4,4,4, 2,4,2,4,4,4,4,4,  { B0-BF }
    2,6,2,8,3,3,5,5, 2,2,2,2,4,4,6,6,  { C0-CF }
    2,5,0,8,4,4,6,6, 2,4,2,7,4,4,7,7,  { D0-DF }
    2,6,2,8,3,3,5,5, 2,2,2,2,4,4,6,6,  { E0-EF }
    2,5,0,8,4,4,6,6, 2,4,2,7,0,4,7,7); { F0-FF }

Var
  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;
  SPWave  : Packed Array[1..4] Of Byte;

  { Total values }

  _Wave    : Packed Array[1..3] Of Single;
  _WaveLen : Packed Array[1..3] Of Single;
  _Pulse   : Packed Array[1..3] Of Single;

  { Remainders }

  Rem_Wave    : Packed Array[1..3] Of Single;
{
Function  HandleStarpath(PC,LastAddr,SPBankNum: Word;
                         TIA_Count,TIA_Scan: SmallInt; ROMSize: Word): Boolean; Pascal;
}
Function  HandleStarpath(PC,LastAddr: LongInt): Boolean; 
Procedure HandlePitfall2(BSValue,Addr,XY,Acc,PC: Word); Pascal;
Procedure FillDump(Const P: Array Of Byte);
Procedure LoadStarpath(Var F: File; Size: Word);
Procedure SaveSPP2Status(Var F: File);
Procedure RestoreSPP2Status(Var F: File);
Procedure InitStarpath;

Implementation

Uses HexWrite,frmDebuggerUnt,TIASound,HandTIA,frmMainUnt;

Type
  TPF2Dump = Packed Array[0..2048 + 255 - 1] Of Byte;

Var
  SPWrite     : Boolean;
  SPWriteVal  : Byte;
//  Listing     : System.Text;
  C0,S0       : Integer;
  C1,S1       : Integer;
  PF2Dump     : TPF2Dump;
  PF2Read     : Packed Array[0..23] Of SmallInt;
  PF2ReadB    : Packed Array[0..7] Of Boolean;
  Rand        : Packed Array[0..3] Of Byte;
  SPOfs       : Word;

Procedure SaveSPP2Status(Var F: File);
Begin
  BlockWrite(F,SPWrite,SizeOf(SPWrite));
  BlockWrite(F,SPWriteVal,SizeOf(SPWriteVal));
  BlockWrite(F,C0,SizeOf(C0));
  BlockWrite(F,S0,SizeOf(S0));
  BlockWrite(F,C1,SizeOf(C1));
  BlockWrite(F,S1,SizeOf(S1));
  BlockWrite(F,PF2Dump,SizeOf(PF2Dump));
  BlockWrite(F,PF2Read,SizeOf(PF2Read));
  BlockWrite(F,PF2ReadB,SizeOf(PF2ReadB));
  BlockWrite(F,Rand,SizeOf(Rand));
  BlockWrite(F,SPOfs,SizeOf(SPOfs));
End; { SaveSPP2Status }


Procedure RestoreSPP2Status(Var F: File);
Begin
  BlockRead(F,SPWrite,SizeOf(SPWrite));
  BlockRead(F,SPWriteVal,SizeOf(SPWriteVal));
  BlockRead(F,C0,SizeOf(C0));
  BlockRead(F,S0,SizeOf(S0));
  BlockRead(F,C1,SizeOf(C1));
  BlockRead(F,S1,SizeOf(S1));
  BlockRead(F,PF2Dump,SizeOf(PF2Dump));
  BlockRead(F,PF2Read,SizeOf(PF2Read));
  BlockRead(F,PF2ReadB,SizeOf(PF2ReadB));
  BlockRead(F,Rand,SizeOf(Rand));
  BlockRead(F,SPOfs,SizeOf(SPOfs));
End; { RestoreSPP2Status }


Procedure LoadStarpath(Var F: File; Size: Word);
Var
  I,J    : Word;
  Loads  : Word;
  Blocks : Word;
  Dest   : Word;
  Header : Packed Array[0..$57] Of Byte;

Begin
  Loads := Size Div 8448;
  Seek(F,0);
  BlockRead(F,ROMBackup,Size);
  For I := 0 To Loads - 1 Do
  Begin
    If I > 0 Then
     Move(ROMBackup[(I - 1) * 8448],ROMBackup[I * 8448],8192);
    Seek(F,I * 8448 + $2000);
    BlockRead(F,Header,SizeOf(Header));
    Blocks := Header[3];
    For J := 0 To Blocks - 1 Do
    Begin
      Seek(F,I * 8448 + J * 256);
      Dest := Header[J + $10];
      Dest := ((Dest And $1C) Shl 6) + ((Dest And 3) Shl 11) + I * 8448;
      BlockRead(F,ROMBackup[Dest],256);
    End; { For J }
  End; { For I }
End; { LoadStarpath }

{
Function HandleStarpath(PC,LastAddr,SPBankNum: Word;
                        TIA_Count,TIA_Scan: SmallInt; ROMSize: Word): Boolean; Pascal;
}
Function HandleStarpath(PC,LastAddr: LongInt): Boolean; 
Const
  Boot: Packed Array[0..$B] Of Byte =
   ($AD,$00,$0E,$A2,$FF,$A0,$00,$A9,$00,$4C,$F7,$00);

Var
  Opcode : Byte;
  Addr1  : Word;
  Addr2  : Word;
  Addr3  : Word;

  CInc1  : Integer;
  CInc2  : Integer;
  CInc3  : Integer;
  CInc4  : Integer;

  B      : Byte;

  Found  : Boolean;
  Index  : Byte;
  TIA_Count : Integer;
  TIA_Scan  : Integer;
  SPBankNum : Integer;

  Function TransWordWrite(Addr: Word): String;
  Begin
    If Addr < $80 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];
    Else TransWordWrite := HexWord(Addr);
    End; { Case }
  End; { TransWordWrite }


  Function TransWordRead(Addr: Word): String;
  Begin
    Case Addr Of
      0..$7F: TransWordRead := TIA_Read_Name[Addr And $F];
  $280..$297: TransWordRead := PIA_Name[Addr];
  $380..$397: TransWordRead := PIA_Name[Addr - $100];
    Else TransWordRead := HexWord(Addr);
    End; { Case }
  End; { TransWordRead }


  Function TransByteRead(Addr: Word): String;
  Begin
    Case Addr Of
      0..$7F: TransByteRead := TIA_Read_Name[Addr And $F];
  $280..$297: TransByteRead := PIA_Name[Addr];
  $380..$397: TransByteRead := PIA_Name[Addr - $100];
     Else TransByteRead := HexByte(Addr);
     End; { Case }
  End; { TransByteRead }


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


  Function 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; { TransWord }


  Function 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; { TransByte }


  Procedure GetWrite;
  Begin
    If Addr3 > $10FF Then
    Begin
      Addr3 := LastAddr;
      CInc3 := CInc4;
    End;
    If Addr2 > $10FF Then
    Begin
      Addr2 := Addr3;
      CInc2 := CInc3;
    End;
    If Addr1 > $10FF Then
    Begin
      Addr1 := Addr2;
      CInc1 := CInc2;
    End;
    If (Addr1 >= $1000) And (Addr1 <= $10FF) Then
    Begin
      SPWrite    := True;
      SPWriteVal := Addr1 And $FF;
      C0         := TIA_Count;
      S0         := TIA_Scan;
      If S0 > 250 Then S0 := 250;
    End;
  End; { GetWrite }

Begin
  TIA_Count := Game.TIA_Count;
  TIA_Scan  := Game.TIA_Scan;
  SPBankNum := Game.SPBankNum;

  If Not SPBoot Then Move(Boot,AtariSeg[$0E00],SizeOf(Boot));

  SPBank         := SPBankNum;
  HandleStarpath := False;
  Opcode         := AtariSeg[PC];

  If (LastAddr = $0E00) And (PC = $0E00) Then
  Begin
    B        := AtariSeg[$FA];
    Found    := False;
    SPSearch := 0;
    While (SPSearch < Game.ROMSize) And (SPSearch < 4 * 8448) And Not Found Do
    Begin
      Index := ROMBackup[SPSearch + $2005];
      If Index = B Then Found := True Else Inc(SPSearch,8448);
    End; { While }
    If Found Then
    Begin

      FillChar(AtariSeg[$81],$1D,#0);
      B := ROMBackup[SPSearch + $2002];
      AtariSeg[$80] := B;
      AtariSeg[$F7] := $CD;   { CMP 1000 }
      AtariSeg[$F8] := $00;
      AtariSeg[$F9] := $10;
      AtariSeg[$FA] := $AD;   { LDA 1FF8 }
      AtariSeg[$FB] := $F8;
      AtariSeg[$FC] := $1F;
      AtariSeg[$FD] := $4C;   { JMP Start }
      AtariSeg[$F8] := B;
      AtariSeg[$FE] := ROMBackup[SPSearch + $2000];
      AtariSeg[$FF] := ROMBackup[SPSearch + $2001];

      SPBankNum := B;
      Move(ROMBackup[SP1[(SPBankNum Shr 2) And 7] + SPSearch],
           AtariSeg[$1000],$800);
      Move(ROMBackup[SP2[(SPBankNum Shr 2) And 7] + SPSearch],
           AtariSeg[$1800],$800);

      SPWrite        := False;
      SPBank         := SPBankNum;
      HandleStarpath := True;
    End;
    Exit;
  End;

  { Log the instruction }

{$IFDEF LOG}
  Write(Listing,HexWord(PC),'    ',Mnem[Opcode],'   ');
  OTyp := ATyp[Opcode];
  If OTyp = 'ABS' Then Write(Listing,'   ',TransWord(MemW[Seg(AtariSeg^):Ofs(AtariSeg^) + PC + 1] And $1FFF));
  If OTyp = 'A.X' Then Write(Listing,'   ',TransWord(MemW[Seg(AtariSeg^):Ofs(AtariSeg^) + PC + 1] And $1FFF),',X');
  If OTyp = 'A.Y' Then Write(Listing,'   ',TransWord(MemW[Seg(AtariSeg^):Ofs(AtariSeg^) + PC + 1] And $1FFF),',Y');
  If OTyp = 'ASY' Then Write(Listing,'   (',TransWord(MemW[Seg(AtariSeg^):Ofs(AtariSeg^) + PC + 1] And $1FFF),',Y) & S');
  If OTyp = 'IND' Then Write(Listing,'   (',HexWord(MemW[Seg(AtariSeg^):Ofs(AtariSeg^) + PC + 1] And $1FFF),')');
  If OTyp = 'I.X' Then Write(Listing,'   (',HexByte(AtariSeg^[PC + 1]),',X)');
  If OTyp = 'I.Y' Then Write(Listing,'   (',HexByte(AtariSeg^[PC + 1]),'),Y');
  If OTyp = 'ACC' Then Write(Listing,'   A');
  If OTyp = 'IMM' Then Write(Listing,'   #',HexByte(AtariSeg^[PC + 1]));
  If OTyp = 'Z.P' Then Write(Listing,'   ',TransByte(AtariSeg^[PC + 1]));
  If OTyp = 'Z.X' Then Write(Listing,'   ',TransByte(AtariSeg^[PC + 1]),',X');
  If OTyp = 'Z.Y' Then Write(Listing,'   ',TransByte(AtariSeg^[PC + 1]),',Y');
  If OTyp = 'I+A' Then Write(Listing,'   #',HexByte(AtariSeg^[PC + 1]),' + A');
  If OTyp = 'REL' Then
  Begin
    B := AtariSeg^[PC + 1];
    Asm
      MOV   BX,WORD PTR PC
      ADD   BX,2
      MOV   AL,BYTE PTR B
      CBW
      ADD   BX,AX
      MOV   WORD PTR J,BX
    End; { Asm }
    Write(Listing,'   ',HexWord(J));
  End;
  If SPWrite Then Write(Listing,'    ',SPWrite,'  (',HexByte(SPWriteVal),')');
{$ENDIF}

  { Get all the addresses that can be accessed }

  If (ATyp[Opcode] = 'A.X') Or           { Absolute X }
     (ATyp[Opcode] = 'A.Y') Or           { Absolute Y }
     (ATyp[Opcode] = 'I.Y') Then         { Indirect Y }
  Begin
    SPOfs := (LastAddr - (AtariSegW(PC + 1) And $1FFF)) And $FF;

    If Copy(ATyp[Opcode],1,1) = 'A' Then
    Begin
      Addr1 := AtariSegW(PC + 1) And $1FFF;
      Addr3 := (Addr1 And $FF00) + (LastAddr And $FF);
      Addr2 := Addr3;
      Addr1 := Addr3;

      If Opcode In [$19,$1D,$39,$3D,$59,$5D,$79,$7D,$B9,$BB,$BC,$BD,$BE,$BF,$D9,$DD,$F9,$FD] Then
      Begin
        CInc1 := 4;                      { Read }
        CInc2 := 4;
        CInc3 := 4;
        CInc4 := 4;
        If (Addr3 And $FF00) <> (LastAddr And $FF00) Then
        Begin
          Inc(CInc1);
          Inc(CInc2);
          Inc(CInc3);
          Inc(CInc4);
        End;
      End
      Else
       If Opcode In [$99,$9C,$9D,$9E,$9F] Then
       Begin
         CInc1 := 4;                     { Write }
         CInc2 := 4;
         CInc3 := 4;
         CInc4 := 5;
       End
       Else
       Begin
         CInc1 := 4;                     { Read/Modify/Write }
         CInc2 := 5;
         CInc3 := 6;
         CInc4 := 7;
         Addr2 := LastAddr;
         Addr3 := LastAddr;
       End;
    End
    Else
    Begin
      Addr1 := AtariSegW(PC + 1) And $FF;
      Addr2 := AtariSegW(Addr1) And $1FFF;
      Addr3 := (Addr2 And $FF00) + (LastAddr And $FF);
      Addr1 := Addr3;
      Addr2 := Addr3;

      If Opcode In [$11,$31,$51,$71,$B1,$D1,$F1] Then
      Begin
        CInc1 := 5;                      { Read }
        CInc2 := 5;
        CInc3 := 5;
        CInc4 := 5;
        If (Addr3 And $FF00) <> (LastAddr And $FF00) Then
        Begin
          Inc(CInc1);
          Inc(CInc2);
          Inc(CInc3);
          Inc(CInc4);
        End;
      End
      Else
       If Opcode In [$91,$93] Then                     
       Begin
         CInc1 := 5;                     { Write }
         CInc2 := 5;
         CInc3 := 5;
         CInc4 := 6;
       End
       Else
       Begin                                           
         CInc1 := 5;                     { Read/Modify/Write }
         CInc2 := 6;
         CInc3 := 7;
         CInc4 := 8;
         Addr2 := LastAddr;
         Addr3 := LastAddr;
       End;
    End;
  End
  Else
  Begin
    CInc4 := Cycles[Opcode];
    CInc1 := CInc4;
    CInc2 := CInc4;
    CInc3 := CInc4;
    Addr1 := LastAddr;                   { Absolute/Indirect X }
    Addr2 := LastAddr;
    Addr3 := LastAddr;
  End;

  CInc1 := CInc1 * 3;
  CInc2 := CInc2 * 3;
  CInc3 := CInc3 * 3;
  CInc4 := CInc4 * 3;

  { Get rid of any addresses that are below the RAM range }

  If Addr3 < $1000 Then
  Begin
    Addr3 := LastAddr;
    CInc3 := CInc4;
  End;
  If Addr2 < $1000 Then
  Begin
    Addr2 := Addr3;
    CInc2 := CInc3;
  End;
  If Addr1 < $1000 Then
  Begin
    Addr1 := Addr2;
    CInc1 := CInc2;
  End;

  Inc(TIA_Count,CInc1);
  If TIA_Count >= 160 Then
  Begin
    Dec(TIA_Count,228);
    Inc(TIA_Scan);
  End;

  { Check to see if we already have the value to write }

  If SPWrite Then
  Begin
    SPWrite := False;

    { If writing isn't enabled and it's not a bank switch, save this as a }
    { new write value intead if possible                                  }

    C1 := TIA_Count;
    S1 := TIA_Scan;
    If TIA_Scan > S0 Then Inc(C1,228 * (TIA_Scan - S0));

    If  (TIA_Scan < S0) Or
        ((TIA_Scan = S0) And (C1 < C0 + 12)) Or
        (C1 > C0 + 18) Or

       ((Addr1 <> $1FF8) And

       (((SPBankNum And 2) = 0) Or
        ((Addr1 >= $1800) And ((SPBankNum And 8) = 0))) )  Then
    Begin

      { Find the first address that accesses 1000-10FF }

      GetWrite;
{$IFDEF LOG}
      WriteLn(Listing);
{$ENDIF}
    End
    Else
    Begin
      Addr1 := LastAddr;

      { Write to the location }

{$IFDEF LOG}
      WriteLn(Listing,'   * --> ',HexWord(Addr1) + ' Last= ' + HexWord(LastAddr));
{$ENDIF}
      If Addr1 <> $1FF8 Then AtariSeg[Addr1] := SPWriteVal;
      If Addr1 = $1FF8 Then
      Begin
        Move(AtariSeg[$1000],
             ROMBackup[SP1[(SPBankNum Shr 2) And 7] + SPSearch],$800);
        Move(AtariSeg[$1800],
             ROMBackup[SP2[(SPBankNum Shr 2) And 7] + SPSearch],$800);

        SPBankNum := SPWriteVal;
        Move(ROMBackup[SP1[(SPBankNum Shr 2) And 7] + SPSearch],
             AtariSeg[$1000],$800);
        Move(ROMBackup[SP2[(SPBankNum Shr 2) And 7] + SPSearch],
             AtariSeg[$1800],$800);

        { If the ROM bank was loaded, fill it in with my routine }

        If SP2[(SPBankNum Shr 2) And 7] = $1800 Then
        Begin
          AtariSeg[$1800] := $4C;   { JMP 0E00 }
          AtariSeg[$1801] := $00;
          AtariSeg[$1802] := $0E;
        End;

        HandleStarpath := True;
        SPBank         := SPBankNum;

        If Addr1 <> $1FF8 Then AtariSeg[Addr1] := SPWriteVal;
{$IFDEF LOG}
        WriteLn(Listing);
{$ENDIF}
      End;
    End;
  End
  Else
  Begin
{$IFDEF LOG}
    WriteLn(Listing);
{$ENDIF}
    { Find the first address that accesses 1000-10FF }

    GetWrite;
  End;
End; { HandleStarpath }


Procedure HandlePitfall2(BSValue,Addr,XY,Acc,PC: Word);
Var
  B       : Byte;
  I,W     : Word;
  Opcode  : Byte;
  X       : Word;
  Y       : Word;
  Value   : Integer;
  M       : String[3];

  Function GetSound: Byte;
  Type Ar = Packed Array[0..$7F] Of Byte;
  Var
    _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;
    L        : LongInt;
    P        : ^Ar;

  Begin
    P := Pointer(LongInt(@AtariSeg) + $1000);
    Asm
      MOV   EDI,DWORD PTR P

      { Create a three-byte mask }

      MOV   ESI,0FFFFFFh

      { Retrieve the sound parameters }

      MOV   EAX,DWORD PTR WaveLen
      MOV   EBX,DWORD PTR Pulse
      MOV   ECX,DWORD PTR Phase
      MOV   EDX,DWORD PTR Signal

      { AND with the mask to ensure that the fourth byte is zero }

      AND   EAX,ESI
      AND   EBX,ESI
      AND   ECX,ESI
      AND   EDX,ESI

      { Write the masked bytes to local copies }

      MOV   DWORD PTR _WaveLen,EAX
      MOV   DWORD PTR _Pulse,EBX
      MOV   DWORD PTR _Phase,ECX
      MOV   DWORD PTR _Signal,EDX

      { Get the new parameters }

      MOV   EAX,DWORD PTR [EDI + 45h]
      MOV   EBX,DWORD PTR [EDI + 4Dh]
      MOV   ECX,DWORD PTR [EDI + 55h]
      MOV   EDX,DWORD PTR [EDI + 5Dh]

      { AND the new parameters with the byte masks }

      AND   EAX,ESI
      AND   EBX,ESI
      AND   ECX,ESI
      AND   EDX,ESI

      { Write the new parameters, forcing them to be in range }

      MOV   DWORD PTR WaveLen,EAX
      SHR   EDX,4
      MOV   DWORD PTR Pulse,EBX
      AND   EDX,03030303h
      MOV   DWORD PTR Phase,ECX
      MOV   DWORD PTR Signal,EDX

      { Use ESI as a status variable }

      SUB   ESI,ESI

      { See if any parameters have changed }

      CMP   EAX,DWORD PTR _WaveLen
      JNE   @L1
      CMP   EBX,DWORD PTR _Pulse
      JNE   @L1
      CMP   ECX,DWORD PTR _Phase
      JNE   @L1
      CMP   EDX,DWORD PTR _Signal
      JNE   @L1
      JMP   @L2
@L1:
      INC   ESI
@L2:
      MOV   DWORD PTR L,ESI
    End; { Asm }
    If L <> 0 Then GetSound := AudC[0] Xor 1 Else GetSound := AudC[0];
  End; { GetSound }

Begin
  If BSValue = $CE Then
  Begin
    If (Addr >= $1008) And (Addr <= $103F) Then
    Begin
      I := Addr And 7;
      If Addr >= $1038 Then
      Begin
        B := $FF;
        Dec(PF2Read[I]);
      End
      Else
       If Addr >= $1028 Then
       Begin
         B := PF2Dump[(PF2Read[I] And $7FF)];
         Dec(PF2Read[I]);
       End
       Else
        If Addr >= $1020 Then
        Begin
          B := PF2Dump[(PF2Read[I] And $7FF)];
          Asm
            MOV  AL,B
            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  B,AH
          End; { Asm }
          Dec(PF2Read[I]);
        End
        Else
         If Addr >= $1018 Then
         Begin
           B := PF2Dump[(PF2Read[I] And $7FF)];
           B := (B Shr 4) + (B Shl 4);
           Dec(PF2Read[I]);
         End
         Else
          If Addr >= $1010 Then
          Begin
            B := PF2Dump[(PF2Read[I] And $7FF)];
            If PF2Read[I] = PF2Read[I + 8]  Then PF2ReadB[I] := True;
            If PF2Read[I] = PF2Read[I + 16] Then PF2ReadB[I] := False;
            If Not PF2ReadB[I] Then B := 0;
            Dec(PF2Read[I]);
          End
          Else
           If Addr >= $1008 Then
           Begin
             B := PF2Dump[(PF2Read[I] And $7FF)];
             Dec(PF2Read[I]);
           End;
      AtariSeg[Addr]        := B;
      AtariSeg[Addr + $800] := B;
      PF2Read[I + 8]  := (PF2Read[I + 8]  And $FF) + (PF2Read[I] And $700);
      PF2Read[I + 16] := (PF2Read[I + 16] And $FF) + (PF2Read[I] And $700);
    End
    Else
     Begin
       If Addr = $1006
        Then AtariSeg[$1006] := GetSound
        Else
         If (Addr >= $1000) And (Addr <= $1003) Then
         Begin
           AtariSeg[Addr] :=
            PF2Dump[2048 + Rand[Addr - $1000]];
           Inc(Rand[Addr - $1000]);
           If Rand[Addr - $1000] = 255 Then Rand[Addr - $1000] := 0;
         End;
     End;
  End
  Else
   If BSValue = $CF Then
   Begin
     If (Addr >= $1040) And (Addr <= $105F){ And ((Addr And 7) < 5)} Then
     Begin
       Opcode := AtariSeg[PC];
       X      := XY And $FF;
       Y      := XY Shr 8;
       Value  := -1;
       M      := Mnem[Opcode];
       Asm
         MOV   AX,WORD PTR M[1]
         MOV   WORD PTR W,AX
         MOV   AL,BYTE PTR M[3]
         MOV   BYTE PTR B,AL
       End; { Asm }
       If W = $5453 Then      { "ST" }
       Begin
         If B = 65 Then Value := Acc Else  { "A" }
          If B = 88 Then Value := X Else   { "X" }
           If B = 89 Then Value := Y;      { "Y" }
         If Value >= 0 Then
         Begin
           AtariSeg[Addr] := Value;

           If (Addr And 7 >= 5) Then
           Begin
             SPWave[(Addr And 7) - 4] := 0;
             _Wave[(Addr And 7) - 4] := 0;
           End;

{$IFDEF P2LOG}
            WriteLn(Listing,HexByte(Value),' --> [',HexWord(Addr),']');
{$ENDIF}
           If (Addr And 7) < 5 Then
           Begin
             I := Addr And 7;
             If (Addr And $10) <> 0 Then
             Begin
               If (Addr And 8) = 0
                Then PF2Read[I] := (PF2Read[I] And $700) + Value
                Else
                Begin
                  PF2Read[I]      := (PF2Read[I]      And $FF)   + ((Value Shl 8) And $700);
                  PF2Read[I + 8]  := (PF2Read[I + 8]  And $FF)   + ((Value Shl 8) And $700);
                  PF2Read[I + 16] := (PF2Read[I + 16] And $FF)   + ((Value Shl 8) And $700);
                  PF2ReadB[I] := False;
                End;
             End
             Else
             Begin
               If (Addr And 8) = 0
                Then PF2Read[I + 8]  := (PF2Read[I + 8]  And $700) + Value
                Else PF2Read[I + 16] := (PF2Read[I + 16] And $700) + Value;
             End;
           End;
         End;
       End;
     End;
   End;
End; { HandlePitfall2 }


Procedure FillDump(Const P: Array Of Byte);
Var
  D   : Packed Array[0..2047] Of Byte;
  I,J : Integer;

Begin
  Move(P[8192],D,2048);
  Move(P[8192 + 2048],PF2Dump[2048],255);
  J := 2047;
  For I := 0 To 2047 Do
  Begin
    PF2Dump[I] := D[J];
    Dec(J);
    If J < 0 Then J := 2047;
  End; { For I }
End; { FillDump }

Procedure InitStarpath;
Begin
  SPWrite        := False;
  SPWriteVal     := 0;
  SPBoot         := False;
  SPBank         := 0;
  SPSearch       := 0;
  C0             := 0;
  S0             := 0;
  C1             := 0;
  S1             := 0;
  SPOfs          := 0;
  Game.SPBankNum := 0;
  Game.SPBoot    := False;
  Game.SPBank    := 0;
  Game.SPSearch  := 0;
  FillChar(SPWave,SizeOf(SPWave),#0);
End; // InitStarpath

Initialization
{$IFDEF LOG }
  Assign(Listing,'STARPATH.LOG');
  ReWrite(Listing);
{$ENDIF}
{$IFDEF P2LOG }
  Assign(Listing,'PITFALL2.LOG');
  ReWrite(Listing);
{$ENDIF}
  FillChar(Rand,SizeOf(Rand),#0);
  FillChar(PF2ReadB,SizeOf(PF2ReadB),#0);
Finalization
{$IFDEF LOG}
  Flush(Listing);
  Close(Listing);
{$ENDIF}
{$IFDEF P2LOG}
  Flush(Listing);
  Close(Listing);
{$ENDIF}
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.
// ----------------------------------------------------------------------