diff --git a/README.md b/README.md new file mode 100644 index 0000000..c5ea120 --- /dev/null +++ b/README.md @@ -0,0 +1,2999 @@ +# Fantavision Reloaded + +# Table of Contents + +* Introduction +* Preparation +* ESC to Bug out +* Ye Olde Boot Tracing + * P5 Boot PROM +* Boot Tracing Stage 1b +* Boot Tracing Stage 2 +* Boot Tracing Stage 3 +* Time to go Loco, er, Logo + * Logo -- no, not the language + * Logo 2 + * Logo 3 ! + * Logo 4 !! +* _"What this, **Byte-Code,** you say young chap?"_ + * Backup 1 + * Backup 2 + * Backup Byte-Code Interpreter + * Backup 1 Disassembly + * Backup 2 Disassembly +* Applesoft?! + * Applesoft Tokens +* Boot Tracing Stage 5 +* Boot Tracing Stage 6 + * Boot Stage Memory Map +* Disk Information + * Notes + * COPY, eh? + * ProDOS Hybrid!? + * ProDOS Block Review + * Disk Usage Details + * Disk Usage Summary +* Easter Eggs + * Source Code + * Original File Names + * Deleted Files!? +* In Search of a Better Beep, or two + +# Introduction + +_"Get off my LAN, Grandpa"_ + +Before Macromedia's [Flash](https://en.wikipedia.org/wiki/Adobe_Flash) +became ubiquitous back in 1985 +[Brøderbund](https://en.wikipedia.org/wiki/Broderbund) +released a fantastic animation program called `Fantavision` + +* ![Logo](pics/logo.png) + +* TODO: PIC: Disk + +* TODO: PIC: Box + +* TODO: PIC: Manual + +Back then I had many unanswered questions about it: + +* Where is the Logo stored on disk? +* Where are the (bitmap) icons stored in memory? +* How is the (mouse) cursor drawing code done? +* What is the movie file format? +* How is it copy-protected? +* How could we remove the copy-protection? +* How does the backup utlity know if a copy has been made? + +Let's have some fun exploring these. Along the way we'll discover: + +* Boot Tracing +* Learn HOW Fantavision is actually copy-protected +* Restore the "Backup Functionality" by writing an "UNBACKUP" program +* Use COPYA to copy it so we can inspect it with any Sector Editor + * Trivially crack it +* Easter Eggs + +Let's get started! + + +# Preparation + +Before we get started, first a word from our sponsor, er, experience. + +**WARNING:** _ALWAYS_ write-protect your **original disk** to prevent (accidental) mistakes from happening! + +No, _I've_ never done that, but it is WAY too easy to make this mistake. +Take the 30 seconds (of insurance). You won't regret the peace of mind it will bring. + +With that warning out of the way: + +Let's create a blank DOS 3.3 data disk that we'll use to save our work-in-progress. + +1. Boot your favorite "Fast" DOS such as ProntoDOS or Diversi-DOS. + +2. Replace the disk with a blank floppy. + +3. Enter these lines: + +``` + NEW + 10 ?CHR$(4);"CATALOG" + INIT HELLO +``` + +4. Remove it from the disk drive and label it as `Fanta.Work` + + + +# ESC to Bug Out + +You may or may not know that while Fantavision boots up +one can hold `ESC` down to enter the built-in backup utility! + +Sadly, most originals will show this screen: + +* ![Backup used](pics/backup_used.png) + +What we want is this picture: + +* ![Backup available](pics/backup_available.png) + +Now my //e has 3 disk drives, two connected on Slot 6, and one on Slot 5. +For fun let's boot Fantavision from drive 5 and enter the backup utility. + +We get the message: + +``` +Make sure that the Fantavision disk is in slot 5, drive 1 +``` + +OK. + +Pressing `RETURN` and it reboots from slot 6. Whoops! +The programmer detected which slot it was started from but were lazy +and didn't properly "exit" (JMP) to the right slot. + +If we were really bored we could write some boot sector tools +on the blank disk in slot 6 and "chain" reverse engineering +but let's take the more traditional approach. + +# Ye Olde Boot Tracing + +1. If you computer isn't already on, turn it on and press `CTRl-RESET` + +2. Insert the original Fantavision disk in Slot 6, Drive 1 + +3. Type these instructions: + +``` + CALL-151 + 9600LoadBoot3 ; Load T$22 4&4 "4 sectors" @ $BC00, $BD00, $BE00, $BF00 +0879:20 00 B5 JSR ReadBoot3 ; Boot Stage 2 reads in encrypted Stage 3 +087C:B0 F5 BCS TestBoot3 ;^ $0873 C=1 error, Hang if NibbleCheck1 fails +087E:4C 00 BE JMP ExecBoot3 ; + + HalfTrackSeek: ; A = Half Track to Seek +0881:85 50 STA SEEK_HALFTRACK ; Save Half Track to seek + + NextTrack: ; +0883:A5 FF LDA RWTS_HALFTRACK ; 6502 Math Reminder: +0885:85 51 STA HAVE_HALFTRACK ; Clear Carry before Addition +0887:38 SEC ; Set Carry before Subtraction +0888:E5 50 SBC SEEK_HALFTRACK ; Already on requested track? +088A:F0 2C BEQ SeekDone ;v $08B8 Yup! Nothing to do! +088C:B0 04 BCS MoveTrackOut ;v $0892 Move Track out to Track $00 + + MoveTrackIn: +088E:E6 FF INC RWTS_HALFTRACK ; Move Track in to Track $22 +0890:90 02 BCC DoSeek ;v $0894 Always, could also do: INC RWTS_HALFTRACK + + MoveTrackOut: +0892:C6 FF DEC RWTS_HALFTRACK ; Intentional fall-into DoSeek + + DoSeek: ; Common code +0894:20 AD 08 JSR PhaseOn ;v +0897:20 B9 08 JSR Delay ;v + PhaseOff: +089A:A5 51 LDA HAVE_HALFTRACK ; +089C:29 03 AND #PHASEMASK ; Drive Stepper Motor = 4 Phases +089E:0A ASL ; 1 phase = 1/2 track +089F:05 2B ORA P5.SlotX16 ; +08A1:A8 TAY ; +08A2:B9 80 C0 LDA PHASEOFF,Y ; Turn stepper motor off +08A5:20 B9 08 JSR Delay ;v +08A8:F0 D9 BEQ NextTrack ;^ $0883 A=00, always +08AA:20 B9 08 JSR Delay ;v *** DEAD CODE ??? Never reached! + PhaseOn: +08AD:A5 FF LDA RWTS_HALFTRACK ; +08AF:29 03 AND #PHASEMASK ; +08B1:0A ASL ; 1 phase = 1/2 track +08B2:05 2B ORA P5.SlotX16 ; +08B4:A8 TAY ; +08B5:B9 81 C0 LDA PHASEON,Y ; Turn stepper motor on + SeekDone: +08B8:60 RTS ; + Delay: +08B9:A9 28 LDA #$28 ; You _could_ minimize the delay time like in DOS 3.3 +08BB:4C A8 FC JMP WAIT ; but that bloats the code + + LogicalSector: ; Logical->Phystical Sector = Interleave 2 + +08BE:00 0D 0B 09 DFB $00,$0D,$0B,$09,$07,$05,$03,$01 +08C2:07 05 03 01 +08C6:0E 0C 0A 08 DFB $0E,$0C,$0A,$08,$06,$04,$02,$0F +08CA:06 04 02 0F + + DestPage: +08CE:B0 B1 B2 B3 DFB $B0,$B1,$B2,$B3,$B4,$B5,$B6,$B7 ; "Pages" of 16-bit address +08D2:B4 B5 B6 B7 +08D6:18 19 1A 1B DFB $18,$19,$1A,$1B,$1C,$1D,$1E,$1F ; to load into +08DA:1C 1D 1E 1F + DS $900-* ; unused/wasted +08DE:00 00 ; +08E0:00 00 00 00 ; +08E4:00 00 00 00 ; +08E8:00 00 00 00 ; +08EC:00 00 00 00 ; +08F0:00 00 00 00 ; +08F4:00 00 00 00 ; +08F8:00 00 00 00 ; +08FC:00 00 00 00 ; +``` + +## P5 Boot PROM + +The boot sector contains code to: + +* `Seek a Track`, and +* `Read a Track`. + +Who knew we would already have 75% of `RWTS` -- Read, Write, Track, Sector :-) + +In case you are wondering where `Sector` comes from -- +it comes from the P5 PROM ReadSector routine @ $C65C. +On my //e it looks this: + +``` + ORG $C65C + + P5.ReadSector +C65C:18 ^0 CLC ; C=0 Look Address D5,AA,96 +C65D:08 ^1 PHP ; C=1 look Data D5,AA,AD + +C65E:BD 8C C0 ^2 LDA DRIVE_DATA,X +C661:10 FB BPL ^2 ;^ $C65E +C663:49 D5 ^3 EOR #$D5 ; Address 1st Prologue Field +C665:D0 F7 BNE ^2 ;^ $C65E + +C667:BD 8C C0 ^4 LDA DRIVE_DATA,X +C66A:10 FB BPL ^4 ;^ $C667 +C66C:C9 AA CMP #$AA ; Address 2nd Prologue Field +C66E:D0 F3 BNE ^3 ;^ $C663 +C670:EA NOP + +C671:BD 8C C0 ^5 LDA DRIVE_DATA,X +C674:10 FB BPL ^5 ;^ $C671 +C676:C9 96 CMP #$96 ; Address 3rd Prologue Field, NOTE: C=1 for $C68C ! +C678:F0 09 BEQ ^6 ;v $C683 + +C67A:28 PLP ;Looking for Address or Data prologue? +C67B:90 DF BCC ^0 ;^ $C65C +C67D:49 AD EOR #$AD ; Prologue Data Field: 3rd +C67F:F0 25 BEQ ^10 ;v $C6A6 +C681:D0 D9 BNE ^0 ;^ $C65C +C683:A0 03 ^6 LDY #$03 ; Read 3 nibbles: Vol,Track,Sec, skip Checksum +C685:85 40 ^7 STA TrackHave ; Eventually contains Track but init #$96 from $C676 + +C687:BD 8C C0 ^8 LDA DRIVE_DATA,X +C68A:10 FB BPL ^8 ;^ $C687 mask = $FF since: C=1 from $C676 +C68C:2A ROL ; ... 4&4 encoded: 1a1c1e1g, C=1 since A > $80 +C68D:85 3C STA $3C ; ... 1st half A= a1c1e1gC + +C68F:BD 8C C0 ^9 LDA DRIVE_DATA,X +C692:10 FB BPL ^9 ;^ $C68F &= 1b1d1f1h +C694:25 3C AND $3C ; ... 2nd half = abcdefgh +C696:88 DEY +C697:D0 EC BNE ^7 ;^ $C685 +C699:28 PLP ; Don't care about carry, restore stack +C69A:C5 3D CMP SectorWant ; A=SectorHave == SectorWant? (init $00 from $C654) +C69C:D0 BE BNE ^0 ;^ $C65C +C69E:A5 40 LDA TrackHave ; (read from prologue) +C6A0:C5 41 CMP TrackWant ; +C6A2:D0 B8 BNE ^0 ;^ $C65C != +C6A4:B0 B7 BCS ^1 ;^ $C65D <= +C6A6:A0 56 ^10 LDY #$56 ; Decode $56 nibbles in 6&2 +C6A8:84 3C ^11 STY $3C + +C6AA:BC 8C C0 ^12 LDY DRIVE_DATA,X +C6AD:10 FB BPL ^12 ;^ $C6AA +C6AF:59 D6 02 EOR $36C-$96,Y ; [$96] $36C:00, $36C-$96=$2D6 +C6B2:A4 3C LDY $3C ; [$FF] $3D5:3F, $2D6+$FF=$3D5 +C6B4:88 DEY +C6B5:99 00 03 STA $0300,Y ; Buf1 = [$300 .. $35B] +C6B8:D0 EE BNE ^11 ;^ $C6A8 + +C6BA:84 3C ^13 STY $3C ; Y = #FF +C6BC:BC 8C C0 ^14 LDY DRIVE_DATA,X +C6BF:10 FB BPl ^14 ;^ $C6BC +C6C1:59 D6 02 EOR $36C-$96,Y +C6C4:A4 3C LDY $3C +C6C6:91 26 STA ($26),Y +C6C8:C8 INY +C6C9:D0 EF BNE ^13 ;^ $C6BA +C6CB:BC 8C C0 ^15 LDY DRIVE_DATA,X +C6CE:10 FB BPL ^15 +C6D0:59 D6 02 EOR $36C-$96,Y +C6D3:D0 87 ^16 BNE ;^ $C65C + +C6D5:A0 00 LDY #$00 +C6D7:A2 56 ^17 LDX #$56 +C6D9:CA ^18 DEX +C6DA:30 FB BMI ^17 ; $C6D7 +C6DC:B1 26 LDA ($26),Y +C6DE:5E 00 03 LSR $0300,X +C6E1:2A ROL +C6E2:5E 00 03 LSR $0300,X +C6E5:2A ROL +C6E6:91 26 STA (P5.Buff),Y +C6E8:C8 INY +C6E9:D0 EE BNE ^18 ;^ $C6D9 + +C6EB:E6 27 INC P5.Buff+1 ; DestAddr += $0100 +C6ED:E6 3D INC P5.SecLoaded; SectorsLoaded++ +C6EF:A5 3D LDA P5.SecLoaded +C6F1:CD 00 08 CMP P5.SecTotal ; SectorsLoaded <= SectorsTotal ? +C6F4:A6 2B LDX P5.SLOTx16 ; +C6F6:90 DB BCC ^16 ;^ $C6D3 + +C6F8:4C 01 08 JMP $0801 ; $0800 = Num of Sectors to read +C6FB:00 DS $C700-* ; unused last 5 bytes +C6FC:00 00 00 00 +``` + +Let's map out the Track/Sector (T/S) boot stages + +``` + ; Stage Addr T/S Load + ; --------------------- + ; 0 C600 T00S0 0800 + ; --------------------- + ; 1 0801 + ; --------------------- + ; 2 T15S0 B000 + ; 2 T15SD B100 + ; 2 T15SB B200 + ; 2 T15S9 B300 + ; 2 T15S7 B400 + ; 2 T15S5 B500 + ; 2 T15S3 B600 + ; 2 T15S1 B700 + ; 2 T15SE 1800 + ; 2 T15SC 1900 + ; 2 T15SA 1A00 + ; 2 T15S8 1B00 + ; 2 T15S6 1C00 + ; 2 T15S4 1D00 + ; 2 T15S2 1E00 + ; 2 T15SF 1F00 + ; --------------------- + ; 2 B500 + ; --------------------- + ; ? BE00 T??S? + ; --------------------- + +``` + +# Boot Tracing Stage 1b + +Since we'll be typing in the same commands over and over again +let's make a "Turn-Key" system on our DOS data disk. + +```asm + 1EEE:A2 00 LDX #$00 + 1EF0:BD 00 C6 LDA $C600,X + 1EF3:9D 00 96 STA $9600,X + 1EF6:E8 INX + 1EF7:D0 F7 BNE $1EF0 + 1EF9:A9 1F LDA #$1F ; Stop @ $1F01 + 1EFB:8D FA 96 STA $96FA + 1EFE:4C 00 96 JMP $9600 + 1F01:00 BRK +``` + +That is, + +```asm + CALL-151 + 1EEE:A2 00 BD 00 C6 9D 00 96 + 1EF6:E8 D0 F7 A9 1F 8D FA 96 + 1EFE:4C 00 96 00 +``` + +Save it via: + +``` + BSAVE BOOT.STOP,A$1EEE,L$14 +``` + +And let's make it auto-load when we boot our DOS disk: + +``` + LOAD HELLO + 5 ? CHR$(4);"BLOAD BOOT.STOP" + SAVE HELLO +``` + +However, we need to stop after boot stage 2 has loaded: + +```asm + 1F01:A9 0E LDA #$0E + 1F03:8D 7F 08 STA $087F ; 87E: JMP $BE00 + 1F06:A9 1F LDA #$1F ; -> + 1F08:8D 80 08 STA $0880 ; 87E: JMP $1F0E + 1F0B:4C 01 08 JMP $0801 + 1F0E:00 +``` + +``` + 1EEEG + C0E8:1 + 4000LoadBoot3 ; Load T$22 4&4 "4 sectors" @ $BC00, $BD00, $BE00, $BF00 +0879:20 00 B5 JSR ReadBoot3 ; Boot Stage 2 reads in encrypted Stage 3 +087C:B0 F5 BCS TestBoot3 ;^ $0873 C=1 error, Hang if NibbleCheck1 fails +087E:4C 00 BE JMP ExecBoot3 ; +``` + +Let's disassemble $B500 ... + +```asm + COUNT = $3E ; 16-bit counter + DRIVE_DATA = $C08C ; Read Disk Nibble + + ReadBoot3: +B500:8D 17 B5 STA _B516+1 ; *** SELF-MODIFYING *** DestAddr + ; These 3 bytes are wasted + ; Should just be STA $3D + ; And we can delete $B516..$B518 +B503:A9 22 LDA #$22 ; TRACK_NIBBLE_CHECK +B505:20 09 B0 JSR RWTS_Seek ; +B508:A6 FD LDX RWTS_SLOTx16 ; +B50A:A9 80 LDA #$80 ; Attempt to read $8080 disk nibbles +B50C:85 3E STA Count ; Count +B50E:85 3F STA Count+1 ; +B510:A9 04 LDA #$04 ; Num "Sectors" or Pages to read +B512:85 3B STA NumSectors ; +B514:A0 00 LDY #$00 ; Num disk nibbles read (actually is 1/2) + _B516: +B516:A9 00 LDA #$00 ; *** SELF-MODIFIED @ $B500 *** Dest Addr to Load at +B518:84 3C STY $3C ; +B51A:85 3D STA DestPage ; DestPage + + NextCount: +B51C:C6 3E DEC Count ; Force read counter +B51E:D0 06 BNE DoNibbleCheck1 ; to read at least once +B520:C6 3F DEC Count+1 ; +B522:D0 02 BNE DoNibbleCheck1 ; +B524:38 SEC ; FAIL nibble check 1 +B525:60 RTS ; + + DoNibbleCheck1: + WaitNib1a: ; ^ +B526:BD 8C C0 LDA DRIVE_DATA,X ; | +B529:10 FB BPl WaitNib1a ;^ $B526 | + TestNib1a: ; | +B52B:C9 F5 CMP #$F5 ; $F5 | <--+ +B52D:D0 ED BNE NextCount ;^ $B51C + | + ; | + WaitNib1b: ; | +B52F:BD 8C C0 LDA DRIVE_DATA,X ; | +B532:10 FB BPL WaitNib1b ;^ $B52F | + TestNib1b: ; | +B534:C9 F4 CMP #$F4 ; $F4 | +B536:D0 F3 BNE TestNib1a ;^ $B52B ---+ + + WaitNib1c: +B538:BD 8C C0 LDA DRIVE_DATA,X; +B53B:10 FB BPL WaitNib2b ;^ $B538 + TestNib1c: +B53D:C9 CF CMP #$CF ; $CF +B53F:D0 F3 BNE $B534 + + : +B541:BD 8C C0 LDA $C08C,X ;+ +B544:10 FB BPL $B541 ;^ +B546:2A ROL +B547:85 3A STA $3A +B549:BD 8C C0 LDA $C08C,X ;+ +B54C:10 FB BPL $B549 ;^ +B54E:25 3A AND $3A +B550:91 3C STA ($3C),Y +B552:C8 INY +B553:D0 EC BNE $B541 +B555:0E FF FF ASL $FFFF ; //e = $C3, //c = $C8, Laser128 = ? TODO: FIXME: +B558:BD 8C C0 LDA $C08C,X +B55B:10 FB BPL $B558 ;^ +B55D:C9 D5 CMP #$D5 ; $ D5 +B55F:D0 AF BNE $B510 ;^ +B561:E6 3D INC $3D ; Inc Dest Page +B563:C6 3B DEC NumSectors ; +B565:D0 DA BNE $B541 ;^ +B567:18 CLC ; PASS nibble check 1 +B568:60 RTS +``` + +This first nibble check reads these disk nibbles on Track $22: + + F5 F4 CF + [4&4 x256] [4&4 x256] + D5 + [4&4 x256] [4&4 x256] + D5 + [4&4 x256] [4&4 x256] + D5 + [4&4 x256] [4&4 x256] + D5 + +This is one of the reasons you need a "Bit-Copier" to copy Track $22. +There are no sectors as traditionally defined by `D5 AA 96` and `D5 AA ED`! + +Let's update our Boot Stages Diagram: + +``` + ; Stage Addr TRK/S Load + ; --------------------- + ; 0 C600 T00S0 0800 + ; --------------------- + ; 1 0801 T15 + ; --------------------- + ; 2 T15S0 B000 + ; 2 T15SD B100 + ; 2 T15SB B200 + ; 2 T15S9 B300 + ; 2 T15S7 B400 + ; 2 T15S5 B500 + ; 2 T15S3 B600 + ; 2 T15S1 B700 + ; 2 T15SE 1800 + ; 2 T15SC 1900 + ; 2 T15SA 1A00 + ; 2 T15S8 1B00 + ; 2 T15S6 1C00 + ; 2 T15S4 1D00 + ; 2 T15S2 1E00 + ; 2 T15SF 1F00 + ; --------------------- + ; 1 0873 + ; 2 B500 T22Sx BC00 $F5,$F4,$CF, [ 4&4:512,$D5 ] x4 + ; 2 T22Sx BD00 + ; 2 T22Sx BE00 + ; 2 T22Sx BF00 + ; --------------------- + ; 3 BE00 ? ? + ; --------------------- +``` + +There are many different ways to remove the protection. +The simpliest is to format track $22 normally, +and modify $B500 to load them in. + +That is exactly what Black Bag's "Kracked" version of Fantavision does. +On Track $15, Sector $5 @ $B500 it uses: + +* RWTS_ReadPrologue = $B126 and +* RWTS_ReadSector = $B011 + +to read two sectors on a normal formatted track $22. +_That_ code looks like this: + +``` + LDA #$22 ; B500:A9 22 ; Nibble Check Track been converted to normal sector + JSR RWTS_Seek ; B502:20 09 B0 + LDX #$60 ; B505:A2 60 ; BUG! Hard-Coded to Drive in Slot 6 ! +FindSector0: ; Should be: LDX RWTS_SLOTx16 -> LDX $FD + JSR RWTS_Prologue ; B507:20 26 B1 + LDA RWTS_HAVE_SEC ; B50A:A5 E3 ; Current sector under disk head + CMP #$00 ; B50C:C9 00 ; Look for sector $0 + BNE FindSector0 ; B50E:D0 F7 + STA $E6 ; B510:85 E6 + LDA #$BE ; B512:A9 BE ; Dest Addr = $BE00 + STA $E7 ; B514:85 E7 + JSR RWTS_ReadSec ; B516:20 11 B0 +FindSectorD: + JSR RWTS_Prologue ; B519:20 26 B1 + LDA RWTS_HAVE_SEC ; B51C:A5 E3 + CMP #$0D ; B51E:C9 0D ; Look for sector $D + BNE FindSectorD ; B520:D) F7 + INC $E7 ; B522:E6 E7 + JSR RWTS_ReadSec ; B522:20 11 B0 + CLC ; B527:18 ; Signal $087C Nibble Check = PASS + RTS ; B528:60 +``` + +We will discuss when we remove the copy protection ourselves. + + +# Boot Tracing Stage 3 $BE00 + +The boot sector code @ $087E calls Stage 4 $BE00: + +```asm +087E:4C 00 BE JMP ExecBoot3 ; +``` + +This is the disaassembly + +```asm + ExecBoot3: + BE00:4C 06 BE JMP Main + BE03:4C AD BE JMP DoNibbleCheck2 ; Nibble Check #2: $D4,$D5,$DE,$A5,$xx,$yy,$E5,$AA + Main: + BE06:20 16 BF JSR Verify64K + BE09:20 75 BE JSR $BE75 + BE0C:A0 58 LDY #<$FF58 + BE0E:A9 FF LDA #>$FF58 + BE10:84 36 STA CSW+0 ; CSWL = $36, Char Out Vector (Function Pointer) + BE12:85 37 STA CSW+1 + BE14:A0 1F LDY #NewKSW + BE18:84 38 STY KSW+0 ; KSWL = $38, Char In Vector (Function Pointer) + BE1A:85 39 STA KSW+1 + BE1C:4C 00 E0 JMP BASIC ; BASIC Cold Start + NewKSW: + BE1F:91 28 STA (BAS),Y ; BASL = $28 + BE21:20 89 FE JSR SETKBD ; SETKBD = $FE89 + BE24:20 93 FE JSR SETVID ; SETVID = $FE93 + BE27:A9 16 LDA #$16 ; First Track to Load + BE29:8D 33 BE STA NextTrack+1 ; *** SELF MODIFYING *** + BE2C:20 09 B0 JSR RWTS_Seek + BE2F:A9 08 LDA #$08 ; DestAddr + NextPage: + BE31:48 PHA ;+ Save DestAddr + NextTrack: + BE32:A0 00 LDY #$00 ; *** SELF-MODIFIED @ $BE27 *** + BE34:EE 33 BE INC $BE33 ; *** SELF MODIFYING *** + BE37:20 00 B0 JSR RTWS_LoadTrack + BE3A:68 PLA ; Restore DestAddr + BE3B:18 CLC + BE3C:69 18 ADC #$18 ; We initially loaded at $0800 + BE3E:29 F0 AND #$F0 ; Force to load at start-of-page $2x00, $3x00, etc + BE40:C9 A1 CMP #$A1 ; Load entire $Ax00 page then stop + BE42:90 ED BCC NextPage ;^ $BE31 + + BE44:AC 00 08 LDY $0800 + + BE75:A2 20 LDX #$20 +``` + + +Here is the diassembly of the second nibble check on Track $22. + +```asm + ; Normally $0200 is the keyboard buffer + ; But here it is used as an array of booleans. + ; + ; bool MissingKey[ 256 ]; + ; + False = $00 + True = $FF + + KeyBuf = $0200 + DriveData = $C08C + + DoNibbleCheck2: + BEAD:A0 00 LDY #$00 + BEAF:A9 FF LDA #True ; -1 = True + _Init200 + BEB1:99 00 02 STA KeyBuf,Y ; MissingKey[ $00 .. $FF ] = True + BEB4:C8 INY + BEB5:D0 FA BNE _Init200 ;^ $BEB1 + + _Nib0 + BEB7:A6 FD LDX RWTS_Slotx16 + _Read1: + BEB9:BD 8C C0 LDX DriveData,X + BEBC:10 FB BPL _Read1 ;^ $BEB9 + _Nib1: + BEBE:C9 D4 CMP #$D4 ; Check1 = #$D4 + BEC0:D0 F5 BNE _Nib0 ;^ $BEB7 + BEC2:20 10 BF JSR _NibRead + _Nib2: + BEC5:C9 D5 CMP #$D5 ; Check2 = #$D5 + BEC7:D0 F5 BNE _Nib1 ;^ $BEBE + BEC9:20 10 BF JSR NibRead + _Nib3: + BECC:C9 DE CMP #$DE ; Check3 = #$DE + BECE:D0 F5 BNE _Nib2 ;^ $BEC5 + BED0:20 10 BF JSR NibRead + _Nib4: + BED3:C9 A5 CMP #$A5 ; Check4 = #$A5 + BED5:D0 F5 BNE _Nib3 ;^ $BECC + BED7:EA NOP + _Nib5: + BED8:BD 8C C0 LDA DriveData,X + BEDB:10 FB BPL _Nib5 + BEDD:2A ROL + BEDE:85 26 STA #$26 ; Save CheckYa + _Nib6: + BEE0:BD 8C C0 LDA DriveData,X + BEE3:10 FB BPL _Nib6 + BEE5:25 26 AND $26 ; Save CheckYb in 4&4 format + BEE7:A8 TAY ; Y = Checksum + BEE8:20 10 BF JSR NibRead + BEEB:C9 E5 CMP #$E5 ; Check7 = #$E5 + BEED:D0 C8 BNE _Nib0 ;^ BEB7 + + BEEF:20 10 BF JSR NibRead + BEF2:C9 AA CMP #$AA ; Check8 = #$AA + BEF4:D0 C1 BNE ;^ $BEB7 + + BEF6:B9 00 02 LDA KeyBuf,Y ; if MissingKey[ Y ] > 0 cont. to next key + BEF9:10 BC BPL _Nib0 ;^ $BEB7 + BEFB:A9 00 LDA #False + BEFD:99 00 02 STA KeyBuf,Y ; else MissingKey[ Y ] = False + BF00:AA TAX ; X = 0 + BF01:A8 TAY ; Y = 0 + _CountKey + BF02:B9 00 02 LDA KeyBuf,Y ; Search $0200 .. $02FF + BF05:30 01 BMI _NextKey ; if MissingKey[ Y ] < 0, don't count it + BF07:E8 INX ; X = Num of Keys we have read so far + _NextKey + BF08:C8 INY + BF09:D0 F7 BNE _CountKey + BF0B:E0 A0 CPX #$A0 ; Keep reading until we have 160 keys + BF0D:90 A8 BCC _Nib0 ;^ $BEB7 + BF0F:60 RTS + + NibRead: + BF10:BD 8C C0 LDA DriveData,X + BF13:10 FB BPL NibRead + BF15:60 RTS +``` + +What this code is doing is checking for $A0 = 160 keys on disk of the form: + +``` + D4 D5 DE A5 ?? ?? E5 AA ?? ?? ?? + \_________/ \___/ \___/ \______/ + Prologue KeyYY Epilog Random Sync Bytes +``` + +Recall that bytes in 4&4 format are stored as disk nibbles: + +|Hex| 4&4 | +|:-:|:---:| +|$00|AA AA| +|$01|AA AB| +|...| ... | +|$D5|EA FF| + + +The rest of the code is pretty straightforward. + +```asm + Verify64K: + BF16:2C 83 C0 BIT $C083 + BF19:2C 83 C0 BIT $C083 +``` + + +# Time to go LOCO, er LOGO + +## Logo -- no, not the language + +1. Boot our `Fanta.Work` disk + +2. Enter in this short ML (machine language program) + +```asm + 1F01:A9 60 LDA #$60 ; "RTS" + 1F03:8D 46 08 STA $0846 ; 846:LDX $2B -> RTS + 1F06:8D 73 08 STA $0873 ; 873:LDX $2B -> RTS + 1F09:20 01 08 JSR $0801 ; + 1F0C:A9 17 LDA #$17 ; A=Track + 1F0E:A0 20 LDY #$20 ; Y=Dest + 1F10:20 20 1F JSR $1F20 + 1F13:A9 18 LDA #$18 ; A=Track + 1F15:A0 30 LDY #$30 ; Y=Dest + 1F17:20 20 1F JSR $1F20 + 1F1A:4C 69 FF JMP $FF69 + + 1F20:8D 57 08 STA $857 ; LDA #$0F Track + 1F23:A2 00 LDX #$00 + 1F25:98 TYA + 1F26:9D CE 08 STA $08CE,X + 1F29:C8 INY ; Dest Page + 1F2A:E8 INX + 1F2B:E0 10 CPX #$10 ; 16 sectors + 1F2D:D0 F6 BNE $1F25 + 1F2F:A6 2B LDX $2B + 1F31:4C 48 08 JMP $0848 +``` + +Via: + +```asm + 1F01:A9 60 8D 46 08 8D 73 08 + 1F09:20 01 08 + 1F0C:A9 17 A0 20 20 20 1F + 1F13:A9 18 A0 30 20 20 1F + 1F1A:4C 69 FF + 1F20:8D 57 08 A2 00 98 + 1F26:9D CE 08 C8 E8 E0 10 + 1F2D:D0 F6 A6 2B 4C 48 08 +``` + +3. And save it: + +``` + BSAVE GET_LOGO_1,A$1EEE,L$46 +``` + +4. Replace Slot 6, Drive 1 disk with the original Fantavision. +And now for the moment of truth ... + +```asm + 1EEEG + C050 C052 C054 C057 +``` + +5. When you are done viewing ... + +```asm + C051 +``` + +## Logo Take 2 + +For some unknown reason there is actually a complete _second_ logo on disk?! + +``` + BLOAD GET_LOGO_1 + CALL-151 + 1F0D:A + 1F14:B + BSAVE GET_LOGO_2,A$1EEE,L$46 +``` + +Hmm, why is our logo messed up? + +It turns out 4 tracks are mirrored !?!? + +|Track| Description | +|:---:|:---------------------------:| +| $08 | Mirror of Track $1A, unused | +| $09 | Mirror of Track $19, unused | +| $0A | Mirror of Track $18 @ $3000 | +| $0B | Mirror of Track $17 @ $2000 | + +This is easy enough to fix: + +Boot our `Fanta.Work` disk ... + +``` + BLOAD GET_LOGO_2 + CALL-151 + 1F0D:B + 1F14:A + BSAVE GET_LOGO_2,A$1EEE,L$46 +``` + +You know the drill ... replace Slot 6, Drive 1 with Fantavision, +and `1EEEG` + + +## Logo Take 3 ! + +Track $20, Sectors $8 .. $F has yet a _3rd_ copy of the logo! (Bottom 1/4) + +``` + BLOAD GET_LOGO_2 + CALL-151 + 1F0D:20 + 1F14:21 + BSAVE GET_LOGO_34,A$1EEE,L$46 +``` + +If we compare the original logo on Tracks $17 and $18 we see that: + +* Track $20, Sector $8 == Track $18, Sector $8 @ $3800 + +## Logo Take 4 !! + +Track $21, Sectors $8 ..$F has yet a _4th_ copy of the logo! (Bottom 1/4) + +If we compare the original logo on Tracks $17 and $18 we see that: + +* Track $21, Sector $8 == Track $18, Sector $8 + +Are you going loco yet? + + +# Boot Tracing Stage 5 + + +# "What this, 'Byte-Code', you say young chap?" Harrumph. + +Long before Java popularized the concept of byte-code in +[1994](https://en.wikipedia.org/wiki/Java_version_history) +people were already using the concept _at least_ **9 years earlier** +back in 1985! + +* [Zork I](https://en.wikipedia.org/wiki/Zork) +is probably the most famous program to use byte-code -- back in 1980 -- predating +even Fantavisio by 5 years. + + * The [Z-Machine](https://en.wikipedia.org/wiki/Z-machine) was created in 1979. + +* [UCSD Pascal](https://en.wikipedia.org/wiki/UCSD_Pascal) is probably the second most famous example -- back in 1978 ! + + * [P-Code](https://en.wikipedia.org/wiki/P-code_machine) first appeared in 1966 ! + +Who knew that it would take almost 30 years for byte-code to go mainstream! + + +## Backup Take 1 + +Track $20 has the built-in Backup Utility which is loaded in at $0800. + +How do I know that? + +* $B500 decodes Track $22 in 4&4 format to $BC00 .. $BFFF +* $BE00 has the relevent code that loads it. + +```asm + BE00:4C 06 BE JMP $BE06 + + BE06:20 16 BF JSR Verify64K + + BE5A:AD 00 C0 LDA $C000 ; Key + BE5D:C9 9B CMP #$9B ; ESC pressed? + BE5F:F0 07 BEQ #$BE68 + + BE68:2C 10 C0 BIT $C010 + BE6B:A0 20 LDY #$20 ; Y=TRACK + BE6D:A9 08 LDA #$08 ; A=ADDR + BE6F:20 00 B0 JSR RWTS_LoadTrack + BE72:4C 00 08 JMP $0800 ; Backup.Main +``` + +## Backup Take 2 + +However on Track $21 there is yet _another_ copy of the Backup Utility ! + +Let's write some code to load both of them. :) + +1. `PR#5` to boot our `Fanta.Work` Disk +2. `BLOAD GET_LOGO_1` +3. `CALL-151` + +```asm + 1F0D:20 + 1F14:21 + BSAVE GET_BACKUP_T20_T21,A$1EEE,L$46 +``` + +4. Replace your Fantavision disk in slot 6 +5. `1EEEG` to boot Fantavision +6. Replace your Fanta-work disk in slot 5 +7. `C500G` to boot Fanta-work +8. `CALL-151` +9. `800<2000.27FFM` +10. `BSAVE B5.BACKUP_T20_0800,A$800,L$800` +11. `800<3000.37FFM` +12. `BSAVE B5.BACKUP_T21_0800,A$800,L$800` +13. `BSAVE LOGO_3_T20,A$2800,L$800` +14. `BSAVE LOGO_4_T21,A$3800,L$800` + + +## Backup Byte-Code Interpreter + +Both backup versions share the same Byte-Code design, +but Track $21 has an extra 2 bytes in the interpretor +which causes the Array of Function Pointers to start +at a higher location in memory. + +```asm + Track $20 Track $21 +_800 JMP $0D37 1000: JMP $14DF + +DecodeToken: +_803 PLA 1003: PLA + STA $70 STA $70 ; Save ReturnAddrLo + PLA PLA + STA $71 STA $70 ; Save ReturnAddrHi +_809 JSR $086D 1009: JSR $106F + JSR $0814 JSR $1014 + JMP $0809 JMP $1009 + +_812 LDA #$8D 1012: LDA #$8D ; CR ? +_814 BPL $0834 1014: BPL $1036 ; Never + +LiteralToken: +_816 CMP #$A0 CMP #$A0 ; < SPACE ? + BCC $0824 BCC $1024 + BIT $32 BIT $32 + BMI $0824 BMI $1024 + CMP #$E0 CMP #$E0 ; > '``, one char before 'a' + BCS $0824 BCS $1024 + AND #$3F AND #$3F ; Make Inverse +_824 ORA #$00 1024: ORA #$00 ; + BIT $FBB3 LDY $FBB3 + BPL $0831 CPY #$06 + BEQ $1033 ; <-- old version extra instruction + CMP #$E0 CMP #$E0 ; < '`', one char before 'a' + BCC $0831 BCC $1033 + AND #$DF AND #$DF +_831 JMP $FDF0 1033: JMP $FDF0 +_834 CMP #$20 1036: CMP #$20 + BNE $083A BNE $103C + LDA #$11 LDA #$11 +_83A ASL ASL + TAY TAY + LDA $0846,Y LDA $1048,Y + PHA PHA + LHA $0845,Y LDA $1047,Y +_844 RTS 1046: RTS + +GetNextToken: ; Leaves Token in A and X +_86D LDY #$00 106F: LDY #00 + INC $70 INC $70 + BNE $0875 BNE $1077 + INC $71 INC $71 +_875 LDA ($70),Y 1077: LDA ($70),Y + TAX TAX +0878:RTS RTS +``` + +We are interested in the table of function pointers. + +|Track|Func Ptr| +|:---:|:-------| +| $20 | $0845 | +| $21 | $1047 | + +Comparing the two jump tables: + +|Token| $20 | $21 | +|:---:|:---:|:---:| +| $00 |$0885|$1087| +| $01 |$FB35|$FB35| +| $02 |$FC57|$FC57| +| $03 |$088E|$1090| +| $04 |$0891|$1093| +| $05 |$089B|$109D| +| $06 |$FC9B|$FC9B| +| $07 |$FC41|$FC41| +| $08 |$08A1|$10A3| +| $09 |$08A8|$10AA| +| $0A |$08B0|$10B2| +| $0B |$03E9|$03E9| +| $0C |$FE92|$FE92| +| $0D |$08BF|$10C1| +| $0E |$08C8|$10CA| +| $0F |$08C8|$10CA| +| $10 |$08C8|$10CA| +| $11 |$08D6|$10D8| +| $12 |$08EC|$10EE| +| $13 |$0901|$1106| + +We find they are identical (barring the +2 offset.) + +Let's decode the byte code tokens: + +``` + 0845 FunctionJumpTable + 0845: [$00] CMD_DONE $0886 Return to caller, like 6502: $00 BRK + 0847: [$01] CMD_TEXT $FB36 SETTXT-3 + 0849: [$02] CMD_HOME $FC58 HOME + 084B: [$03] CMD_NORM $088F Switch to Normal Text + 084D: [$04] CMD_INV $0892 Switch to Inverse Text + 084F: [$05] CMD_05 $089C + 0851: [$06] CMD_EOL $FC9C CLREOL + 0853: [$07] CMD_CLR $FC42 CLREOP + 0855: [$08] CMD_HTAB $08A2 xx -> $24 = x-1 + 0857: [$09] CMD_VTAB $08A9 -> Call $FB5B TABV yy+1 + 0859: [$0A] CMD_REP $08B1 xx yy Print char XX repeated YY times + 085B: [$0B] CMD_0B $03EA + 085D: [$0C] CMD_PR0 $FE93 SETVID (PR#0) + 085F: [$0D] CMD_POKE $08C0 lo hi val, like 6502: $8D STA $abs + 0861: [$0E] CMD_DUP_E $08C9 Duplicate of CMD_PTR$ + 0863: [$0F] CMD_DUP_F $08C9 Duplicate of CMD_PTR$ + 0865: [$10] CMD_PTR$ $08C9 Print Pointer to String + 0867: [$11] CMD_JSR2 $08D7 JSR address at next two bytes + 0869: [$12] CMD_INKEY $08ED Wait for keypress + 086B: [$13] CMD_BEEP $0902 Soft Beep + [$20] CMD_JSR -> remapped to [$11] JSR yy xx +``` + + +### Backup 1 Disasembly + +Here is the diassembly of Backup 1: + +```asm +0800:4C 37 0D JMP $0D37 + +DecodeToken: +0803:68 _803 PLA +0804: STA $70 ; Save ReturnAddrLo +0806: PLA +0807: STA $71 ; Save ReturnAddrHi +0809: _809 JSR $086D +080C:20 14 08 JSR $0814 +080F:4C 09 08 JMP $0809 + + _812 LDA #$8D ; CR ? + _814 BPL $0834 ; Never + + LiteralToken: + _816 CMP #$A0 ; < SPACE ? + BCC $0824 + BIT $32 + BMI $0824 + CMP #$E0 ; > '``, one char before 'a' + BCS $0824 + AND #$3F ; Make Inverse + _824 ORA #$00 ; + BIT $FBB3 + BPL $0831 + ; <-- old version extra instruction + CMP #$E0 ; < '`', one char before 'a' + BCC $0831 + AND #$DF + _831 JMP $FDF0 + _834 CMP #$20 + BNE $083A + LDA #$11 + _83A ASL + TAY + LDA $0846,Y + PHA + LHA $0845,Y + _844 RTS + + GetNextToken: ; Leaves Token in A and X + _86D LDY #$00 + INC $70 + BNE $0875 + INC $71 + _875 LDA ($70),Y + TAX TAX +0878:RTS RTS + + + + +0879: GetPointerByte +0879:20 6D 08 JSR GetNextToken +087C:85 72 STA $72 +087E:20 6D 08 JSR GetNextToken +0881:85 73 STA $73 +0883:B1 72 LDA ($72),Y ; Y=0 +0885:60 RTS + + +0896:68 PLA +0897:68 + +0896:85 32 STA $32 +0898:8C 25 08 STY $0825 +089B:60 RTS + +089C:A9 7F LDA #$7F +089E:A0 40 LDY #$40 +08A0:D0 F4 BNE $0896 ; Always + +08C0: Cmd_Poke +08C0:20 79 08 JSR GetPointerByte ; Addr -> $72,$73 +08C3:20 6D 08 JSR GetNextToken ; Val -> A +08C6:91 72 STA ($72),Y ; Poke Addr,Val +08C8:60 RTS + + Cmd_PTR$ +08C9:20 79 08 JSR GetPointerByte +08CC:B1 72 LDA ($72),Y +08CE:F0 06 BEQ $08D6 +08D0:20 16 08 JSR LiteralToken +08D3:C8 INY +08D4:D0 F6 BNE $08CC +08D6:60 RTS + +08F9: Seperator +08F9: JSR DecodeToken +08FC:0A DFB CMD_REP +08FD:AD DFB "-" +08FE:27 DFB 39 ; +08FF:8D DFB $8D ; CR +0900:00 DFB CMD_END +0901:60 RTS + +0918: DriveOn +0918:A6 FD LDX RWTS_SLOT16 ; $2B -> $FD +091A:BD 89 C0 LDA $C089,X ; +091D:A9 00 LDA #$00 +091F:4C A8 FC JMP WAIT + +0922: DiskLoadNibbleCheck +0922:20 18 09 JSR DriveOn ; $0918 +0925:24 6D BIT $6D +0927:10 0B BPL $0934 +0929:A9 44 LDA #$44 ; Track $22 +092B:85 FF STA RWTS_HalfTrack ; TODO: CLEANUP +092D:A9 00 LDA #0 ; Track $00 +092F:20 09 B0 JSR RWTS_Seek +0932:46 6D LSR $6D +0934:A9 B8 LDA #$B8 ; Load @ $B800 +0936:4C 00 B5 JMP ReadBoot3 ; Carry Clear = Original, Set = Copy + +0939:20 22 09 JSR DiskLoadNibbleCheck +093C:B0 02 BCS $0940 +093E:38 SEC +093F:60 RTS + +0940:A9 40 LDA #$40 +0942:85 60 STA $60 +0944:20 44 19 JSR $1944 +0947:90 04 BCC +2 ; $094D +0949:C6 60 DEC $60 +094D:BD 88 C0 LDA DRIVE_MOTON_OFF,X +0950:60 RTS + + GetKey +08ED:2C 10 C0 BIT KEYSTROBE +08F0:AD 00 C0 LDA KEYBOARD +08F3:10 FB BNE $8F0 +08F5:2C 10 C0 BIT KEYSTROBE +08F8:60 RTS + +0AB7: BottomSeperator +0AB7:20 03 08 JSR DecodeToken +0ABA:09 DFB CMD_VTAB +0ABB:18 DFB #24 +0ABC:08 DFB CMD_HTAB +0ABD:01 DFB #1 +0ABE:0A DFB CMD_REP +0ABF:AD ASC "-" +0AC0:27 DFB #39 ; 39 cols +0AC1:08 DFB CMD_HTAB +0AC2:01 DFB #1 +0AC3:00 DFB CMD_DONE +0AC4:60 RTS + + AlreadyCopied +0B90:20 03 08 JSR DecodeToken +0B93:02 DFB CMD_HOME +0B94:09 DFB CMD_VTAB +0B95:09 DFB #9 +0B96:D4 E8 ASC "This disk has already been used to" +0B98:E9 F3 A0 E4 +0B9C:E9 F3 EB A0 +0BA0:E8 E1 F3 A0 +0BA4:E1 EC F2 E5 +0BA8:E1 E4 F9 A0 +0BAC:E2 E5 E5 EE +0BB0:A0 F5 F3 E5 +0BB4:E4 A0 F4 EF +0BB8: DFB CR +0BB8: DFB CR +0BBA ASC "make a backup." +0BC8: DFB 00 +0BC9:4C 05 0B JMP $0B05 + + CheckAlreadyCopied +0BCC:20 22 09 JSR DiskLoadNibbleCheck +0BCF:B0 FB BCS $0BCC ; if C=1 then disk read error, keep trying +0BD1:AD 00 B8 LDA $B800 ; if DiskCopiedFlag == 00=Copied, FF=Not copied +0BD4:F0 BA BEQ AlreadyCopied ;^ $0B90 +0BD6:60 RTS + +0D1A: TXT_FANTAVISION_NAME +0D1A: ASC "Fantavision" +0D25:00 DFB CMD_DONE +0D26: TXT_FANTAVISION_DISK +0D26: ASC "Fantavision disk" +0D36:00 DFB CMD_DONE + +0D37:A6 FD LDX $FD ; SLOTx16 +0D39:8E E9 1F STX $1FE9 ; +0D3C:8E F7 1F STX $1FF7 ; +0D3F:A9 00 LDA #$00 +0D41:8D EB 1F STA $1FEB +0D44:8D F0 1F STA $1FF0 +0D47:46 6B LSR $6B +0D49:46 6C LSR $6C +0D4B:20 03 08 JSR DecodeToken +0D4E:01 DFB CMD_TEXT +0D4F:02 DFB CMD_HOME +0D50:03 DFB CMD_NORM +0D51:20 F9 08 JSR Seperator +0D54:A0 A0 A0 ASC " " +0D57:10 DFB CMD_PTR$ +0D58:1A 0D DA TXT_FANTAVISION_NAME +0D5A:A0 ASC " (TM) Backup Utility" +0D70:8D DFB CR +0D71:20 F9 08 JSR Seperator +0D74:0D DFB CMD_POKE +0D75:22 00 DA WNDTOP ; $22 = Window.Top +0D77:04 DFB #4 ; 4 Lines +0D78:0D DFB CMD_POKE +0D79:23 00 DA WNDBOT ; $23 = Window.Bottom +0D7B:16 DFB #22 ; Normally $18 = 24 rows +0D7C:20 B7 0A JSR BottomSeperator +0D7F:20 CC 0B JSR CheckAlreadyCopied +0D82:02 DFB CMD_HOME +0D83: ASC "This utility lets you make one backup" +0DA8:8D DFB CR +0DA9: ASC "of your " +0DB1:10 DFB CMD_PTR$ +0DB2:26 0D DA TXT_FANTAVISION_DISK +0DB4:AE ASC "." +0DB5:8D DFB CR +0DB6:8D DFB CR +0DB7:04 DFB CMD_INV +0DB8: ASC "IMPORTANT:" +0DC2:03 DFB CMD_NORM +0DC3:A0 D9 ASC " You may use this option" +0DDB:8D DFB CR +0DDC:08 DFB CMD_HTAB +0DDD:0C DFB #12 +0DDE: ASC "only once." +0DE8:8D DFB CR +0DE9:8D DFB CR +0DEA:D4 ASC "To make a backup, you will need" +0E09:8D DFB CR +0E0A: ASC "one blacnk disk." +0E19:8D DFB CR +0E1A:8D DFB CR +0E1B: ASC "You will need to swap disks a number of " +0E42:8D DFB CR +0E43: ASC "times. The program will tell you when" +0E68:8D DFB CR +0E69 ASC "to do this." +0E74:8D DFB CR +0E75:8D DFB CR +0E76: ASC "To start, make sure your " +0E8F:10 DFB CMD_PTR$ +0E90:1A 0D DA TXT_FANTAVISION_NAME +0E92:8D DFB CR +0E93: ASC "disk (label side up) is in" +0EAD:8D DFB 8D +0EAE:20 JSR $0AC5 ; TODO: FIXME +``` + +To 'fake' the backup used: + +``` +BD1:A9 +BD3:EA + +800G +``` + + +### Backup 2 Disasembly + +TODO: FIXME + +```asm +``` + +# Applesoft?! + +1. Boot our `Fanta.Work` disk +2. `BLOAD GET_LOGO_1` +3. `CALL-151` + +```asm + 1F0D:16 + BSAVE GET_APPLESOFT_MENU,A$1EEE,L$46 +``` + +4. Replace your Fantavision disk in slot 6 +5. `1EEEG` +6. Replace your Fanta-work disk in slot 5 +7. `C500G` +8. `NEW` +9. `CALL-151` + NOTE: We DON'T want `67:0` to change start of Applesoft from $801 to $800 +10. `800<2000.2FFFM` +11. `BSAVE B6.FANTASOFT.BAS_T16_0800,A$800,L$1000` +12. `` +13. `LIST` + +```Basic +4864 ONERR GOTO 9000 +1 REM Fantavision (C) 1985 by Scott Anderson - 9/26/85 +3 HIMEM: 2 * 4096 +5 POKE 1012,0 +9 HOME: VTAB 23:HTAB 4:PRINT "PRESS THE SPACE BAR TO CHANGE THE": + HTAB 3:PRINT "DRAWING TOOL OR TO MAKE A SHOW DISK."; +10 GOTO 5000 +100 HTAB 11-2*(I>4): PRINT LEF$( I$(I),1)" - "I$(I):RETURN +150 HTAB 2:FOR I = 1 TO 38: PRINT " ";:NEXT: RETURN +180 HTAB 10 - (LEN( I$( ID ) ) ) / 2: PRINT "THE DRAWING TOOL IS A "I$(ID)".":RETURN +400 REM Get Input Device +410 TEXT: HOME: HTAB 9:PRINT "= [ FANTAVISION MENU ] =":PRINT:GOSUB 150 +430 FOR I = 1 to NI: VTAB 4 + 2*I + 2*(I>4):GOSUB 100:NEXT +440 VTAB 22: CALL EB: PRINT: HTAB 13:PRINT "YOU CHOICE:";: GET A$: A=ASC(A$): A=A-32*(A>96):A$=CHR$(A):PRINT A$; +445 I = NI +450 IF A <> ASC( I$(I) ) THEN I=I-1:ON I > 0 GOTO 450:PRINT CHR$(7);:GOTO 440 +460 ON I > 4 GOTO 490:ID = I: D = ND +470 IF DB%(D,0) <> ID THEN D=D-1:ON D > 0 GOTO 470 +480 IF D THEN GOSUB 500:ON SL > 0 GOTO 490:VTAB 23:HTAB 5:PRINT "WHAT SLOT IS THE " I$(ID)" IN? :";: GET A$:SL = VAL( A$ ):PRINT SL;:ON NOT SL GOTO 440 +490 RETURN +500 B=1:SL=7 +510 IF PEEK(12*4096 + SL*256 + DB%(0,B)) = DB%(D,B) THEN B=B+1: ON B < 5 GOTO 510:GOTO 580 +520 B = 1: SL = SL - 1:ON SL > 0 GOTO 510 +580 RETURN +600 L = DS*16 + 49292:X = PEEK( L - 3 ): X = PEEK( L - 1 ):REM Dr2 on +610 X = PEEK( L ): DD = 2:FOR I = 1 to 20: IF PEEK(L) = X THEN NEXT I:DD = 1 +630 X = PEEK( L - 4 ):RETURN +800 REM +890 RETURN +900 REM +990 RETURN +5000 REM Start of program +5020 LS = 4*256 - 2: IL = LS + 1 +5040 EB = 64578 +5050 Z = 43008: IO = 48249: BF = 48896: CA = 776: CP = 789 +5060 DS = PEEK( IO + 1 ) / 16 +5070 GOSUB 600 +5100 DATA 6,MOUSE,GRAPICS TABLET,KOALA PAD,JOY STICK,CREATE A SHOW DISK,QUIT THIS MENU +5110 READ NI:FOR I = 1 TO NI: READ I$(I):NEXT +5200 DATA 2 +5201 DATA 0, 5, 7, 11, 12 +5210 DATA 1, 56, 24, 1, 32 +5211 DATA 2,120,255,200,160 +5230 READ ND: FOR D = 0 TO ND: FOR B = 0 TO 4: READ DB%(D,B):NEXT:NEXT +5300 D = ND +5310 GOSUB 500: IF SL=0 THEN D=D-1:ON D > 0 GOTO 5310 +5320 IF D THEN ID = DB%(D,0) +5340 ID = ID+4 * NOT ID +5600 VTAB 22:GOSUB 180 +6000 A = PEEK( 49152 ): IF A > 127 THEN 6800 +6010 W = W + 1: IF W < 150 GOTO 6000: GOTO 6900 +6800 GOSUB 400:ON I = 5 GOTO 7000 +6820 IF QF THEN 8000 +6840 HOME: VTAB 15: GOSUB 180 +6900 ID = ID - (ID = 4) +6920 POKE LS-1,255 * (DD=2): POKE LS,SL:POKE IL,ID-1 +6940 CALL 768 +7000 :TEXT:HOME:VTAB 3:HTAB 9:PRINT "=[ CREATE A SHOW DISK ]=" +7010 VTAB 22:CALL EB: PRINT: PRINT " :::::::: PRESS 'ESC' TO EXIT ::::::::" +7020 VTAB 6:HTAB 3:PRINT "TO CREATE A SHOW DISK, THIS PROGRAM": HTAB 3:PRINT "MUST COPY SOME FILES FROM THE MOVIE":HTAB 3:PRINT "MATINEED ON SIDE II OF FANTAVISION." +7030 GOSUB 150 +7050 ON DD = 1 GOTO 7100:VTAB 13:HTAB 3:PRINT "INSERT THE MATINEE IN DRIVE 1," +7060 HTAB 7:PRINT "AND A BLANK DISK IN DRIVE 2." +7070 PRINT:HTAB 9:PRINT "PRESS RETURN WHEN READY:";:GET A$:ON A$ = CHR$(27) GOTO 7900:GOTO 7200 +7100 VTAB 14:HTAB 8:PRINT "INSERT BLANK SHOW DISKETTE":HTAB 7:PRINT "IN DRIVE 1 AND PRESS RETURN:";:GET A$ +7120 ON A$ = CHR$(27) GOTO 7900 +7200 POKE ZP + 2, 2:POKE ZP + 5,96 + 128*(DD=2):POKE 0,0:POKE IO+2,DD:CALL CA:IF PEEK(0) THEN 7700 +7220 B = PEEK( BF + 4 ):ON B < 241 or PEEK( BF + 2 ) <> 3 or PEEEK( BF + 36 ) <> 13 GOTO 7700 +7230 B = B - 240: N$ = "": FOR I = 1 TO B: N$ = N$ + CHR$( PEEK( BF + 4 + I ) ):NEXT +7240 IF N$ = "FANTAVISION" THEN POKE 0, 144:GOTO 9900 +7250 VTAB 18:HTAB 13 - B / 2: PRINT "DESTROY "N$"? (Y/N):"; +7300 GET A$: ON A$ <> "Y" AND A$ <> "y" GOTO 7900:VTAB 18:HTAB 1:PRINT SPC(40) +7700 QF + 1: POKE 0,0: CALL CP: IF PEEK(0) THEN 9900 +7900 GOTO 6800 +8000 HOME: VTAB 10, HTAB 9:PRINT "INSERT THE DESIRED DISK,":PRINT:HTAB 12:PRINT "THEN PRESS RETURN:";:GET A$ +8010 PRINT: CALL 12*4096 + DS*256 +9000 Error trap +9010 RUN +9900 REM Dos Errors +9910 ER = PEEK( 0 ):POKE 0,0:VTAB 12:CALL EB:PRINT CHR$(7):FLASH +9920 IF ER=39 THEN HTAB 12:PRINT "UNABLE TO FORMAT.":GOTO 9990 +9930 IF ER=43 OR ER=16 THEN HTAB 13:PRINT "WRITE PROTECTED.":GOTO 9990 +9940 IF ER=51 THEN HTAB 13:PRINT "DRIVE TOO SLOW.":GOTO 9990 +9950 IF ER=52 THEN HTAB 13:PRINT "DRIVE TOO FAST.":GOTO 9990 +9970 IF ER=144 THEN HTAB 8:PRINT "CAN'T DESTROY FANTAVISION!":GOTO 9990 +9980 HTAB 15:PRINT "DRIVE ERROR." +9990 NORMAL:HTAB 16:HTAB 9:PRINT "PRESS ANY KEY FOR MENU:";:GET A$:GOTO 5400 +``` + +NOTES: + +* Line 0 has a bogus line number `4864 due to $0803:00 13` +* Line 3 changes the top of Applesoft variables to memory $2000, right before the HGR screen. +* Line 5 changes the Reset Vector Checksum: 1012 = $3F4. +* Line 6490 Exits the Applesoft program to $0300 + +Here is a disassembly of the first few bytes of the Applesoft program. + +```asm +0800:08 0C 08 00 13 A5 AB 39 30 30 30 00 + \/ \___/ \___/ \/ \/ \/ \/ \/ \/ \/ + not Addr Line GOTO 9 0 0 0 End-of-Line + used Next Num ONERR + Statement +``` + +Let's pivot that table to make it easier to read: + +|Addr|Byte(s) |Meaning | +|:--:|:----------|:--------------------------| +|0800|08 |not used | +|0801|0C 08 |Address of next line, $080C| +|0803|00 13 |Line number, $1300 | +|0805|A5 |ONERR | +|0806|AB |GOTO | +|0807|39 30 30 30|9000 | +|080B|00 |End-Of-Line sentinel | + +## Applesoft Tokens + +In case your knowledge of Applesoft is rusty, +Bit-7 is used to desiginate BASIC "Tokens" + +Quick review of Applesoft in ROM on the Apple. + +* $D000 is an Array of 16-bit Function Pointers +* $D0D0 is the string (in DCI format) of all the token names. + +Let's write a program to generate a nice table for us: + +```asm + ORG $300 + LDA #$D0 ; 0300:A9 D0 + STA $FE ; 0302:85 FE + STA $FF ; 0304:85 FF + LDA #$80 ; 0306:A9 80 Start @ Token $80 + STA $FC ; 0308:85 FC + +^0 JSR PRBYTE ; 030A:20 DA FD + LDA #$A0 ; 030D:A9 A0 space char + JSR COUT ; 030F:20 ED FD +^1 LDY #$00 ; 0312:A0 00 + LDA ($FE),Y ; 0314:B1 FE + PHA ; 0316:48 + INC $FE ; 0317:E6 FE + BNE ^2 ; 0319:D0 02 + INC $FF ; 031B:E6 FF +^2 ORA #$80 ; 031D:09 80 + JSR COUT ; 031F:20 ED FD + PLA ; 0322:68 + BPL ^1 ; 0323:10 ED + JSR CROUT ; 0325:20 8E FD CROUT = $FD8E + + LDA $C000 ; 0328:AD 00 C0 + BPL ^4 ; 032B:10 0B + STA $C010 ; 032D:8D 10 C0 +^3 + LDA $C000 ; 0330:AD 00 C0 + BPL ^3 ; 0333:10 FB + STA $C010 ; 0335:8D 10 C0 +^4 + INC $FC ; 0338:E6 FC + LDA $FC ; 033A:A5 FC Token + CMP #$EB ; 033C:C9 EB + BNE ^0 ; 033E:D0 CA + RTS ; 0340:60 +``` + +Enter in the raw machine code: + +``` +300:A9 D0 85 FE 85 FF A9 80 +308:85 FC 20 DA FD A9 A0 20 +310:ED FD A0 00 B1 FE 48 E6 +318:FE D0 02 E6 FF 09 80 20 +320:ED FD 68 10 ED 20 8E FD +328:AD 00 C0 10 0B 8D 10 C0 +330:AD 00 C0 10 FB 8D 10 C0 +338:E6 FC A5 FC C9 EB D0 CA +340:60 +``` + +Which generates this table: + +|Hex| Token | +|:-:|:---------| +|$80| END | +|$81| FOR | +|$82| NEXT | +|$83| DATA | +|$84| INPUT | +|$85| DEL | +|$86| DIM | +|$87| READ | +|$88| GR | +|$89| TEXT | +|$8A| PR# | +|$8B| IN# | +|$8C| CALL | +|$8D| PLOT | +|$8E| HLIN | +|$8F| VLIN | +|$90| HGR2 | +|$91| HGR | +|$92| HCOLOR= | +|$93| HPLOT | +|$94| DRAW | +|$95| XDRAW | +|$96| HTAB | +|$97| HOME | +|$98| ROT= | +|$99| SCALE= | +|$9A| SHLOAD | +|$9B| TRACE | +|$9C| NOTRACE | +|$9D| NORMAL | +|$9E| INVERSE | +|$9F| FLASH | +|$A0| COLOR= | +|$A1| POP | +|$A2| VTAB | +|$A3| HIMEM: | +|$A4| LOMEM: | +|$A5| ONERR | +|$A6| RESUME | +|$A7| RECALL | +|$A8| STORE | +|$A9| SPEED= | +|$AA| LET | +|$AB| GOTO | +|$AC| RUN | +|$AD| IF | +|$AE| RESTORE | +|$AF| & | +|$B0| GOSUB | +|$B1| RETURN | +|$B2| REM | +|$B3| STOP | +|$B4| ON | +|$B5| WAIT | +|$B6| LOAD | +|$B7| SAVE | +|$B8| DEF | +|$B9| POKE | +|$BA| PRINT | +|$BB| CONT | +|$BC| LIST | +|$BD| CLEAR | +|$BE| GET | +|$BF| NEW | +|$C0| TAB( | +|$C1| TO | +|$C2| FN | +|$C3| SPC( | +|$C4| THEN | +|$C5| AT | +|$C6| NOT | +|$C7| STEP | +|$C8| `+` | +|$C9| `-` | +|$CA| `*` | +|$CB| `/` | +|$CC| `^` | +|$CD| AND | +|$CE| OR | +|$CF| > | +|$D0| = | +|$D1| < | +|$D2| SGN | +|$D3| INT | +|$D4| ABS | +|$D5| USR | +|$D6| FRE | +|$D7| SCRN( | +|$D8| PDL | +|$D9| POS | +|$DA| SQR | +|$DB| RND | +|$DC| LOG | +|$DD| EXP | +|$DE| COS | +|$DF| SIN | +|$E0| TAN | +|$E1| ATN | +|$E2| PEEK | +|$E3| LEN | +|$E4| STR$ | +|$E5| VAL | +|$E6| ASC | +|$E7| CHR$ | +|$E8| LEFT$ | +|$E9| RIGHT$ | +|$EA| MID$ | + + +There is very nice chart at [Call APPLE Applesoft Tokens](http://www.callapple.org/vintage-apple-computers/apple-ii/applesoft-tokens/) + + +To see Token 13 + +``` +NEW +127 REM ABC +511 REM DEF +CALL-151 +800.817 + +``` +# Boot stage 5 + +# Boot stage 6 + +The Applesoft "Fantavision Menu" returns via CALL 768 + +```asm +0300:A9 60 LDA #$60 +0302:8D 50 40 STA $4050 +0306:4C 00 60 JMP $6000 FANTA_INIT +0309:20 26 03 JSR $0326 +030B:A9 02 LDA #$02 +030D:85 40 STA $40 +030F:20 00 B3 JSR $B300 +0312:4C 1B 03 JMP $031B +``` + +## Boot Stage Memory Map + +From $BE27 we can build this memory map + +|Track|Address| +|:---:|:-----:| +| $15a| $B000 .. $B700 | +| $15b| $1800 .. $1FFF | +| $16 | $0800 .. $17FF | +| $17 | $2000 .. $2FFF | +| $18 | $3000 .. $3FFF | +| $19 | $4000 .. $4FFF | +| $1A | $5000 .. $5FFF | +| $1B | $6000 .. $6FFF | +| $1C | $7000 .. $7FFF | +| $1D | $8000 .. $8FFF | +| $1E | $9000 .. $9FFF | +| $1F | $A000 .. $AFFF | + + + +# Disk Information + +If one boots up Copy \]\[ 5.0 and uses the `Sector Editor` +to read the original `Fantavision` disk you'll get an `I/O Error.` + +Inspecting the disk nibbles via `Copy > Bit Copy > Nibble Editor` +Tracks $00 through $21 we find the following disk nibbles +for Track $00, Sector $0: + +``` +D5 AA 96 FF FE AA AA AA AA FF FE DE AB +\______/ \___/ \___/ \___/ \___/ \___/ + Address Vol Trk Sec XOR Address +Prologue 254 $00 $0 Check Epilogue + +...random sync bytes... + +D5 AA AD ...342... DE AA EB +\______/ \______/ + Data Data +Prologue Epilogue +``` + +The standard Address bit-stream for a DOS 3.3 disk is: + +``` +D5 AA 96 vv vv tt tt ss ss cc cc DE AA EB +\______/ \___/ \___/ \___/ \___/ \______/ + Address Vol. Track Sec. Check Address +Prologue Epilogue +``` + +Everything looks kosher with _Fantavision_ -- except +Fantavision has changed the epilog disk nibbles from the +standard `DE AA EB` to the non-standard `DE AB` + +Returning to the Sector Editor we can press `P` to patch DOS 3.3 +and use `RETURN` to cycle through the fields until we get to +`CHECK EPILOG?`, `N` to toggle it, then `ESC` to return to the sector edit. + +``` +CUSTOM + + ADDRESS + + CHECK EPILOG? NO +``` + +Re-reading T00S0 ... + +``` +00- 01 A9 60 8D 01 08 A2 00 +08- 86 FF B5 00 9D 00 10 E8 +10- D0 F8 8D 08 C0 BD 00 10 +18- 95 00 E8 D0 F8 A9 FF 8D +20- FB 04 8D F3 03 8D F4 03 +28- 8D 00 C0 8D 0C C0 8D 0E +30- C0 8D 5F C0 8D 81 C0 20 +38- 2F FB 20 58 FC 20 84 FE +40- 20 93 FE 20 89 FE A6 2B +48- 8A 4A 4A 4A 4A 09 C0 8D +50- 6E 08 A9 0F 85 52 A9 15 +58- 85 41 0A 20 81 08 A5 52 +60- B9 BE 08 85 3D B9 CE 08 +68- F0 05 85 27 20 5C 00 C6 +70- 52 10 EB A6 2B 86 FD A9 +78- BC 20 00 B5 B0 F5 4C 00 +80- BE 85 50 A5 FF 85 51 38 +88- E5 50 F0 2C B0 04 E6 FF +90- 90 02 C6 FF 20 AD 08 20 +98- B9 08 A5 51 29 03 0A 05 +A0- 2B A8 B9 80 C0 20 B9 08 +A8- F0 D9 20 B9 08 A5 FF 29 +B0- 03 0A 05 2B A8 B9 81 C0 +B8- 60 A9 28 4C A8 FC 00 0D +C0- 0B 09 07 05 03 01 0E 0C +C8- 0A 08 06 04 02 0F B0 B1 +D0- B2 B3 B4 B5 B6 B7 18 19 +D8- 1A 1B 1C 1D 1E 1F 00 00 +E0- 00 00 00 00 00 00 00 00 +E8- 00 00 00 00 00 00 00 00 +F0- 00 00 00 00 00 00 00 00 +F8- 00 00 00 00 00 00 00 00 +``` + +AH-HA! Success! + +Q. Why does the P5 PROM read these sectors but not DOS or ProDOS ? + +A. We're getting ahead of ourselvs but the P5 PROM: + +* **only** checks the 3 disk nibbles od the Prolog fields, and +* _ignores_ the Epilig fields entirely! + + + +## COPY, eh? + +To over-use a cliche, _"With knowledge comes power."_ + +With our new found knowledge we can use the old standby `COPYA` on a +DOS 3.3 Master (disk) to copy all but the last track. + +The only catch are: + +* we need to tell DOS 3.3 to ignore the Address Prologue (or use the correct one), and +* we need to tell COPYA to skip track $22. + +Both of these are pretty easy to do: + +DOS 3.3 only checks for the disk nibble `$DE` epilog in one of two places: + +* Address Epilog at $B98B +* Data Epilog at $B92F + +The Data fields are read in DOS 3.3's function `READ16` @ $B8DC but we are +only interested in the Data Epilog portion @ $B92F: + +```asm +392F:BD 8C C0 155 READ7 LDA Q6L,X +3932:10 FB 156 BPL READ7 *** NO PAGE CROSS! *** +3934:C9 DE 157 CMP #$DE FIRST BIT SLIP MARK? +3936:D0 0A 158 BNE RDERR (ERR IF NOT) +3938:EA 159 NOP DELAY BETWEEN NIBLS. +3939:BD 8C C0 160 READ8 LDA Q6L,X +393C:10 FB 161 BPL READ8 *** NO PAGE CROSS! *** +393E:C9 AA 162 CMP #$AA SECOND BIT SLIP MARK? +3940:F0 5C 163 BEQ RDEXIT (DONE IF IT IS) +3942:38 164 RDERR SEC INDICATE 'ERROR EXIT'. +3943:60 165 RTS FROM READ16 OR RDADR16. +``` + +The Address fields are read in DOS 3.3's function `RDADR16` @ $B944 but we are +only interested in the Address Epilog portions @ $ B98B: + +```asm +398B:BD 8C C0 093 RDA6 LDA Q6L,X FIRST BIT-SLIP NIBL. +398E:10 FB 094 BPL RDA6 *** NO PAGE CROSS! *** +3990:C9 DE 095 CMP #$DE +3992:D0 AE 096 BNE RDERR ERROR IF NONMATCH. +3994:EA 097 NOP DELAY BETWEEN NIBLS. +3995:BD 8C C0 098 RDA7 LDA Q6L,X SECOND BIT-SLIP NIBL. +3998:10 FB 099 BPL RDA7 *** NO PAGE CROSS! *** +399A:C9 AA 100 CMP #$AA +399C:D0 A4 101 BNE RDERR ERROR IF NONMATCH. +399E:18 102 RDEXIT CLC CLEAR CARRY ON +399F:60 103 RTS NORMAL READ EXITS. +``` + +We need to change byte @ $B99B from $AA to $AB. + +Technically we only need to change one of these. + + + +## ProDOS Hybrid!? + +If we boot `ProDOS` and try to `CAT` our `Fanta.COPYA` disk +our efforts are rewarded with this: + +``` + /FANTAVISION + + NAME TYPE BLOCKS MODIFIED + + *FORMAT BIN 7 4-SEP-85 + M.SPIDER BIN 4 + M.CANCAN BIN 4 + M.TREE BIN 5 + M.OBJECTS BIN 3 + M.DIVE BIN 4 + M.FACE BIN 3 + M.PEOPLE BIN 4 + M.REDWHITEBLUE BIN 3 + M.ENGLISHFONT BIN 10 + M.SLANTFONT BIN 4 + M.ORBITFONT BIN 4 + M.DOTS2FONT BIN 6 + M.CIRCUITFONT BIN 5 + M.DOTSFONT BIN 6 + M.OUTLINEFONT BIN 8 + M.LAND BIN 3 + + BLOCKS FFREE: 78 BLOCKS USED: 202 +``` + + + +## Disk Notes + +## Notes + +T00S8 n/a ProDOS Block 3B ProDOS Volume Directory 2 + M.MORFIC + M.VOLCANO +T00S9 n/a ProDOS Block 3A ProDOS Volume Directory 2 + M.DOTS2FONT + M.CIRCUITFONT + M.DOTSFONT + M.OUTLINEFONT + M.LAND + M.APPLE2 + M.SHADOWTRIXKS +T00SA n/a ProDOS Block 2B ProDOS Volume Directory 1 + M.FACE + M.PEOPLE + M.REDWHITEBLUE + M.ENGLISHFONT + M.SLANTFONT + M.ORBITFONT +T00SB n/a ProDOS Block 2A ProDOS Volume Directory 1 + VOLUME: "FANTAVISION" + FORMAT + M.SPIDER + M.CANCAN + M.TREE + M.OBJECTS + M.DIVE + + +## ProDOS Block Review + +NOTES: + +* Block = ProDOS Block number (Dec) +* Track (Hex) +* Sector = Physical Sector (Hex) +* Logical Sector = Copy ][+ + +|Block|Track|Sectors|Logical | +|----:|:---:|:-----:|:------:| +| 0 | 00 | 0,2 | 0,E | +| 1 | 00 | 4,6 | D,C | +| 2 | 00 | 8,A | B,A | +| 3 | 00 | C,E | 9,8 | +| 4 | 00 | 1,3 | 7,6 | +| 5 | 00 | 5,7 | 5,4 | +| 6 | 00 | 9,B | 3,2 | +| 7 | 00 | D,F | 1,F | +| : | : | : | : | +| 279 | 22 | D,F | 1,F | + +Version 1 + +```asm + 0300:A9 00 LDA #00 ; Start Block + 0302:85 FF STA $FF + 0304:20 10 03 JSR Block2TrackSector + 0307:E6 FF INC $FF + 0309:A5 FF LDA $FF + 030B:C9 20 CMP #$10 ; End Block + 030D:90 F5 BCC $304 + 030F:60 RTS + +Block2TrackSector: + 0310:48 PHA ;+(1) + 0311:48 PHA ;+(2) + JSR PRBYTE + LDA #'=' ; $BD + JSR COUT + PLA ;-(2) + + 0312:29 07 AND #7 + 0314:C9 04 CMP #4 + 0316:29 03 AND #3 + 0318:08 PHP + 0319:0A ASL + 031A:28 PLP + 031B:2A ROL + 031C:85 FE STA $FD ; Sector First Half + 031E:A9 00 LDA #$00 ; Block+1 + 0320:4A LSR + 0321:68 PLA ;-(2) + 0322:6A ROR + 0323:4A LSR + 0324:4A LSR + 0324:85 FC STA $FC ; Track + + 0327:A9 D4 LDA #$'T' ; + 0329:20 ED FD JSR COUT + 032C:A5 FC LDA $FC ; Track + 032E:20 DA FD JSR PRBYTE ; Print 2 hex digits = Register A + 0331:A9 D3 LDA #$'S' ; + 0333:20 ED FD JSR $FDED + 0336:A5 FD LDA $FD ; Sector + 0338:20 E3 FD JSR PRHEX ; Print 1 hex digit = Register A + 033B:A9 AC LDA #$',' + 033D:20 ED FD JSR COUT + 0340:A4 FD LDY $FD ; Sector Second Half + 0342:C8 INY + 0343:C8 INY + 0344:98 TYA + 0345:20 E3 FD JSR PRHEX + 0348:20 8E FD JSR CROUT ; $FD8E + 034B:68 PLA ;-(1) + 034C:60 RTS +``` + +## Disk Usage Summary + +| T/S |Addr |Block|Offset|Description | +|:---:|:---:|----:|-----:|:-----------------------------| +|T00S0|$0800| 0a | n/a | Boot Stage 1 - Boot Sector | +|T00S1| n/a | 7a |#0000 | `/FANTAVISION/FORMAT` | +|T00S2| n/a | 6b | n/a | ProDOS Volume Bitmap | +|T00S3| n/a | 6a | n/a | ProDOS Volume Bitmap | +|T00S4| n/a | 5b | n/a | ProDOS Volume Directory 4 | +|T00S5| n/a | 5a | n/a | ProDOS Volume Directory 4 | +|T00S6| n/a | 4b | n/a | ProDOS Volume Directory 3 | +|T00S7| n/a | 4a | n/a | ProDOS Volume Directory 3 | +|T00S8| n/a | 3b | n/a | ProDOS Volume Directory 2 | +|T00S9| n/a | 3a | n/a | ProDOS Volume Directory 2 | +|T00SA| n/a | 2b | n/a | ProDOS Volume Directory 1 | +|T00SB| n/a | 2a | n/a | ProDOS Volume Directory 1 | +|T00SC| n/a | 1b | n/a | SOS Boot Part B | +|T00SD| n/a | 1a | n/a | SOS Boot Part A, JMP $A06E, ASC "SOS BOOT 1.1 .SOS.KERNEL" | +|T00SE| n/a | 0b | n/a | "PRODOS__________", "*** UNABLE TO LOAD PRODOS ***" | +|T00SF| n/a | 7b |#0100 | `/FANTAVISION/FORMAT` | +| --- | --- | -- | --- | --- | +|T01S0| n/a | 8a |#0200 | /FANTAVISION/FORMAT | +|T01S1| n/a | 15a |#0200 | `/FANTAVISION/M.SPIDER` | +|T01S2| n/a | 14b |#0100 | `/FANTAVISION/M.SPIDER` | +|T01S3| n/a | 14a |#0000 | `/FANTAVISION/M.SPIDER` 05 01 06 04 3B 08 FF 00 | +|T01S4| n/a | 13b |#0D00 | `/FANTAVISION/FORMAT`, Zero | +|T01S5| n/a | 13a |#0C00 | `/FANTAVISION/FORMAT`, Mirror of T00SE, "PRODOS" | +|T01S6| n/a | 12b |#0B00 | `/FANTAVISION/FORMAT` | +|T01S7| n/a | 12a |#0A00 | `/FANTAVISION/FORMAT`, Mirror of T00SD, "SOS BOOT 1.1 KERNEL" | +|T01S8| n/a | 11b |#0900 | `/FANTAVISION/FORMAT` | +|T01S9| n/a | 11a |#0800 | `/FANTAVISION/FORMAT`, Subdirectory "MOVIES" ? | +|T01SA| n/a | 10b |#0700 | `/FANTAVISION/FORMAT` | +|T01SB| n/a | 10a |#0600 | `/FANTAVISION/FORMAT` | +|T01SC| n/a | 9b |#0500 | `/FANTAVISION/FORMAT` | +|T01SD| n/a | 9a |#0400 | `/FANTAVISION/FORMAT` | +|T01SE| n/a | 8b |#0300 | `/FANTAVISION/FORMAT`, Zero | +|T01SF| n/a | 15b |#0300 | `/FANTAVISION/M.SPIDER` | +| --- | --- | -- | --- | --- | + +``` + |T02S0| /FANTAVISION/M.SPIDER #0400 + |T02S1| + |T02S2| + |T02S3| + |T02S4| /FANTAVISION/M.CANCAN #0700, Zero + |T02S5| /FANTAVISION/M.CANCAN #0600 + |T02S6| /FANTAVISION/M.CANCAN #0500 + |T02S7| /FANTAVISION/M.CANCAN #0400 + |T02S8| /FANTAVISION/M.CANCAN #0300, Zero + |T02S9| /FANTAVISION/M.CANCAN #0200 + |T02SA| /FANTAVISION/M.CANCAN #0100 + |T02SB| /FANTAVISION/M.CANCAN #0000, 0000:03 03 04 04 ... + |T02SC| /FANTAVISION/M.SPIDER #0700 + |T02SD| /FANTAVISION/M.SPIDER #0600 + |T02SE| /FANTAVISION/M.SPIDER #0500 + |T02SF| /FANTAVISION/M.TREE #????? Zero + + |T03S0| + |T03S1| + |T03S2| + |T03S3| + |T03S4| + |T03S5| + |T03S6| Zero + |T03S7| + |T03S8| + |T03S9| + |T03SA| + |T03SB| + |T03SC| + |T03SD| + |T03SE| + |T03SF| Zero + + T04S4 Zero + T04S6 Zero + T04S8 Zero + + T05S8 Zero + T05SC Zero + T05SF Zero + + T06SC Zero + T06SE Zero + T07S8 Zero + T07SF Zero + + T08Sx Mirror of Track $1A + T09Sx Mirror of Track $19 + T0ASx Mirror of Track $18 @ $3000 + T0BSx Mirror of Track $17 @ $2000 + + T0CSx ??? + T0CSE Zero + T0DS0 00:69, remaining Zero + + T0FSx Blank / Not used + T10Sx Blank / Not used + T11Sx Blank / Not used + + T12S0 $???? + T13S0 $???? + T14S0 $???? +``` + +T15S0 $B000 RWTS + +``` + NOTES: + + * $02AA .. $02FF used as disk nibbles decode buffer for $56 bytes + + B000: JMP $B451 ; RWTS_ReadTrack ; Y = Track, A = Addr + B003: JMP $B3ED ; RWTS_ ; TODO + B006: JMP $B422 ; RWTS_ ; TODO + B009: JMP $B0E9 ; RWTS_Seek ; A = Track + B00C: JMP $B462 + B00F: SEC RTS ; Error + + B051: CMP #$D5 + B05B: CMP #$AA + B065: CMP #$AD + B069: Decode #$56 nibbles into $2AA..$2FF + B0DC: CMP #$DE + B0E9: + CHECKSUM = $E1 + HALF_TRACK_PREV = $EC (mirror of $FF) + HALF_TRACK_WANT = $EB + HALF_TRACK_HAVE = $FF ; TODO: FIXME: RWTS_HALFTRACK +``` + +T15S1 $B100 @ $B126:read sector prologue D5 AA 96 [xx yy zz] DE + +``` + B136:CMP #$D5 + B140:CMP #$AA + B14B:CMP #$96 + B172:CMP #$DE + + Valid Disk Nibbles (6-bit * 4) Lookup Table + ;[+0 +1 +2 +3 +4 +5 +6 +7] + ;[+8 +9 +A +B +C +D +E +F] + B196: 00 04 ; -- -- -- -- -- -- 96 97 + B198:98 99 08 0C 9C 10 14 18 ; -- -- 9A 9B -- 9D 9E 9F + B1A0:A0 A1 A2 A3 A4 A5 1C 20 ; -- -- -- -- -- -- A6 A7 + B1A8:A8 A9 AA 24 28 2C 30 34 ; -- -- -- AB AC AD AE AF + B1B0:B0 B1 38 3C 40 44 48 4C ; -- -- B2 B3 B4 B5 B6 B7 + B1B8:B8 50 54 58 5C 60 64 68 ; -- B9 BA BB BC BD BE BF + B1C0:C0 C1 C2 C3 C4 C5 C6 C7 ; -- -- -- -- -- -- -- -- + B1C8:C8 C9 CA 6C CC 70 74 78 ; -- -- -- CB -- CD CE CF + B1D0:D0 D1 D2 7C D4 D5 80 84 ; -- -- -- D3 -- -- D6 D7 + B1D8:D8 88 8C 90 94 98 9C A0 ; -- D9 DA DB DC DD DE DF + B1E0:E0 E1 E2 E3 E4 A4 A8 AC ; -- -- -- -- -- E5 E6 E7 + B1E8:E8 B0 B4 B8 B8 C0 C4 C8 ; -- E9 EA EB EC ED EE EF + B1F0:F0 F1 CC D0 D4 D8 DC E0 ; -- -- F2 F3 F4 F5 F6 F7 + B1F8:F8 E4 E8 EC F0 F4 F8 FC ; -- F9 FA FB FC FD FE FF + +T15S2 $B200 Optimized 6&2 Decode Table + + Notes: + * 4 bytes/nibble + * 4'th byte not used -- used as padding since X*3 = x*2 + x = too slow + * Sequence in psuedo-base 4: 0,2,1,3 + + B200:00 00 00 96 ; [00] + B204:02 00 00 97 ; [01] + B208:01 00 00 9A ; [02] + B20C:03 00 00 9B ; [03] + B210:00 02 00 9D ; [04] + B214:02 02 00 9E ; [05] + B218:01 02 00 9F ; [06] + B21C:03 02 00 A6 ; [07] + B220:00 01 00 A7 ; [08] + B224:02 01 00 AB ; [09] + B228:01 01 00 AC ; [0A] + B22C:03 01 00 AD ; [0B] + B230:00 03 00 AE ; [0C] + B234:02 03 00 AF ; [0D] + B238:01 03 00 B2 ; [0E] + B23C:03 03 00 B3 ; [0F] + + B240:00 00 02 B4 ; [10] + B244:02 00 02 B5 ; [11] + B248:01 00 02 B6 ; [12] + B24C:03 00 02 B7 ; [13] + B250:00 02 02 B9 ; [14] + B254:02 02 02 BA ; [15] + B258:01 02 02 BB ; [16] + B25C:03 02 02 BC ; [17] + B260:00 01 02 BD ; [18] + B264:02 01 02 BE ; [19] + B268:01 01 02 BF ; [1A] + B26C:03 01 02 CB ; [1B] + B270:00 03 02 CD ; [1C] + B274:02 03 02 CE ; [1D] + B278:01 03 02 CF ; [1E] + B27C:03 03 02 D3 ; [1F] + + B280:00 00 01 D6 ; [20] + B284:02 00 01 D7 ; [21] + B288:01 00 01 D9 ; [22] + B28C:03 00 01 DA ; [23] + B290:00 02 01 DB ; [24] + B294:02 02 01 DC ; [25] + B298:01 02 01 DD ; [26] + B29C:03 02 01 DE ; [27] + B2A0:00 01 01 DF ; [28] + B2A4:02 01 01 E5 ; [29] + B2A8:01 01 01 E6 ; [2A] + B2AC:03 01 01 E7 ; [2B] + B2B0:00 03 01 E9 ; [2C] + B2B4:02 03 01 EA ; [2D] + B2B8:01 03 01 EB ; [2E] + B2BC:03 03 01 EC ; [2F] + + B2C0:00 00 03 ED ; [30] + B2C4:02 00 03 EE ; [31] + B2C8:01 00 03 EF ; [32] + B2CC:03 00 03 F2 ; [33] + B2D0:00 02 03 F3 ; [34] + B2D4:02 02 03 F4 ; [35] + B2D8:01 02 03 F5 ; [36] + B2DC:03 02 03 F6 ; [37] + B2E0:00 01 03 F7 ; [38] + B2E4:02 01 03 F9 ; [39] + B2E8:01 01 03 FA ; [3A] + B2EC:03 01 03 FB ; [3B] + B2F0:00 03 03 FC ; [3C] + B2F4:02 03 03 FD ; [3D] + B2F8:01 03 03 FE ; [3E] + B2FC:03 03 03 FF ; [3F] + + T15S3 $B300 + T15S4 $B400 + T15S5 $B500 + T15S6 $B600 Zero, Unused + T15S7 $B700 Zero, Unused + + T15S8 $1800 FORMAT??? + T15S9 $1900 + T15SA $1A00 + T15SB $1B00 + T15SC $1C00 + T15SD $1D00 + T15SE $1E00 + T15SF $1F00 + + T16S0 $0800 Applesoft Utility!! "= [ FANTAVISION MENU ] =" + T16S1 $0900 + T16S2 $0A00 + T16S3 $0B00 + T16S4 $0C00 MOUSE,GRAPHICS TABLET,KOALA PAD,JOYSTICK,CREATE A SHOW DISK, QUIT THIS MENU + T16S5 $0D00 + T16S6 $0E00 + T16S7 $0F00 "INSERT THE MATINEE IN DRIVE 1,", "AND A BLANK DISK IN DRIVE 2." + T16S8 $1000 "DESTROY" + T16S9 $1100 "INSERT THE DESIRED DISK", "UNABLE TO FORMAT." + T16SA $1200 "DRIVE TOO FAST", "DRIVE TOO SLOW", "CAN'T DESTROY FANTAVISION!" + T16SB $1300 last 5 bytes: "5400",0 + T16SC $1400 Blank / Unused + T16SD $1500 Blank / Unused + T16SE $1600 Blank / Unused + T16SF $1700 Blank - reserved for Applesoft variaibles, HIMEM: 2*4096 + + T17S0 $2000 Logo + T17S1 $2100 Logo + T17S2 $2200 Logo + T17S3 $2300 Logo + T17S4 $2400 Logo + T17S5 $2500 Logo + T17S6 $2600 Logo + T17S7 $2700 Logo + T17S8 $2800 Logo + T17S9 $2900 Logo + T17SA $2A00 Logo + T17SB $2B00 Logo + T17SC $2C00 Logo + T17SD $2D00 Logo + T17SE $2E00 Logo + T17SF $2F00 Logo + T18S0 $3000 Logo + T18S1 $3100 Logo + T18S2 $3200 Logo + T18S3 $3300 Logo + T18S4 $3400 Logo + T18S5 $3500 Logo + T18S6 $3600 Logo + T18S7 $3700 Logo + T18S8 $3800 Logo + T18S9 $3900 Logo + T18SA $3A00 Logo + T18SB $3B00 Logo + T18SC $3C00 Logo + T18SD $3D00 Logo + T18SE $3E00 Logo + T18SF $3F00 Logo + + T19S0 $4000 + T19S1 $4100 + T19S2 $4200 "MOVIE MATINEE DISK BLANK SHOW DISKETTE" + T19S3 $4300 Source Assembly Fragment 1 + T19S4 $4400 Table, Source Assembly Fragment 2 + T19S5 $4500 + T19S6 $4600 + T19S7 $4700 + T19S8 $4800 + T19S9 $4900 "FANTAVISIONFORMAT" + T19SA $4A00 + T19SB $4B00 + T19SC $4C00 + T19SD $4D00 + T19SE $4E00 + T19SF $4F00 + + T1AS0 $5000 + T1AS1 $5100 + T1AS2 $5200 + T1AS3 $5300 + T1AS4 $5400 + T1AS5 $5500 + T1AS6 $5600 + T1AS7 $5700 + T1AS8 $5800 + T1AS9 $5900 @ $4E: "(C) 1985 BY SCOTT ANDERSON" + T1ASA $5A00 + T1ASB $5B00 + T1ASC $5C00 + T1ASD $5D00 + T1ASE $5E00 @ $6F: "(C) 1984 BY SCOTT ANDERSON" + T1ASF $5F00 + + T1BS0 $6000 + T1BS1 $6100 + T1BS2 $6200 + T1BS3 $6300 @ $E2: "(C) 1984 BY SCOTT ANDERSON" + T1BS4 $6400 + T1BS5 $6500 @ $8D: "(C) 1984 BY SCOTT ANDERSON" + T1BS6 $6600 + T1BS7 $6700 + T1BS8 $6800 + T1BS9 $6900 + T1BSA $6A00 Icons?? + T1BSB $6B00 Icons?? + T1BSC $6C00 + T1BSD $6D00 + T1BSE $6E00 + T1BSF $6F00 + + T1CS0 $7000 + T1CS0 $7100 + T1CS2 $7200 @59 HGR LookUP Y Table low byte + + Relocated to LC: $FE00 + + 59: $00,$00,$00,$00,$00,$00,$00,$00 ; 0 .. 7 + 61: $80,$80,$80,$80,$80,$80,$80,$80 ; 8 .. 15 + 69: $00,$00,$00,$00,$00,$00,$00,$00 ; 16 .. 23 + 71: $80,$80,$80,$80,$80,$80,$80,$80 ; 24 .. 31 + 79: $00,$00,$00,$00,$00,$00,$00,$00 ; 32 .. 39 + 81: $80,$80,$80,$80,$80,$80,$80,$80 ; 40 .. 47 + 89: $00,$00,$00,$00,$00,$00,$00,$00 ; 48 .. 55 + 91: $80,$80,$80,$80,$80,$80,$80,$80 ; 56 .. 63 + + 99: $28,$28,$28,$28,$28,$28,$28,$28 ; 64 .. 71 + A1: $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8 ; 72 .. 79 + A9: $28,$28,$28,$28,$28,$28,$28,$28 ; 80 .. 87 + B1: $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8 ; 88 .. 95 + B9: $28,$28,$28,$28,$28,$28,$28,$28 ; 96 .. 103 + C1: $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8 ; 104 .. 111 + C9: $28,$28,$28,$28,$28,$28,$28,$28 ; 112 .. 119 + D1: $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8 ; 120 .. 127 + + D9: $50,$50,$50,$50,$50,$50,$50,$50 ; 128 .. 135 + E1: $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0 ; 136 .. 143 + E9: $50,$50,$50,$50,$50,$50,$50,$50 ; 144 .. 151 + F1: $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0 ; 152 .. 159 + F9: $50,$50,$50,$50,$50,$50,$50 ; 160 .. 166 *** spans sector + + T1CS3 $7300 @00 HGR Lookup Y Table, Low byte and High Bytes + 00: $50 ; 167 *** spans sector + 01: $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0 ; 168 .. 175 + 09: $50,$50,$50,$50,$50,$50,$50,$50 ; 176 .. 183 + 11: $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0 ; 184 .. 191 + + HGR Lookup Y Table + Relocated to LC: $FF00 + + 59:00 04 08 0C 10 14 18 1C ; 0 .. 7 + 61:00 04 08 0C 10 14 18 1C ; 8 .. 15 + 69:01 05 09 0D 11 15 19 1D ; 16 .. 23 + 71:01 05 09 0D 11 15 19 1D ; 24 .. 31 + 79:02 06 0A 0E 12 16 1A 1E ; 32 .. 39 + 81:02 06 0A 0E 12 16 1A 1E ; 40 .. 47 + 89:03 07 0B 0F 13 17 1B 1F ; 48 .. 55 + 91:03 07 0B 0F 13 17 1B 1F ; 56 .. 63 + + 99:00 04 08 0C 10 14 18 1C ; 64 .. 71 + A1:00 04 08 0C 10 14 18 1C ; 72 .. 79 + A9:01 05 09 0D 11 15 19 1D ; 80 .. 87 + B1:01 05 09 0D 11 15 19 1D ; 88 .. 95 + B9:02 06 0A 0E 12 16 1A 1E ; 96 .. 103 + C1:02 06 0A 0E 12 16 1A 1E ; 104 .. 111 + C9:03 07 0B 0F 13 17 1B 1F ; 112 .. 119 + D1:03 07 0B 0F 13 17 1B 1F ; 120 .. 127 + + D9:00 04 08 0C 10 14 18 1C ; 128 .. 135 + E1:00 04 08 0C 10 14 18 1C ; 136 .. 143 + E9:01 05 09 0D 11 15 19 1D ; 144 .. 151 + F1:01 05 09 0D 11 15 19 1D ; 152 .. 159 + F9:02 06 0A 0E 12 16 1A ; 160 .. 166 *** spans sector + + T1CS4 $7400 + 00: 1E ; 167 *** spans sector + 01:02 06 0A 0E 12 16 1A 1E ; 168 .. 175 + 09:03 07 0B 0F 13 17 1B 1F ; 176 .. 183 + 11:03 07 0B 0F 13 17 1B 1F ; 184 .. 191 + + LC:$FEC0: + + LC:$FEDB + FEDD: BE C0 FE LDX $FEC0,Y + FEE0: BD 00 FB LDA $FB00,X + FEE3: 10 02 BPL $FEE7 + FEE5: A9 13 LDA #$13 + FEE7: 29 3F AND #$3F + FEE9: D0 02 BNE $FEED + FEEB: A9 20 LDA #$20 + FEED: 99 00 04 STA $0400,Y + FEF0: 88 DEY + FEF1: 10 EA BPL $FEDD + FEF3: 60 RTS + + T1CS5 $7500 + T1CS6 $7600 + T1CS7 $7700 + T1CS8 $7800 + T1CS9 $7900? @74 Main menu: File, and Edit + + Note: K = Next key frame + + 33: Pointer $DCF2 + 35: Pointer $DCF3 + 37: Pointer $0700 + 39: Pointer $DCF7 + 3B: Pointer $DCFB + 3D: Pointer $1C08 + 3F: Pointer $DD71 + 41: Pointer $DD75 + 43: Pointer $4606 + 45: Pointer $DDA5 + 47: Pointer $DDAC + 49: Pointer $7005 + 4B: Pointer $3FC0 TODO: HGR Screen Hole + + 50: "File" MENU + 54: "L" @ $DD1B accelerator = File | Load Movie + 58: "S" @ $DD25 accelerator = File | Save Movie + 5C:0x18 @ $DD2F accelerator = File | Clear Movie (Ctrl-X), can use Y/N + 60: "D" @ $DD3A accelerator = File | Load Backdrop + 64: "B" @ $DD47 accelerator = File | Save Backdrop -> "Screen name:" + 68: "W" @ $DD54 accelerator = File | Clear Backdrop + 6C: "F" @ $DD62 accelerator = File | Format Disk + 70: "Q" @ $DD6D accelerator = File | Quit + 74: "Load Movie" + "Save Movie" + "Clear Movie" + "Load Backdrop" + "Save Backdrop" + "Clear Backdrop" + "Format Disk" + "Quit" + "Edit" MENU + CE: "Z" @ $DD8D accelerator = Edit | Undo + D2: "X" @ $DD91 accelerator = Edit | Cut + D6: "C" @ $DD94 accelerator = Edit | Copy + DA: "V" @ $DD98 accelerator = Edit | Paste + DE: "K" @ $DD9D accelerator = Edit | Clone + E2: "^" @ $DDA2 accelerator = Edit | Zap frame (Shift-6) + E6: "Undo" + "Cut" + "Copy" + "Paste" + "Clone" + "Zap" + "Go" MENU + + T1CSA $7A00 Main menu: Goodies + + 00: "oodies" + 05:0x1A @ $DDC0 accelerator = Goodies | Zoom (Ctrl-Z), top menu: Right/Left Left/Right + 09:0x14 @ $DDC4 accelerator = Goodies | Turn (Ctrl-T), top menu: Counter-Clockwise / Clockwise + 0D:0x0C @ $DDC8 accelerator = Goodies | Lean (Ctrl-L), top menu: Left/Right + 11:0x06 @ $DDCC accelerator = Goodies | Flip (Ctrl-F), top menu: Left/Right Up/Down + 15:0x13 @ $DDD0 accelerator = Goodies | Squash (Ctrl-S), top menu: Up / Down" + 19: "Zoom" + "Turn" + "Lean" + "Flip" + "Squash" + + T1DS0 $8000 + T1DS1 $8100 + T1DS2 $8200 + T1DS3 $8300 + T1DS4 $8400 + T1DS5 $8500 + T1DS6 $8600 + T1DS7 $8700 + T1DS8 $8800 + T1DS9 $8900 + T1DSA $8A00 + T1DSB $8B00 + T1DSC $8C00 + T1DSD $8D00 + T1DSE $8E00 + T1DSF $8F00 + + T1ES0 $9000 + T1ES1 $9100 + T1ES2 $9200 + T1ES3 $9300 + T1ES4 $9400 + T1ES5 $9500 + T1ES6 $9600 + T1ES7 $9700 + T1ES8 $9800 + T1ES9 $9900 + T1ESA $9A00 + T1ESB $9B00 + T1ESC $9C00 + T1ESD $9D00 + T1ESE $9E00 + T1ESF $9F00 + + T1FS0 $A000 + T1FS1 $A100 + T1FS2 $A200 + T1FS3 $A300 + T1FS4 $A400 + T1FS5 $A500 + T1FS6 $A600 UNUSED Make Scripts + T1FS7 $A700 DOS 3.3: FTOC Track/Sector List: T1BS04 T1BS03 T1BS02 + T1FS8 $A800 @ $2D: DOS3.3 FILENAME: "UP.D2" + T1FS9 $A900 DOS 3.3: FTOC Track/Sector List: T1CS0E + T1FSA $AA00 @ $82: DOS3.3 FILENAME: "PATCH" + T1FSB $AB00 + T1FSC $AC00 + T1FSD $AD00 + T1FSE $AE00 + T1FSF $AF00 + + T20S0 $0800 Backup Version A + T20S1 $0900 Backup Version A + T20S2 $0A00 Backup Version A + T20S3 $0B00 Backup Version A + T20S4 $0C00 Backup Version A + T20S5 $0D00 Backup Version A + T20S6 $0E00 Backup Version A + T20S7 $0F00 Backup Version A + T20S8 $3800 Logo bottom 1/4, same as T18S8 and T21S8 + T20S9 $3900 Logo bottom 1/4, same as T18S9 and T21S9 + T20SA $3A00 Logo bottom 1/4, same as T18SA and T21SA + T20SB $3B00 Logo bottom 1/4, same as T18SB and T21SB + T20SC $3C00 Logo bottom 1/4, same as T18SC and T21SC + T20SD $3D00 Logo bottom 1/4, same as T18SD and T21SD + T20SE $3E00 Logo bottom 1/4, same as T18SE and T21SE + T20SF $3F00 Logo bottom 1/4, same as T18SF and T21SF + + T21S0 $0800 Backup Version B + T21S1 $0900 Backup Version B + T21S2 $0A00 Backup Version B + T21S3 $0B00 Backup Version B + T21S4 $0C00 Backup Version B + T21S5 $0D00 Backup Version B + T21S6 $0E00 Backup Version B + T21S7 $0F00 Backup Version B + T21S8 $3800 Logo bottom 1/4, same as T18S8 + T21S9 $3900 Logo bottom 1/4, same as T18S9 + T21SA $3A00 Logo bottom 1/4, same as T18SA + T21SB $3B00 Logo bottom 1/4, same as T18SB + T21SC $3C00 Logo bottom 1/4, same as T18SC + T21SD $3D00 Logo bottom 1/4, same as T18SD + T21SE $3E00 Logo bottom 1/4, same as T18SE + T21SF $3F00 Logo bottom 1/4, same as T18SF + + T22S? $BC00 + T22S? $BD00 + T22S? $BE00 Boot Stage 4 + T22S? $BF00 +``` + +* NOTE: Track $22 has a single sector of 4 pages. + + +# Easter Eggs + +## Source Code + +There are partial copies of the source code left on the disk! +Track $19, Sectors 4 and 3 have these gems, respectively: + +* Track $19, Sector 4 + +```Assembly +pag + + + DFB DialA+2 + DA Mess9 + hex FE ;yes/no + hex 15 ;HTAB 4 + + DFB DialA+2 + DA Mess10 + h +``` + +* Track $19, Sector 3 + +```Assembly +a + +Dialog0 + DFB MenuA ;area + DA Mess0 + DFB 0 ;input len + hex 14 ;HTab 1*4,Vtab 4; + DFB DialA + DA Mess1 + DFB 0 + hex 14 + + DFB BDrpA + DA Mess2 + DFB 0 + hex 4C + + DFB DialA+2 + DA Mess3 + hex FF ;get button + hex 44 ;H16,V4 + + DFB DialA+2 + DA Mess4 + hex FF + hex 14 +``` + + +## Original Files Names + +Track $1F, Sector $6 has this gem of a build script! + +``` + 600.160F + ... + BLOAD O:FLB000 ,A$1000 + BLOAD O:RDB500 ,A$1500 + BLOAD O:RWTS1800 ,A$1800 + 1000<1500.150F + ... + BLOAD FANTAVISION,$1000 + 41D6:18 60 + BLOAD F.PATCH,A$306C + 1000<1700.1F0F + ... + BLOAD O:BACKUP,A$2000 + 2000<2000.200F + ... DONE + FP + @ + BLOAD FANTA +``` + +NOTES: + +* There is no space after the ####.####F but I included one to make the `Control` characters easier to read + + +Here is a quick analysis on the filenames: + +``` + Filename: FL = Fantavision Loader ??? + vv + BLOAD O:FLB000,A$1000 + $B000 + ^^^^ + Load address + + Filename: RD = Read Disk ??? Roland's Disk protection??? + vv + BLOAD O:RDB500,A$1500 + $B500 + ^^^^ + Load address + BLOAD O:RWTS1800,A$1800 +``` + +## Easter Egg: Deleted Files!? + +If we boot Copy \]\[+ 8.0 and choose `UNDELETE FILES` +we find there are 4 deleted files on our `Fanta.COPYA` ! + +``` + M.APPLE2 BIN 4 + M.SHADOWTRIXKS BIN 8 + M.MORFIC BIN 5 + M.VOLCANO BIN 5 +``` + + + +# In Search of a Better Beep, or two + +Some of us Apple fans take our BEEP pretty serious. + +* [Apple IIc Plus – Fixing the Beep](http://quinndunki.com/blondihacks/?p=2471) + +Fantavision has a nice "soft beep" instead of the classic "hard beep" + +```asm + F8.Wait = $FCA8 + Squeeker = $C030 ; Technically it is a speaker but who are we kidding here. This is no SID chip. + + ORG $0902 + SoftBeep + 0902:A0 20 LDY #$20 + SoftCycle + 0904:A9 02 LDA #$02 ;+ + 0906:20 A8 FC JSR F8.Wait + 0909:8D 30 C0 STA Squeeker + + 090C:A9 24 LDA #$24 + 090E:20 A8 FC JSR F8.Wait + 0911:8D 30 C0 STA Squeeker + + 0914:88 DEY + 0915:D0 ED BNE SoftCycle ;^ $0904 + 0917:60 RTS +``` + +Fantavision also has Roland Gustafsson classic 'RW18' error "ZAP" @ $B380. +(Track $15, Sector $3) + +```asm + Read16Sec: + B333:A2 0F LDX #$0F ; 16 sectors to load from track + ; ... + B34B:F0 31 BEQ ReadError ; if failed to read disk ... + + ReadError: + B37E:38 SEC + B37F:EA NOP ; *** SELF-MODIFIED to be RTS $60 + B380:A0 00 LDY #$00 ; Br0derbund "ZAP" sound + ^1 + B382:AD 30 C0 LDA $C030 + B385:98 TYA + ^2 + B386:38 SEC + B387:E9 01 SBC #$01 + B389:D0 FB BNE ^2 ;^ $B386 + B38B:88 DEY + B38C:D0 F4 BNE ^1 ;^ $B382 + B38E:4C 33 B3 JMP $B333 ;^ $B333 +``` + + +