From c9af84fa277032f739ee607f98c89905655e1c57 Mon Sep 17 00:00:00 2001 From: 4am Date: Mon, 2 Oct 2023 23:42:07 -0400 Subject: [PATCH] add support for JMP600 bootloader [fixes Wizard of Words v1.0] --- src/apicode.a | 6 +++ src/apidefs.a | 8 +++- src/id/bootfailure.a | 5 +++ src/id/inspect0.a | 13 ++++++ src/id/jmp600.a | 47 +++++++++++++++++++ src/modify.a | 42 +++++++++++++++++ src/mods/t00only.a | 1 + src/passport.a | 1 + src/patchers/t00_jmp600.a | 90 +++++++++++++++++++++++++++++++++++++ src/patchers/t00_laureate.a | 30 +++++-------- src/strings/en.a | 6 ++- src/strings/enid.a | 1 + 12 files changed, 227 insertions(+), 23 deletions(-) create mode 100644 src/id/jmp600.a create mode 100644 src/patchers/t00_jmp600.a diff --git a/src/apicode.a b/src/apicode.a index ac3d32e..fb3db19 100644 --- a/src/apicode.a +++ b/src/apicode.a @@ -37,6 +37,8 @@ jmp modify2 ;jmodify3 jmp modify3 +;jmultimodify + jmp multimodify ;jcompare jmp compare ;jcompare1 @@ -79,6 +81,10 @@ ; set in IDBootFailure() after reading T00 FIRSTFILTER +;gIsJMP600 + !byte FALSE ; 0=true, 1=false + ; reset before each operation + ; set in IDBootloader() after reading T00,S00 ;gIsDidatech !byte FALSE ; 0=true, 1=false ; reset before each operation diff --git a/src/apidefs.a b/src/apidefs.a index a6941a6..e005519 100644 --- a/src/apidefs.a +++ b/src/apidefs.a @@ -185,9 +185,10 @@ gIsLowDOS = gPossibleB4BBBasic-$01 ; byte gIsBaudville = gIsLowDOS-$01 ; byte gIsEnlightenment = gIsBaudville-$01 ; byte gIsDidatech = gIsEnlightenment-$01 ; byte +gIsJMP600 = gIsDidatech-$01 ; byte ;LASTFILTER ; add new gIs* above this line ;gIsInfocom18 is a special case whose ID is not in the regular inspection path -gIsInfocom18 = gIsDidatech-$01 ; byte +gIsInfocom18 = gIsJMP600-$01 ; byte ;gIs13Sector is a special case whose ID is not in the regular inspection path gIs13Sector = gIsInfocom18-$01 ; byte ;gMECCFastloadType is a special case integer whose default value cannot be #FALSE @@ -203,7 +204,8 @@ jcompare3 = gDisplayBytes-$03 ; 3-byte jcompare2 = jcompare3-$03 ; 3-byte jcompare1 = jcompare2-$03 ; 3-byte jcompare = jcompare1-$03 ; 3-byte -jmodify3 = jcompare-$03 ; 3-byte +jmultimodify = jcompare-$03 ; 3-byte +jmodify3 = jmultimodify-$03 ; 3-byte jmodify2 = jmodify3-$03 ; 3-byte jmodify1 = jmodify2-$03 ; 3-byte jmodify = jmodify1-$03 ; 3-byte @@ -226,6 +228,7 @@ modify = jmodify modify1 = jmodify1 modify2 = jmodify2 modify3 = jmodify3 +multimodify = jmultimodify PrintByID = jPrintByID SearchTrack = jSearchTrack CallRWTS = jCallRWTS @@ -302,6 +305,7 @@ ConstructStandardDelivery = jConstructStandardDelivery !warn "gDisplayBytes=",gDisplayBytes !warn "jcompare=",jcompare !warn "jmodify=",jmodify +!warn "jmultimodify=",jmultimodify !warn "jPrintByID=",jPrintByID !warn "jSearchTrack=",jSearchTrack !warn "jCallRWTS=",jCallRWTS diff --git a/src/id/bootfailure.a b/src/id/bootfailure.a index 27daab2..a5b67d2 100644 --- a/src/id/bootfailure.a +++ b/src/id/bootfailure.a @@ -63,6 +63,7 @@ VerifyInfocom18 beq .setcount ; passport-test-suite/Trinity - Side B.woz [Z=1] here lda #$02 ; passport-test-suite/Time Lord.woz [Z=0] here ; only two sectors when in ID mode + .setcount sta tmp ; sector counter @@ -422,3 +423,7 @@ read13 lda $C0E8 rts } + +; this prevents branches in this file from crossing a page +; (adjust as necessary) +filler !fill 9 diff --git a/src/id/inspect0.a b/src/id/inspect0.a index d590053..1b493df 100755 --- a/src/id/inspect0.a +++ b/src/id/inspect0.a @@ -148,6 +148,19 @@ IDBootloader jmp Trace8B3 .not8b3 ; +; Try to identify a bootloader that loads several sectors +; into the text page before loading a non-standard RWTS in +; higher memory. +; Exit via custom trace function if found. +; + +IDJMP600 + bcs .notjmp600 + jsr PrintByID + !byte s_jmp600 + sta gIsJMP600 ; A = 0 (TRUE) + jmp FoundJMP600 +.notjmp600 +; ; Try to identify all the different MECC fastloader variants. ; Exit via custom trace function if found. ; (in A=0,X=0; out A=0,X=0) diff --git a/src/id/jmp600.a b/src/id/jmp600.a new file mode 100644 index 0000000..57d6d4f --- /dev/null +++ b/src/id/jmp600.a @@ -0,0 +1,47 @@ +;------------------------------------------------------------------------------ +; IDJMP600 +; identify JMP600 bootloader +; custom boot sector uses its own RWTS to load one or more sectors into the +; text page and eventually jumps to $600 which uses a second RWTS to load +; and jump to a third RWTS at $B700 +; +; in: track buffer contains T00,S00 +; A = 0 +; X = 0 +; out: C clear if JMP600 bootloader was found +; C set if not found +; A = 0 +; X = 0 +; all other registers & flags clobbered +;------------------------------- +!macro IDJMP600 { + ldy #$11 + jsr compare + !byte $01,$A2,$00,$BD,$00,$08,$9D,$00 + !byte $02,$E8,$D0,$F7,$4C,$0F,$02,$A9 + !byte $A0 + ; passport-test-suite/Competition Karate.woz [C=0] matches +} + +FoundJMP600 +; +; We found a JMP600 bootloader. Now we create +; an RWTS that can read the rest of the disk. +; Starting with our built-in RWTS, we modify address +; and data prologues based on the parameters of the +; original disk. +; + lda $84A + lsr + sta UNIV_A1 + lda $853 + sta UNIV_A2 + lda $85D + sta UNIV_A3 + lda $888 + sta UNIV_D1 + lda $891 + sta UNIV_D2 + lda $89B + sta UNIV_D3 + jmp ADStyle diff --git a/src/modify.a b/src/modify.a index bc06d22..5d0152c 100755 --- a/src/modify.a +++ b/src/modify.a @@ -90,3 +90,45 @@ mod_tmp_y=*+1 ldy #$FD ; SMC clv rts + +multimodify +; in: (A/Y) -> sector+offsets+values block +; X = number of values (must also be equal number of sectors and offsets) +; out: all registers/flags clobbered + sta @getsector+1 + sty @getsector+2 + stx @loop+1 + clc + adc @loop+1 + bcc + + iny ++ sta @getoffset+1 + sty @getoffset+2 + clc + adc @loop+1 + bcc + + iny ++ sta @getvalue+1 + sty @getvalue+2 + jmp @next +@loop + ldy #$FD ; SMC +@getvalue + lda $FDFD, y ; SMC + sta @cmpvalue + sta @modvalue +@getsector + lda $FDFD, y ; SMC +@getoffset + ldx $FDFD, y ; SMC + jsr compare1 +@cmpvalue + !byte $FD ; SMC + bcc @next + jsr modify1 +@modvalue + !byte $FD ; SMC +@next + dec @loop+1 + bpl @loop + rts diff --git a/src/mods/t00only.a b/src/mods/t00only.a index 44cca6c..473a9bf 100644 --- a/src/mods/t00only.a +++ b/src/mods/t00only.a @@ -101,6 +101,7 @@ T00_IsNotRWTS !source "../patchers/t00_baudville.a" !source "../patchers/t00_enlightenment.a" !source "../patchers/t00_scottforesman.a" + !source "../patchers/t00_jmp600.a" rts !if * > $3200 { diff --git a/src/passport.a b/src/passport.a index f84cbd3..823455e 100755 --- a/src/passport.a +++ b/src/passport.a @@ -76,6 +76,7 @@ NonRelocatable !source "id/davidson.a" !source "id/holle.a" !source "id/phoenix.a" + !source "id/jmp600.a" !source "id/555.a" !source "id/trace32.a" !source "id/trace8b3.a" diff --git a/src/patchers/t00_jmp600.a b/src/patchers/t00_jmp600.a new file mode 100644 index 0000000..ba2434d --- /dev/null +++ b/src/patchers/t00_jmp600.a @@ -0,0 +1,90 @@ +;------------------------------------------------------------------------------ +; #JMP600 +; custom boot sector uses its own RWTS to load one or more sectors into the +; text page and eventually jumps to $600 which uses a second RWTS to load +; and jump to a third RWTS at $B700 +; +; tested on +; - Dinosaurs v1.0 (Advanced Ideas) +; - Wizard of Words v1.0 (Advanced Ideas) +;------------------------------------------------------------------------------ +; +; common to all variants: +; +; T00,S00,$4A: -> D5 +; T00,S00,$53: -> AA +; T00,S00,$5D: -> 96 +; +; T00,S00,$88: -> D5 +; T00,S00,$91: -> AA +; T00,S00,$9B: -> AD +; +; T00,S03,$1A: -> D5 +; T00,S03,$23: -> AA +; T00,S03,$2D: -> 96 +; +; T00,S03,$57: -> D5 +; T00,S03,$60: -> AA +; T00,S03,$6A: -> AD +; +; That's all that's required for the 'basic' version (e.g. Wizard of Words v1.0). +; Its final RWTS loaded into $B700+ is custom but seamlessly supports both +; reading and reading of both protected and unprotected disks. However, there +; are several variants in use. Some variants require additional patches because +; - they don't support reading from unprotected disks (e.g. In Search of the Most Amazing Thing), or +; - they don't support writing to unprotected disks, or +; - they support writing to disks but in some other protected format that is +; different than the program disk (e.g. Competition Karate, Amazon) + +; e.g. Competition Karate / Amazon variant: +; +; T00,S06,$53: -> D5 +; T00,S06,$58: -> AA +; T00,S06,$5D: -> AD +; T00,S06,$9E: -> DE +; T00,S06,$A3: -> AA +; T00,S06,$A8: -> EB +; +; T00,S07,$46: -> D5 +; T00,S07,$4B: -> AA +; T00,S07,$50: -> 96 +; T00,S07,$7A: -> DE +; T00,S07,$7F: -> AA +; T00,S07,$84: -> EB +; +; T00,S08,$74: -> D5 +; T00,S08,$82: -> AA +; T00,S08,$91: -> 96 +; +; TODO need to test on real hardware and see if these are sufficient: +; T00,S06,$49: -> 04 to restore standard timing +; T00,S07,$D2: -> 2C to burn fewer cycles +; T00,S08,$6C: -> 2C to burn fewer cycles +; +;.competitionkaratemulti ; length=21 dec +; !byte $08,$08,$08,$08,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$06,$06,$06,$06,$06,$06,$06 +; !byte $91,$82,$74,$6C,$F7,$E8,$DA,$D2,$84,$7F,$7A,$50,$4B,$46,$A8,$A3,$9E,$5D,$58,$53,$49 +; !byte $96,$AA,$D5,$2C,$AD,$AA,$D5,$2C,$EB,$AA,$DE,$96,$AA,$D5,$EB,$AA,$DE,$AD,$AA,$D5,$04 + +!zone { + ; gTrack = 0 + lda gIsJMP600 + beq .start + jmp .exit + +.jmp600multi ; length=12 dec +;sectors + !byte $03,$03,$03,$03,$03,$03,$00,$00,$00,$00,$00,$00 +;offsets + !byte $6A,$60,$57,$2D,$23,$1A,$9B,$91,$88,$5D,$53,$4A +;values + !byte $AD,$AA,$D5,$96,$AA,$D5,$AD,$AA,$D5,$96,$AA,$D5 + +.start + lda #<.jmp600multi + ldy #>.jmp600multi + ldx #12 + jsr multimodify + +.exit +} diff --git a/src/patchers/t00_laureate.a b/src/patchers/t00_laureate.a index a66c70a..83a3b3f 100644 --- a/src/patchers/t00_laureate.a +++ b/src/patchers/t00_laureate.a @@ -6,31 +6,21 @@ !zone { lda gIsLaureate bne .exit - beq + ; passport-test-suite/Sound Ideas- Word Attack - Disk 1 - Ending Consonants.woz [Z=1] reaches here + beq .start ; passport-test-suite/Sound Ideas- Word Attack - Disk 1 - Ending Consonants.woz [Z=1] reaches here -.sectors +.laureatemulti +;sectors !byte $04,$04,$04,$04,$04,$04,$04,$04,$04,$05,$05,$05,$05,$05,$05,$05,$06,$06,$06 -.offsets +;offsets !byte $53,$58,$5D,$9E,$A3,$A8,$E7,$F1,$FC,$35,$3F,$55,$5F,$6A,$91,$9B,$49,$D5,$D6 -.values +;values !byte $D5,$AA,$AD,$DE,$AA,$EB,$D5,$AA,$AD,$DE,$AA,$D5,$AA,$96,$DE,$AA,$D6,$D5,$20 -+ lda #$12 - sta .loop+1 - -.loop ldy #$d1 - lda .values,y - sta .valuea - sta .valueb - lda .sectors,y - ldx .offsets,y - jsr compare1 -.valuea !byte $d1 - bcc + - jsr modify1 -.valueb !byte $d1 -+ dec .loop+1 - bpl .loop +.start + lda #<.laureatemulti + ldy #>.laureatemulti + ldx #19 + jsr multimodify lda #$0A ldx #$12 diff --git a/src/strings/en.a b/src/strings/en.a index cf5192f..e38705a 100755 --- a/src/strings/en.a +++ b/src/strings/en.a @@ -221,6 +221,7 @@ StringTableLow ; must be kept in sync with constants in enid.a !byte <.didatech !byte <.anychecksum !byte <.unexpected5and3 + !byte <.jmp600 StringTableHigh ; must be kept in sync with constants in enid.a !byte >.header @@ -381,11 +382,12 @@ StringTableHigh ; must be kept in sync with constants in enid.a !byte >.didatech !byte >.anychecksum !byte >.unexpected5and3 + !byte >.jmp600 .passport !text "Passport ",$00 .header - !text "@",s_passport,"by 4am@",s_space7,"@",s_space7," 2023-09-04",$00 + !text "@",s_passport,"by 4am@",s_space7,"@",s_space7," 2023-10-02",$00 .bar9 !text "_________",$00 .bar18 @@ -790,3 +792,5 @@ StringTableHigh ; must be kept in sync with constants in enid.a !text "address field checksum",$8D,$00 .unexpected5and3 !text "@",s_tfound,"5-and-3 @",s_protectiontrack,$8D,$00 +.jmp600 + !text "@",s_found,"JMP $0600 @",s_bootloader,$8D,$00 diff --git a/src/strings/enid.a b/src/strings/enid.a index 805a360..bb77530 100644 --- a/src/strings/enid.a +++ b/src/strings/enid.a @@ -159,3 +159,4 @@ s_probs5 = $9A s_didatech = $9B s_anychecksum = $9C s_unexpected5and3 = $9D +s_jmp600 = $9E