ONE LINER: Vaporshow

Did you ever want to test whether there are any active bits at an unknown address or memory-mapped-IO port?  This one-liner uses vaporlock to distinguish active bits vs floating bits on the Apple data bus.

 

*0300:A0 00 A9 08 84 3C 85 3D

*0308:A9 1C 84 3E 85 3F A9 AA

*0310:91 3C 49 FF AA 20 BA FC

*0318:8A 90 F5 8D 55 C0 F1 42

*0320:B1 42 D1 42 D0 FC 51 42

*0328:20 41 FE 8D 54 C0 4C 48

*0330:F9

*BSAVE CMD.VAPORSHOW,A$300,L$31

 

Use Vaporshow to test an address by entering the target address to the left of a less-than sign, and ending the line with "300G" as shown in the test examples below.  Vaporshow prints two bytes, with the first byte indicating which bits are floating (0 bits are valid, 1 bits are floating) and the second byte showing the contents of the address.

 

Here's how it works, crammed into one complicated diagram...

 

Vaporshow works by filling text page 2 with a parity pattern that ensures every bit of every video byte differs from every bit of the previous byte, except when the video scanner repeats one address during horizontal blanking.  So, when text page 2 is displayed, all floating bits are continuously changing with odd-even-odd timing...except at that one repeated address at the horizontal-blanking boundary.

The weirdest part of Vaporshow is the LDA-CMP-BNE loop, whose instructions are timed so that the CMP instruction executes at the opposite parity of the LDA instruction.  If the entire byte is valid, then the byte accessed by the CMP will exactly match the byte accessed by LDA, so the program will simply conitnue.  But if the byte contains any floating bits, then those particular bits will be flipped when the CMP accesses them and the loop will repeat.  In that case the loop repeats until the video scanner has enumerated that one repeated address at the horizontal-blanking boundary, at which point the CMP starts reading bytes of the opposite timing parity as before.  Once that occurs, the loop exits and immediately executes an EOR, which is now timed to read the opposite parity as the previous LDA operation.

Here's how the "magic" loop behaves with three test addresses: C000, C030, and C061

 

Vaporshow helps reveal where simpler emulators behave differently from real hardware because they don't simulate the floating bus, with the result that they don't ever show any floating bits.  In this example below, javascript-based Apple//jse doesn't have any floating bits so the game controller ports show as 8 valid bits (00) instead of 1 valid bit and 7 floating bits (7F).  It also reveals that the game controller addresses aren't duplicated like the original hardware, so this emulator won't behave like real hardware with BASIC programs that use the PDL() functions to read the controller buttons.

 

For comparison, if we run those same commands on a real Apple II motherboard, it shows 1 valid bit and 7 floating bits (7F) because the high bit, and only the high bit, is a valid flag bit while the other seven bits are floating.  It also demonstrates that the game controller addresses are duplicated in the address space, which enables BASIC programs to use PDL() functions to read the controller buttons.
Content Type: