apple2ts icon indicating copy to clipboard operation
apple2ts copied to clipboard

Apple 2TS does not work on the sample WOZ images provided in applesauce

Open univta0001 opened this issue 1 year ago • 7 comments
trafficstars

Hi, some of the woz images from Applesauce (http://evolutioninteractive.com/applesauce/woz_images.zip) are not working with Apple2TS.

Some of non-working titles

  1. Blazing Paddles (incorrect cross track synchronization)
  2. Miner 2049er II
  3. Wings of Fury - Disk 1

univta0001 avatar Aug 28 '24 10:08 univta0001

Balance of Power - fails cross-track sync check on track 35, see https://github.com/AppleWin/AppleWin/issues/1022 Blazing Paddles - stuck at track 0/0.5 - this might be an unenhanced ROM issue? Miner 2049er - oscillates between tracks 0-3 Sammy Lightfoot - boots to title screen, press , just reboots - cross track sync Wings of Fury - just boots to Applesoft

Bilestoad - works Bouncing Kamungas - works DOS 3.3 - works Hard Hat Mack - works Print Shop Companion - works Rescue Raiders - works Mr. Do - works

ct6502 avatar Sep 15 '24 03:09 ct6502

Balance of Power - works Blazing Paddles - works Miner 2049er - works due to same commit that fixed Balance of Power: https://github.com/ct6502/apple2ts/commit/743fcb78721111996fa9b843af47f323e05232c6 Sammy Lightfoot - works Wings of Fury - still just boots to Applesoft

ct6502 avatar Sep 20 '24 04:09 ct6502

For the wings of fury, it does not works probably is due to incorrect handling of softswitch $C08D as mentioned in the readme that is shown below.

READING OFFSET DATA STREAMS

Some programs will reset the data latch mid way through a nibble (via LDA $C08D,x). This will cause the incoming data stream to read offset from the normal nibble starts. These streams will usually incorporate timing bits between nibbles that will not become data bits instead. Some good test candidates for this are "Wings of Fury" and "Stickybear Town Builder". If you can get to the title screens, then you have passed.

univta0001 avatar Sep 20 '24 12:09 univta0001

Where was that README from?

ct6502 avatar Sep 20 '24 13:09 ct6502

You can find the readme.txt under the folder woz test images in the woz_images.zip. It is also mentioned in WOZ 2.1 reference under the section "Abusing Disk Controller Soft Switches for Fun and Profit". The Wings of Fury has apparently implemented E7 protection.

For convenience, here is the paragraph from the WOZ 2.1 reference site,

Another nuance that needs to be implemented is that reading $C08D,X will reset the sequencer and clear the contents of the data latch. This is used to great effect in the E7 protection scheme to resynchronize the nibble stream to make timing bits become valid data bits.

univta0001 avatar Sep 20 '24 14:09 univta0001

Your implementation on LATCH_ON do fixes some games with E7 protection (for e.g. G.I JOE and Ikari Warriors).

For Wings of Fury, it does pass the initial E7 protection. I got stuck at track 2.

  1. It passes the detection of initial EE
  2. It then read 7 bytes and put into data memory 0xf0. The values tallies with values obtained from MAME / AppleWin.

univta0001 avatar Sep 21 '24 01:09 univta0001

I had to uncomment some code in the $C08D,X data latch. Now Wings of Fury gets past track 0, and gets stuck on track 2. Putting a breakpoint at $6E21 shows that it reads the first few chunks of data and then goes off the rails. Need to compare with Virtual ][ to see where my emulator deviates...

ct6502 avatar Sep 21 '24 04:09 ct6502

The implementation of resetting of the data register at $C08D,X sometimes do not work if the value is greater than 0. This is observed in one of the WOZ test images called Stickybear Town Builder. Because the data register is non zero, this software will hang after clicking Build Town option.

One possible fix is change the current code


if (value >= 0) {
     dataRegister = value
}

to the following


if (ds.writeMode && value >= 0) {
     dataRegister = value
}

univta0001 avatar Apr 19 '25 09:04 univta0001

The problem code is at hex $0359, where it does a STA $C08D,X. A=$AD No idea why it is trying to load the write data latch during a read, but you are correct, this is definitely a problem. Image

ct6502 avatar Apr 19 '25 16:04 ct6502

Current status as of 4/19/2025:

All these work, added unit tests: Balance of Power Blazing Paddles King's Quest Miner 2049er (briefly broken as part of fix for #134) Sammy Lightfoot

Stickybear Town Builder also works fine now, but no unit test because it requires user interaction to get to where it was hanging.

Wings of Fury - gets to track 2, then infinite loop around address $6Cxx.

ct6502 avatar Apr 20 '25 04:04 ct6502

I had to uncomment some code in the $C08D,X data latch. Now Wings of Fury gets past track 0, and gets stuck on track 2. Putting a breakpoint at $6E21 shows that it reads the first few chunks of data and then goes off the rails. Need to compare with Virtual ][ to see where my emulator deviates...

Hi, i have taken a look at why Wings of Fury is hung at track 2. The code failed at 0x6c10 where the expected value is 0x96 but return 0xe5. I have tabulated it for Apple2TS (left side) vs my emulator (right side). Apple2TS should read 0x96 at bit location 943

Cycle C0EC Value Bit Location Diff Cycle Cycle C0EC Value Bit Location Diff Cycle
3045844 0xff 831 3160510 0xff 832
3045883 0xff 841 39 3160549 0xff 842 39
3045922 0xff 851 39 3160588 0xff 852 39
3045961 0xff 861 39 3160627 0xff 862 39
3046007 0xff 871 46 3160666 0xff 871 39
3046039 0xd5 879 32 3160698 0xd5 879 32
3046065 0x9d 887 26 3160731 0x9d 888 33
3046098 0x9a 895 33 3160764 0x9a 896 33
3046130 0x97 903 32 3160796 0x97 904 32
3046162 0x9b 911 32 3160828 0x9b 912 32
3046199 0xaa 919 37 3160858 0xaa 919 30
3046287 0xe5 941 88 3160953 0x96 943 95

On further inspection of Apple2TS code, i noticed that in diskdata.ts line 178

if (dataRegister & 128 && cycleRemainder <= 6) break

If this line of code is changed to the line below, it will work. Setting the cutoff to 70 also works. In both cases, this modified setting will break some other images

if (dataRegister & 128) break

univta0001 avatar May 13 '25 13:05 univta0001

Hi, finally manage to solve Wings of Fury, just changing the getNextByte function from

      if (dataRegister > 0 || bit) {
        dataRegister = (dataRegister << 1) | bit
      }

to

      if (dataRegister > 0 || bit) {
        if (dataRegister & 128) {
            dataRegister = 0
        }
        dataRegister = (dataRegister << 1) | bit
      }

The extra condition is required so that the data register is cleared when the data register high bit is set.

univta0001 avatar May 14 '25 07:05 univta0001

Hi, also tested one round with all the WOZ 2.0 images. All are working except for the following

  1. DOS 3.2 System Master.woz (Apple2ts is using P6 ROM)
  2. First Math Adventures - Understanding Word Problems (Apple2ts is clearing the data register to 0. Refer to the WOZ test image readme)
  3. PlanetFall (cycleRemainder <= 6 fails, working is cycleRemainder <= 8)
  4. Border Zone (Works but with bit timing of 4us, Loading time is around 50s. This image is with bit timing 3.5us. The expected loading time is 18s)
  5. The Print Shop Companion - Disk 1, Side A (Works but very slow in firefox)

univta0001 avatar May 14 '25 12:05 univta0001

The code below should be able to address point 2. and 3.

const getNextByte = (ds: DriveState, dd: Uint8Array, cycles: number) => {
  // const tracklocSave = ds.trackLocation
  // If no disk then return random noise from the drive.
  // Some programs (like anti-m) use this to check if no disk is inserted.
  if (dd.length === 0) return randByte()
  let result = 0

  // Read individual bits and combine them.
  cycleRemainder += cycles

  while (cycleRemainder >= 4) {
    const bit = getNextBit(ds, dd)
    if (!(dataRegister & 0x80 && !bit)) {
      if (dataRegister & 0x80) {
          dataRegister = 0
      }
      dataRegister = (dataRegister << 1) | bit
    }
    cycleRemainder -= 4
    // Changing this cycleRemainder cutoff to less than 6 will break
    // loading certain disks like Balance of Power.
    // 6 - will break Planetfall and Border Zone
    // 8 - will work for all the test images in driverstate.test
    if (dataRegister & 128 && cycleRemainder <= 8) break
  }
  if (cycleRemainder < 0) {
     cycleRemainder = 0
  }
  dataRegister &= 0xFF

  // if (ds.halftrack === 70 && dataRegister > 127) {
  //   console.log(toHex(dataRegister))
  // }
  // if (s6502.PC >= 0x9E45 && s6502.PC <= 0x9E5F) {
  //   console.log(`  getNextByte: ${cycles} cycles PC=${toHex(s6502.PC, 4)} loc=${tracklocSave} dataRegister=${toHex(dataRegister)}`)
  // }
  result = dataRegister
  return result
}

univta0001 avatar May 14 '25 13:05 univta0001

I'm really busy for the next week or so, so I won't be able to look at this until after that, but overall this looks great. I don't see a slowdown with Print Shop Companion, at least not using Chrome. I noticed that you deleted the "fast path" for non-synchronized disks. Does it actually cause any problems, or is it just not that much faster?

ct6502 avatar May 14 '25 14:05 ct6502

The fast path is causing problem, that is why i have deleted it. No worries take your time to make the change. I have also tried updating the getNextByte to support WOZ 2.0 optimalTiming parameter to fix the speed issue of Border Zone. It also fixes on images that rely on non standard bit timing (for e.g. Paul Whitehead Teaches Chess at https://github.com/a2-4am/passport-test-suite/blob/master/Paul%20Whitehead%20Teaches%20Chess.woz

The changes are

-- In diskdata.ts
const getNextByte = (ds: DriveState, dd: Uint8Array, cycles: number) => {
  // const tracklocSave = ds.trackLocation
  // If no disk then return random noise from the drive.
  // Some programs (like anti-m) use this to check if no disk is inserted.
  if (dd.length === 0) return randByte()
  let result = 0

  // Read individual bits and combine them.
  cycleRemainder += cycles

  while (cycleRemainder >= ds.optimalTiming / 8) {
    const bit = getNextBit(ds, dd)
    if (!(dataRegister & 0x80 && !bit)) {
      if (dataRegister & 0x80) {
          dataRegister = 0
      }
      dataRegister = (dataRegister << 1) | bit
    }
    cycleRemainder -= (ds.optimalTiming / 8) 
    // Changing this cycleRemainder cutoff to less than 6 will break
    // loading certain disks like Balance of Power.
    if (dataRegister & 128 && cycleRemainder <= (ds.optimalTiming / 4)) break
  }
  if (cycleRemainder < 0) {
     cycleRemainder = 0
  }
  dataRegister &= 0xFF

  // if (ds.halftrack === 70 && dataRegister > 127) {
  //   console.log(toHex(dataRegister))
  // }
  // if (s6502.PC >= 0x9E45 && s6502.PC <= 0x9E5F) {
  //   console.log(`  getNextByte: ${cycles} cycles PC=${toHex(s6502.PC, 4)} loc=${tracklocSave} dataRegister=${toHex(dataRegister)}`)
  // }
  result = dataRegister
  return result
}
-- drivestate.ts 

const initDriveState = (index: number, drive: number, hardDrive: boolean): DriveState => {
  return {
    index: index,
    hardDrive: hardDrive,
    drive: drive,
    status: "",
    filename: "",
    diskHasChanges: false,
    motorRunning: false,
    isWriteProtected: false,
    isSynchronized: false,
    halftrack: 0,
    prevHalfTrack: 0,
    writeMode: false,
    currentPhase: 0,
    trackStart: hardDrive ? Array<number>() : Array<number>(80).fill(0),
    trackNbits: hardDrive ? Array<number>() : Array<number>(80).fill(51024),
    trackLocation: 0,
    maxHalftrack: 0,
    lastLocalWriteTime: -1,
    cloudData: null,
    writableFileHandle: null,
    lastWriteTime: -1,
    optimalTiming: 32,
  }
}

-- decodedisk.ts

const decodeWoz2 = (driveState: DriveState, diskData: Uint8Array): boolean => {
  const woz2 = [0x57, 0x4F, 0x5A, 0x32, 0xFF, 0x0A, 0x0D, 0x0A]
  const isWoz2 = woz2.find((value, i) => value !== diskData[i]) === undefined
  if (!isWoz2) return false
  driveState.isWriteProtected = diskData[22] === 1
  driveState.isSynchronized = diskData[23] === 1
  driveState.optimalTiming = diskData[59]

univta0001 avatar May 14 '25 15:05 univta0001

Thanks @univta0001 for all the help and the code. That final code block seemed to fix a lot more issues, and now even Wings of Fury boots! I'm going to close this bug. If we find other disk images that don't work, let's open a new issue.

ct6502 avatar Jul 12 '25 16:07 ct6502