mirror of
https://github.com/Michaelangel007/apple2_fantavision_reloaded.git
synced 2024-09-30 05:56:59 +00:00
3000 lines
88 KiB
Markdown
3000 lines
88 KiB
Markdown
# 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
|
||
9600<C600.C6FFM
|
||
96FA:1F
|
||
1F01:00
|
||
9600G
|
||
```
|
||
|
||
We end up with this "error" screen:
|
||
|
||
```
|
||
1F03- A=01 X=60 Y=00 P=31 S=F0
|
||
*
|
||
```
|
||
|
||
Let's turn off that drive motor so we don't wear the drive (and disk) out.
|
||
|
||
```
|
||
C0E8:1
|
||
```
|
||
|
||
We want to save this puppy so let's move the Boot Stage 1 to a safe place ...
|
||
|
||
```
|
||
3800<800.8FFM
|
||
```
|
||
|
||
... and reboot with our `Fanta.Work` disk so we can save it.
|
||
|
||
I already have a work ProntoDOS disk in Drive 5 so I'll be using ...
|
||
|
||
```
|
||
C500G
|
||
```
|
||
|
||
... but if you only have 1 drive you'll just need to flip disks more often.
|
||
Anytime you see `C500G` replace it with:
|
||
|
||
```
|
||
C600G
|
||
```
|
||
|
||
Once we are back in DOS land we can save it.
|
||
|
||
```
|
||
800<3800.38FFM
|
||
BSAVE B1.FANTAVISION_T00S0_0800,A$800,L$100
|
||
```
|
||
|
||
Now that we have the boot sector saved let's tear into it and see what it is doing.
|
||
Now I could be a jerk and hand-wave it as
|
||
|
||
* _"Implementation Details"_ or the equally annoying
|
||
* _"Left as an Exercise for the Reader"_
|
||
|
||
but I'll be nice guy and provide a fully documented disassembly:
|
||
|
||
```asm
|
||
; P5 PROM Drive Usage ZP and IO
|
||
P5.Buff = $26 ; 16-bit pointer to dest
|
||
P5.SlotX16 = $2B ; i.e. $60 = Slot 6
|
||
P5.WantTrack= $41 ;
|
||
|
||
P5.SecLoaded= $3D ;
|
||
P5.SecTotal = $0800 ; Boot Sector contains total number of sectors to load
|
||
|
||
PHASEMSAK = $03 ; 4 phases
|
||
PHASEOFF = $C080
|
||
PHASEON = $C081
|
||
DRIVE_DATA = $C08C
|
||
|
||
; Globals
|
||
SEEK_HALFTRACK = $50
|
||
HAVE_HALFTRACK = $51
|
||
NumSecLeft = $52
|
||
BufZP = $1000 ; Zero Page is saved here
|
||
|
||
RWTS_SLOTx16 = $FD
|
||
RWTS_HALFTRACK = $FF ;
|
||
|
||
ReadBoot3 = $B500
|
||
LoadBoot3 = $BC00
|
||
ExecBoot3 = $BE00
|
||
|
||
; Misc.
|
||
RESET = $3F2 ; Ctrl-Reset Vector + Checksum
|
||
TXTHOLE31 = $4FB ; 40x24 Text Sceen Hole
|
||
|
||
; IO Switches
|
||
STORE40 = $C000 ; W
|
||
ALTZPOFF = $C008
|
||
CLR80VID = $C00C
|
||
CLRALTCHAR = $C00E ; Turn off Mouse Text
|
||
DHIRESOFF = $C05F
|
||
|
||
ROMIN = $C081
|
||
|
||
; F800 ROM Entry Points
|
||
F8.INIT = $FB2F ;
|
||
F8.HOME = $FC58 ; Clear 40x24 text screen
|
||
F8.SETNORM = $FE84 ;
|
||
F8.SETVID = $FE93 ; PR#0
|
||
F8.SETKBD = $FE89 ; IN#0
|
||
|
||
ORG $800
|
||
|
||
0800:01 DFB $01 ; Tell P5 PROM to read only 1 Sector
|
||
Boot1: ; A=01 X=60 Y=00 P=31 S=F0 Boot Stage #1 Entry Point from $C6F8
|
||
0801:A9 60 LDA #$60 ; Save "RTS" @ $0801 so that when we call
|
||
0803:8D 01 08 STA Boot1 ; `CallReadSec` it will return to NextSector @ $086F
|
||
|
||
0806:A2 00 LDX #$00 ; Save _absolute_ track the drive head is on
|
||
0808:86 FF STX RWTS_HALFTRACK ; since we can only move _relative_ tracks
|
||
|
||
080A: SaveZP: ; Copy $0000[ $00 .. $FF ] to $1000
|
||
080A:B5 00 LDA $00,X ; Just in case ALTZPON was accidently left on
|
||
080C:9D 00 10 STA BufZP,X ;
|
||
080F:E8 INX ;
|
||
0810:D0 F8 BNE SaveZP ;^ $080A
|
||
|
||
0812:8D 08 C0 STA ALTZPOFF ; //e+, //c, IIgs, Laser 128
|
||
|
||
LoadZP: ;
|
||
0815:BD 00 10 LDA BufZP,X ;
|
||
0818:95 00 STA $00,X ;
|
||
081A:E8 INX ;
|
||
081B:D0 F8 BNE LoadZP ;^ $0815
|
||
|
||
081D:A9 FF LDA #$FF ;
|
||
081F:8D FB 04 STA TXTHOLE31 ; Screen Text Hole Slot 3, Temp 1
|
||
|
||
0822:8D F3 03 STA RESET+1 ; Make Ctrl-Reset
|
||
0825:8D F4 03 STA RESET+2 ; do warm restart @ TODO: FIXME:
|
||
|
||
0828:8D 00 C0 STA STORE40 ;
|
||
082B:8D 0C C0 STA CLR80VID ;
|
||
082E:8D 0E C0 STA CLRALTCHAR ;
|
||
0831:8D 5F C0 STA DHIRESOFF ;
|
||
0834:8D 81 C0 STA ROMIN ;
|
||
|
||
0837:20 2F FB JSR F8.INIT ;
|
||
083A:20 58 FC JSR F8.HOME ; Clear 40x24 text screen
|
||
083D:20 84 FE JSR F8.SETNORM ;
|
||
0840:20 93 FE JSR F8.SETVID ; PR#0
|
||
0843:20 89 FE JSR F8.SETKBD ; IN#0
|
||
|
||
0846:A6 2B LDX P5SLOTx16 ; X=60 = Drive Slot * $10
|
||
0848:8A TXA ;
|
||
0849:4A LSR ;
|
||
084A:4A LSR ;
|
||
084B:4A LSR ;
|
||
084C:4A LSR ; A=06
|
||
084D:09 C0 ORA #$C0 ; A=C6 = $Cx00 = Memory-Mapped IO: i.e. $C6 = slot 6 P5 PROM
|
||
084F:8D 6E 08 STA CallReadSec+2 ; *** SELF-MODIFYING Code !
|
||
|
||
0852:A9 0F LDA #$0F ; Num Sectors to Read
|
||
0854:85 52 STA NumSecLeft ;
|
||
0856:A9 15 LDA #$15 ; Track $15 contains Boot Stage 2
|
||
0858:85 41 STA P5.WantTrack ;
|
||
085A:0A ASL ; $15 * 2 = $2A Half-Tracks
|
||
085B:20 81 08 JSR HalfTrackSeek ;v $0881
|
||
|
||
LoadSector:
|
||
085E:A5 52 LDY NumSecLeft ;
|
||
0860:B9 BE 08 LDA LogicalSector,Y ;
|
||
0863:85 3D STA P5SECTOR ;
|
||
0865:B9 CE 08 LDA DestPage,Y ;
|
||
0868:F0 05 BEQ NextSector ;v $086F Never read into Zero Page!
|
||
086A:85 27 STA P5.Buff+1 ; Tell P5PROM where in mem we want to load
|
||
|
||
CallReadSec: ; *** SELF-MODIFIED @ $084F
|
||
086C:20 5C 00 JSR $005C ; CALL P5 PROM Read Sector @ $C65C
|
||
|
||
NextSector:
|
||
086F:C6 52 DEC NumSecLeft ;
|
||
0871:10 EB BPL LoadSector ;^ $085E
|
||
|
||
TestBoot3: ; Boot Stage 2 done, do stage 3
|
||
0873:A6 2B LDX P5.SlotX16 ;
|
||
0875:86 FD STX RWTS_SLOTx16 ;
|
||
0877:A9 BC LDA #>LoadBoot3 ; 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:
|
||
|
||
```asm
|
||
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
|
||
4000<B000.B7FFM
|
||
```
|
||
|
||
Boot to our `Fanta.Work` disk ...
|
||
|
||
```
|
||
C500G
|
||
```
|
||
|
||
... so we can save it:
|
||
|
||
```
|
||
BSAVE B2.FANTAVISION_T15_B000,A$4000,L$800
|
||
```
|
||
|
||
|
||
# Boot Tracing Stage 2
|
||
|
||
Once the entire track $15 of Stage 2 is read in it is executed to read Stage 3.
|
||
|
||
```asm
|
||
TestBoot3: ; Boot Stage 2 done, do stage 3
|
||
0873:A6 2B LDX P5.SlotX16 ;
|
||
0875:86 FD STX RWTS_SLOTx16 ;
|
||
0877:A9 BC LDA #>LoadBoot3 ; 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
|
||
BE16:A9 BE LDA #>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. `<CTRL-C>`
|
||
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 <NO DATE>
|
||
M.CANCAN BIN 4 <NO DATE>
|
||
M.TREE BIN 5 <NO DATE>
|
||
M.OBJECTS BIN 3 <NO DATE>
|
||
M.DIVE BIN 4 <NO DATE>
|
||
M.FACE BIN 3 <NO DATE>
|
||
M.PEOPLE BIN 4 <NO DATE>
|
||
M.REDWHITEBLUE BIN 3 <NO DATE>
|
||
M.ENGLISHFONT BIN 10 <NO DATE>
|
||
M.SLANTFONT BIN 4 <NO DATE>
|
||
M.ORBITFONT BIN 4 <NO DATE>
|
||
M.DOTS2FONT BIN 6 <NO DATE>
|
||
M.CIRCUITFONT BIN 5 <NO DATE>
|
||
M.DOTSFONT BIN 6 <NO DATE>
|
||
M.OUTLINEFONT BIN 8 <NO DATE>
|
||
M.LAND BIN 3 <NO DATE>
|
||
|
||
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 <Ctrl-Y>
|
||
...
|
||
BLOAD O:FLB000 ,A$1000
|
||
BLOAD O:RDB500 ,A$1500
|
||
BLOAD O:RWTS1800 ,A$1800
|
||
1000<1500.150F <Ctrl-Y>
|
||
...
|
||
BLOAD FANTAVISION,$1000
|
||
41D6:18 60
|
||
BLOAD F.PATCH,A$306C
|
||
1000<1700.1F0F <Ctrl-Y>
|
||
...
|
||
BLOAD O:BACKUP,A$2000
|
||
2000<2000.200F <Ctrl-Y>
|
||
...<Ctrl-C> DONE <Ctrl-G>
|
||
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 <NO DATE>
|
||
M.SHADOWTRIXKS BIN 8 <NO DATE>
|
||
M.MORFIC BIN 5 <NO DATE>
|
||
M.VOLCANO BIN 5 <NO DATE>
|
||
```
|
||
|
||
|
||
|
||
# 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
|
||
```
|
||
|
||
|
||
|