diff --git a/notes/mig_notes.txt b/notes/mig_notes.txt new file mode 100644 index 0000000..50fc23a --- /dev/null +++ b/notes/mig_notes.txt @@ -0,0 +1,25 @@ +MIG space references in ROM: +CE00-CE1F - MIG RAM window +CE20 - Increment page +CE3D-CE3E - ? +CE40 - write in E4D9,E503,E612,EF02 + read in 8E9C,E9A3,E9EB,EA15,EA2D,EA40,EE87, + always around slot 6 I/O accesses. +CE60 - read in routine at E4C7,E8C5,E974,EA6B,EE95 + write in routine at E4F2,E612,E652,EF02,EFC6,F54C + always around slot 6 I/O accesses. +CEA0 - Reset page 0 +CECD - ? from data +CED5 - ? from data +CF9A - ? from bank switch @C746 prob calling main bannk +CFCF - ? from data +CFFF - leftover from non //c ROM + +MIG page usage: +Page 0 - 3.5 ROM - routines at CA12, E51D +CE11 - slot I/O offset of ? (ldy CE11, lda C000,y in routine at CA12) +Page 1 - used by routines at CA71,E54F,E534 +Page 2 - Appears used only by accelerator code +Page 3 - used by routines at CA4B, CA71, E1E1, EB8B, ECCF +Page 4+ - used all over the place + diff --git a/notes/rom5_zeros.txt b/notes/rom5_zeros.txt new file mode 100644 index 0000000..043f195 --- /dev/null +++ b/notes/rom5_zeros.txt @@ -0,0 +1,27 @@ +Inventory of zeros of 5 bytes or more in the IIc Plus ROM + +Main Bank +C1FB - 5 bytes +C4EE - 12 bytes +C5F3 - 5 bytes +C6FB - 5 bytes +C9A1 - 9 bytes +CFF9 - 7 bytes +Alt Bank +C572 - 8 bytes +C7FB - 8 bytes +C7FC - 7 bytes +CE00 - 512 bytes not usable (MIG space) +D134 - 76 bytes +D516 - 234 bytes +D6CE - 306 bytes +DB63 - 157 bytes +DE00 - 512 bytes maybe not usable (second mig space?), none of the firmware + touches it. +F72D - 16 bytes not usable (some kind of data table) +F7ED - 19 bytes +FB3C - 196 bytes +FC3C - 12 bytes +FCC9 - 55 bytes +FE96 - 352 bytes, but reserve 65816 vectors + diff --git a/rom5x/B0_CFF9_switch_cmd.s b/rom5x/B0_CFF9_switch_cmd.s new file mode 100644 index 0000000..67c637c --- /dev/null +++ b/rom5x/B0_CFF9_switch_cmd.s @@ -0,0 +1,8 @@ +#include "iic+.defs" +.text +* = $cff9 ; 7 bytes available here + lda #$a9 ; lda opcode + nop ; jmp/jsr $cffa does lda #$ea + jmp $fbdf ; jump to bell1 hijack +; total 6 bytes. + diff --git a/rom5x/B0_FAB4_patch_pwrup.s b/rom5x/B0_FAB4_patch_pwrup.s new file mode 100644 index 0000000..428fa8f --- /dev/null +++ b/rom5x/B0_FAB4_patch_pwrup.s @@ -0,0 +1,7 @@ +; patch PWRUP to call boot5x + +#include "iic+.defs" +.text +* = $fab4 + nop + jmp gobt5x diff --git a/rom5x/B0_FAC8_patch_reset.s b/rom5x/B0_FAC8_patch_reset.s new file mode 100644 index 0000000..cbb9912 --- /dev/null +++ b/rom5x/B0_FAC8_patch_reset.s @@ -0,0 +1,7 @@ +; patch RESET.X to call reset5x + +#include "iic+.defs" +.text +* = $fac8 + jmp gorst5x + diff --git a/rom5x/B0_FBDF_bell1_hijack.s b/rom5x/B0_FBDF_bell1_hijack.s new file mode 100644 index 0000000..2898a2b --- /dev/null +++ b/rom5x/B0_FBDF_bell1_hijack.s @@ -0,0 +1,4 @@ +.text +* = $fbdf + sta $c028 + diff --git a/rom5x/B0_FCDE_patch_coldstart.s b/rom5x/B0_FCDE_patch_coldstart.s deleted file mode 100644 index d7849d2..0000000 --- a/rom5x/B0_FCDE_patch_coldstart.s +++ /dev/null @@ -1,5 +0,0 @@ -#include "iic+.defs" -.text -* = $fcde - sta rombank - diff --git a/rom5x/B1_CF00_rom5x.s b/rom5x/B1_CF00_rom5x.s deleted file mode 100644 index 332105f..0000000 --- a/rom5x/B1_CF00_rom5x.s +++ /dev/null @@ -1,39 +0,0 @@ -#include "iic+.defs" -.text -* = rom5x - asl butn1 ; check option key - bcc rd5x ; not pressed, see if RD recoverable - lda #"O" ; flashing "O" - sta $7d0 ; tell user -exit5x lda #>(r5xrtn-1) - pha - lda #<(r5xrtn-1) - pha - ldy #$00 ; in case someone assumes this later - jmp swrts2 -rd5x jsr rdinit ; init ram card and registers - lda pwrup,y ; get power up flag - cmp #pwrbyte ; already initialized? - beq exit5x ; exit if so - jsr testsize ; does not wreck x or y - lda numbanks,y ; get discovered # banks - beq exit5x ; no memory - stz addrl,x ; set slinky address 0 - stz addrm,x - stz addrh,x - lda data,x ; get first byte - cmp #$01 ; boot block? - bne exit5x ; nope - lda data,x ; next byte - beq exit5x ; not bootable if 0 - cmp #$ff ; other likely byte for fresh RAM - beq exit5x ; not bootable if $ff - lda #pwrbyte ; sta pwrup,y - lda #"R" ; tell user - sta $7d0 ; on screen - bra exit5x -rdinit bit rx_mslot*$100 ; activate registers - ldy #rx_mslot ; slot offset - ldy #rx_devno ; register offset - rts - diff --git a/rom5x/B1_D516_boot5x.s b/rom5x/B1_D516_boot5x.s new file mode 100644 index 0000000..12c858b --- /dev/null +++ b/rom5x/B1_D516_boot5x.s @@ -0,0 +1,112 @@ +#include "iic+.defs" +.text +* = boot5x ; 234 bytes available, code assembles to 231 when + ; next line uncommented +; jsr ntitle ; TODO "Apple IIc +" + jsr rdrecov ; try to recover ramdisk + lda power2 + rx_mslot ; get action saved by reset5x + beq boot4 ; if zero, continue boot + jsr bann5x ; display ROM 5X footer + lda power2 + rx_mslot ; boot selection +btc2 cmp #$02 ; clear ramcard + bne btc3 + jsr rdclear ; do clear + bra boot4 +btc3 cmp #$03 ; Diags + bne btc4 + jmp $c7c4 +btc4 cmp #$04 ; RX diags + bne btc5 + ldx #$ff + txs ; reset stack + jsr rdinit ; get x and y loaded + stx sl_devno ; diags need this + jsr testsize ; compute card size + lda #>(monitor-1) ; load "return" address + pha ; into stack so that we + lda #<(monitor-1) ; exit card test into + pha ; the monitor + lda numbanks,y ; get the card size in banks + bne dordiag ; do diag if memory present + jmp swrts2 ; otherwise jump to monitor +dordiag jmp $db3a ; diags +btc5 cmp #$05 ; boot smartport + beq boot5 + ; fall through if none of the above +boot4 lda #rx_mslot ; boot slot 4 + bra bootsl +boot5 lda #$c5 ; boot slot 5 + bra bootsl +boot6 lda #$c6 ; boot slot 6 +bootsl ldx #$00 ; low byte of slot +bootadr stx $0 ; store address + sta $1 ; return to bank 0 does jmp (0) +endbt4x lda #>(bt5xrtn-1) + pha + lda #<(bt5xrtn-1) + pha + lda $1 + jmp swrts2 +rdrecov jsr rdinit ; init ramcard + lda pwrup,y ; get power up flag + cmp #pwrbyte ; already initialized? + beq recovdn ; exit if initialized + jsr testsize ; does not wreck x or y + lda numbanks,y ; get discovered # banks + beq recovdn ; no mem + stz addrl,x ; set slinky address 0 + stz addrm,x + stz addrh,x + lda data,x ; start check for bootable ramdisk + cmp #$01 + bne recovdn ; not bootable + lda data,x ; next byte should be nonzero and not $ff + beq recovdn ; not bootable + cmp #$ff + beq recovdn ; not bootable + lda #pwrbyte + sta pwrup,y ; set power byte + lda #"R" ; tell user + sta $7d0 ; on screen +recovdn rts +; zero ram card space +rdclear jsr rdinit ; init ramcard + jsr testsize ; get size + lda numbanks,y ; # of 64Ks to write + beq clrdone ; no memory + lda #$c0 ; 'A' - 1 + sta $400 ; upper left corner + stz addrl,x ; slinky address 0 + stz addrm,x + stz addrh,x +clbnklp inc $400 ; poor mans progress meter + ldy #$00 +cl64klp ldx #$00 ; loop for all pages in bank +cl256lp txa ; loop for all bytes in page + ldx #rx_devno + stz data,x ; write a zero to card + tax + dex + bne cl256lp ; 256 byte loop + dey + bne cl64klp ; 64K loop + ldx #rx_mslot + dec numbanks,x + bne clbnklp ; if more banks +clrdone ldx #rx_mslot + stz pwrup,x ; zero powerup byte + lda #$a0 ; ' ' + sta $400 ; clear progress + rts +rdinit bit rx_mslot*$100 ; activate registers + ldy #rx_mslot ; slot offset + ldx #rx_devno ; register offset + rts +; next is snippet of code to boot external 5.25 +bootext lda #$e0 + ldy #$01 + ldx #$60 + jmp $c60b +bt4xend = * + + diff --git a/rom5x/B1_D6CE_rom5x_misc.s b/rom5x/B1_D6CE_rom5x_misc.s new file mode 100644 index 0000000..c181862 --- /dev/null +++ b/rom5x/B1_D6CE_rom5x_misc.s @@ -0,0 +1,90 @@ +#include "iic+.defs" +.text +* = misc5x ; max 306 bytes + bra domenu + bra dobann + bra gtkey + bra confirm +dobann jsr ntitle + ldx #(msg2-msg1) ; msg display entry point + jmp disp +domenu jsr ntitle ; "Apple ||c +" + ldx #$00 ; menu start + jsr disp ; show it + rts +gtkey lda #$60 + sta ($0),y ; cursor + sta kbdstrb ; clr keyboard +kbdin lda kbd ; get key + bpl kbdin + sta kbdstrb ; clear keyboard + sta ($0),y ; put it on screen + rts +; display message, input x = message start relative to msg1 +disp stz $0 ; load some safe defaults + lda #$40 + sta $1 + ldy #$0 ; needs to be zero +disp0 lda msg1,x ; get message byte + bne disp1 ; proceed if nonzero + rts ; exit if 0 +disp1 inx ; next byte either way + cmp #$20 ; ' ' + bcc disp2 ; start of ptr if < 20 + eor #$80 ; invert high bit + sta ($0),y ; write to mem + inc $0 ; inc address low byte + bra disp0 ; back to the beginning +disp2 sta $1 ; write address high + lda msg1,x ; get it + sta $0 ; write address low + inx ; set next msg byte + bra disp0 ; back to the beginning +confirm pha + ldx #(msg3-msg1) ; ask confirm + jsr disp + jsr gtkey + plx + ora #$20 ; to lower + cmp #$f9 ; "y" + php + txa + plp + rts +; display "Apple IIc +" in a convoluted manner +; ultimately, the rts instruction here "rts" to swrts2 +; which switches banks and "rts" to the title/banner firmware call +; which then "rts" to swrts (same addr as swrts2, but main bank) +; which then actually rts to our caller +ntitle lda #>(swrts2-1) ; put return addr of swrts2 on stack + pha + lda #<(swrts2-1) + pha + lda #>(banner-1) + pha + lda #<(banner-1) + pha + lda #>(swrts2-1) + pha + lda #<(swrts2-1) + pha + rts ; jump to swrts2 +; msg format +; A byte < $20 indicates high byte of address. +; Next byte must be low byte of address. Anything +; else are characters to display and will have their +; upper bit inverted before being written to the screen. +msg1 = * + .db $05,$06,"0 Monitor" + .db $05,$86,"1 Reboot" + .db $06,$06,"2 Zero RAM Card" + .db $06,$86,"3 Sys Diags" + .db $07,$06,"4 RAM Card Diags" + .db $07,$86,"5 Boot 3.5/SmartPort" + .db $04,$2e,"6 Boot 5.25" +; .db $04,$ae,"7 Accelerator" + .db $07,$5f,"By M.G." +msg2 .db $07,$db,"ROM 5X 02/08/17" + .db $05,$ae,$00 ; cursor pos in menu +msg3 .db $05,$b0,"SURE? ",$00 + diff --git a/rom5x/B1_DB63_reset5x.s b/rom5x/B1_DB63_reset5x.s new file mode 100644 index 0000000..e9c5eef --- /dev/null +++ b/rom5x/B1_DB63_reset5x.s @@ -0,0 +1,42 @@ +#include "iic+.defs" +.text +* = reset5x ; max 157 bytes + stz power2 + rx_mslot ; action = normal reset + lda #>(rst5xrtn-1) ; common case + pha + lda #<(rst5xrtn-1) + pha ; note that this stays on stack + asl butn1 ; closed apple + bcs ckdiag +exitrst jmp swrts2 +; check to see if both apples are down +ckdiag bit butn0 ; open apple + bmi exitrst ; return to RESET.X +; present menu because only closed apple is down +menu jsr menu5x ; display menu + jsr gkey5x + cmp #$b0 ; "0" + bne ckkey1 + ldx #$ff ; reset stack + txs + lda #>(monitor-1) ; monitor entry on stack + pha + lda #<(monitor-1) + pha + jmp swrts2 ; rts to enter monitor +ckkey1 cmp #$b2 ; "2" + beq doconf + cmp #$b4 ; "4" + bne ckkey2 +doconf jsr conf5x + bne menu ; go back to menu4x +ckkey2 sec + sbc #$b0 ; ascii->number + bmi menu ; < 0 not valid + cmp #$08 ; we will use 7 for accelerator later + bpl menu ; > 7 not valid + sta power2 + rx_mslot ; for boot5x + stz softev + 1 ; deinit coldstart + stz pwerdup ; ditto + bra exitrst + diff --git a/rom5x/B1_FBE2_rom5x_dispatch.s b/rom5x/B1_FBE2_rom5x_dispatch.s new file mode 100644 index 0000000..5bbb798 --- /dev/null +++ b/rom5x/B1_FBE2_rom5x_dispatch.s @@ -0,0 +1,17 @@ +#include "iic+.defs" +.text +* = $fbe2 ; ~29 bytes free here + cmp #$a9 ; reset patch + bne chk2 + jmp reset5x +chk2: cmp #$ea ; boot patch + bne dowait + jmp boot5x +dowait: jsr $fcb5 ; do delay if anything else + lda #>($fbe2-1) + pha + lda #<($fbe2-1) + pha + lda #$00 ; in case someone assumes this + jmp swrts2 + ; 28 bytes, will have to move if we get bigger diff --git a/rom5x/B1_FCE1_go_to_rom5x.s b/rom5x/B1_FCE1_go_to_rom5x.s deleted file mode 100644 index deb8cbf..0000000 --- a/rom5x/B1_FCE1_go_to_rom5x.s +++ /dev/null @@ -1,6 +0,0 @@ -#include "iic+.defs" -.text -* = $fce1 - sta set80col ; instruction we patched over - jmp rom5x - diff --git a/rom5x/README.md b/rom5x/README.md index 52d6ee5..f1f5ed5 100644 --- a/rom5x/README.md +++ b/rom5x/README.md @@ -1,18 +1,26 @@ # ROM 5X by MG -## DO NOT EVEN TRY THIS YET :-) +## PRELIMINARY, DO NOT EVEN TRY THIS YET :-) **Warning:** This has not been tested on an emulator or a real Apple IIc Plus. -This is a patch for the Apple IIc Plus firmware that tries to recover a battery-backed -RAM disk upon cold start. Because of the limited space in the Apple IIc ROM. it does not -have the complete feature set of ROM 4X for the (non-Plus) //c. +This is ROM4X revised to the Apple IIc Plus ROM version 5. -Upon cold start, the patch checks for a potentially bootable RAM disk and restores the -appropriate screen holes to prevent it from being destroyed and to enable boot. If a -RAMdisk is recovered, a flashing "R" will appear in the lower left corner of the screen. +There are almost no free bytes in the main bank of the IIc Plus firmware, so +I had to get creative to get into the alternate bank, where I then had to split +the code up across multiple smaller free spaces. Ironically this makes the +code larger as well. + +For those interested, I hijack the monitor BEEP1 routine. The beep routine has +an LDA #$40 and then calls WAIT with this value for a .1 second delay, +presumably so that multiple beeps are distinct from each other. + +I patch the JSR WAIT to be STA $C028, which switches to the other bank. +The code in the other bank checks the accumulator and for two values calls +either reset5x or boot5x, and for any other value executes the WAIT (assuming +that we got there from BEEP1). + +Then, in only 6 bytes I can create two entry points that load the value into +A that we need for the reset or boot routines, and then jump to the above patch. -To prevent the check and recovery, power on the machine with the Option key held down. -A flashing "O" will appear in the lower left corner of the screen and the system will -boot without checking for or recovering any RAM disk. diff --git a/rom5x/iic+.defs b/rom5x/iic+.defs index b22fc74..73f829c 100644 --- a/rom5x/iic+.defs +++ b/rom5x/iic+.defs @@ -1,8 +1,10 @@ ; hardware -set80col = $c001 +;set80col = $c001 rombank = $c028 butn0 = $c061 butn1 = $c062 +kbd = $c000 +kbdstrb = $c010 addrl = $bff8 addrm = $bff9 addrh = $bffa @@ -20,8 +22,13 @@ sl_scrn7 = $778 - $c0 sl_scrn8 = $7f8 - $c0 numbanks = sl_scrn1 pwrup = sl_scrn7 +power2 = sl_scrn8 sl_devno = $778 +; locations +softev = $3f2 +pwerdup = $3f4 + ; values pwrbyte = $a5 rx_slot = $4 @@ -29,8 +36,35 @@ rx_mslot = rx_slot + $c0 rx_devno = rx_slot * $10 + $88 ; entry points -r5xrtn = $fce1 -rom5x = $cf00 +gorst5x = $cff9 +gobt5x = $cffa +rst5xrtn = $facb +bt5xrtn = $fb19 +reset5x = $db63 +boot5x = $d516 testsize = $d99f swrts2 = $c784 +monitor = $ff59 +misc5x = $d6ce +menu5x = misc5x +bann5x = menu5x+2 +gkey5x = bann5x+2 +conf5x = gkey5x+2 +banner = $fb60 + +; macros +#define psa(addr) \ + lda #>(addr-1) \ + pha \ + lda #<(addr-1) \ + pha \ + jsr swrts2 + +#define rtj(addr) \ + psa(addr) \ + rts + +#define rtl(addr) \ + psa(addr) \ + jmp swrts2