commit b76308e29b390daa961b8d8f541982cb35e2500b Author: Eric Smith Date: Fri Dec 16 22:20:29 2016 -0700 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3d19fad --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +*~ +*.lst +*.p +*.bin +*.hex +*.sr +*.srec +*.dsk +*.pdf +*.txt +rana-31-orig.bin diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6f9d6e6 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +all: check + +check: rana-31.bin + echo "3087ad4f71d8b76add2870939552b9b369efcc0ac949a27d5e9f00162b4488dc rana-31.bin" | sha256sum -c + +%.p %.lst: %.asm + asl -cpu 6502 -L -C $< + +%.bin: %.p + p2bin -r '$$c800-$$cfff' $< $@ + +clean: + rm -f *.lst *.p *.bin diff --git a/README.md b/README.md new file mode 100644 index 0000000..d188823 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# a2-rana-elite - Reverse-engineered Rana Elite floppy disk controller firmware + +Copyright 2014, 2016 Eric Smith + +a2-rana-elite development is hosted at the +[a2-rana-elite Github repository](https://github.com/brouhaha/a2-rana-elite/). + +## Introduction + +The Rana Elite Controller for the Apple II is a floppy disk controller +compatible with the Apple Disk II controller, but with additional features. +The Elite can control four drives (vs. two for the Disk II controller), and +by virtue of having more firmware, can automatically boot either 13-sector +or 16-sector disks. diff --git a/rana-31.asm b/rana-31.asm new file mode 100644 index 0000000..6e8b7b0 --- /dev/null +++ b/rana-31.asm @@ -0,0 +1,559 @@ +; Reverse-engineered firmware of Rana Elite floppy disk +; controller for Apple II. + +; Assembly source code copyright 2014, 2016 Eric Smith +; The author of this assembly source code does not claim copyright on the +; executable object code as found in the EPROM chip of the Rana Elite +; floppy disk controller. + +; Cross-assemble with Macro Assembler AS: +; http://john.ccac.rwth-aachen.de:8000/as/ + +fillto macro endaddr,value,{noexpand} + ifnb value +v set value + else +v set $00 + endif + while *1024 + fcb [1024] v + else + fcb [endaddr-*] v + endif + endm + endm + +fcstrm macro s + irpc c,s + fcb 'c'|$80 + endm + endm + + +Z00 equ $00 +bufptr equ $26 +denib_counter equ $2a +slot16 equ $2b +temp equ $3c +sector equ $3d +Z40 equ $40 +Z41 equ $41 + +D0100 equ $0100 + +D02d6 equ $02d6 + +D0300 equ $0300 +L0301 equ $0301 +D0356 equ $0356 + +tramp_0801 equ $0376 ; trampoline for 16-sector boot + +D0399 equ $0399 +D03c6 equ $03c6 +D03c7 equ $03c7 +D03cc equ $03cc +D03ce equ $03ce + +D0800 equ $0800 ; 16-sector boot: additional sector count +L0801 equ $0801 ; 16-sector boot: jump address + +tramp_0301 equ $08e0 ; trampoline for 13-sector boot +D08e3 equ $08e3 +D08e6 equ $08e6 +D08e7 equ $08e7 + +; Woz controller addresses (index by slot * 16) +phoff equ $c080 ; phase off +phon equ $c081 ; phase on +mtroff equ $c088 ; motor off +mtron equ $c089 ; motor on +drv0en equ $c08a ; drive 0 enable +drv1en equ $c08b ; drive 1 enable +q6l equ $c08c ; set Q6 low +q6h equ $c08d ; set Q6 high +q7l equ $c08e ; set Q7 low +q7h equ $c08f ; set Q7 high + +seld12 equ $c800 ; write to select drive bank for drives 1 and 2 +seld34 equ $c801 ; write to select drive bank for drives 3 and 4 +romoff equ $cfff ; access to turn off shared ROM + +monwait equ $fca8 ; monitor wait subroutine + + org $c800 + + fillto $cc00 + +Lcc00: jmp Lcde2 + +; build 13-sector denibblization table - D0800[nib] = 5-bit data +; starting with ($08ff) = $1f, and descending to ($08ab) = $00 +; duplicates code in Apple 13-sector boot ROM stating at Cx00 +Lcc03: ldx #$20 + ldy #$00 +Lcc07: lda #$03 + sta temp + clc + dey + tya +Lcc0e: bit temp + beq Lcc07 + rol temp + bcc Lcc0e + + cpy #$d5 ; skip $d5, used for marks + beq Lcc07 + + dex ; Y is a valid nibble, set table[Y] to index + txa + sta D0800,y + bne Lcc07 + +; Copy two instruction trampoline (six bytes) from tramp_0301_rom to tramp_0301. +Lcc21: ldy #tramp_0301_len-1 +Lcc23: lda tramp_0301_rom,y + sta tramp_0301,y + dey + bpl Lcc23 + + lda #$40 + sta D08e6 + lda #$03 + sta bufptr+1 + lda #$ff + sta D0300 + sta D08e7 + ldx slot16 + +Lcc3f: ldy D08e6 + iny + beq read_sector_13 + dec D08e6 + beq Lcc00 + +read_sector_13: + clc ; flag clear, look for address mark +read_something_13: + php ; save flag + +; read first byte of mark +Lcc4c: lda q6l,x ; read disk + bpl Lcc4c +Lcc51: eor #$d5 ; first byte of mark? + bne Lcc4c ; no + +; read second byte of mark +Lcc55: lda q6l,x + bpl Lcc55 + cmp #$aa + bne Lcc51 + nop + +; read third byte of mark +Lcc5f: lda q6l,x + bpl Lcc5f + cmp #$b5 ; address mark? + beq found_address_mark_13 + + plp ; retrieve flag - looking for address mark? + bcc Lcc3f ; yes, try again + +; check for a data mark + eor #$ad + beq found_data_mark_13 + bne Lcc3f +found_address_mark_13: + ldy #$03 ; read volume, track, sector + ; volume and track ignored, presumed OK + ; checksum not read + +Lcc73: lda q6l,x + bpl Lcc73 + rol ; save upper slice + sta temp + +Lcc7b: lda q6l,x + bpl Lcc7b + and temp ; merge slices + dey ; 3rd byte yet? + bne Lcc73 ; no, get another + + plp ; throw away flag + + cmp sector ; correct sector? + bne Lcc3f ; no, get another + bcs read_something_13 ; yes. carry is set, go back and look for data mark + +found_data_mark_13: +; read 154 nibbles, denibblize with running xor, +; and store from $0899 down to $0800 + ldy #$9a +Lcc8e: sty temp +Lcc90: ldy q6l,x + bpl Lcc90 + eor D0800,y + ldy temp + dey + sta D0800,y + bne Lcc8e + +; Y now zero +; read 256 nibbles, denibblize with running xor, +; and store in buffer in ascending order +Lcca0: sty temp +Lcca2: ldy q6l,x + bpl Lcca2 + eor D0800,y + ldy temp + sta (bufptr),y + iny + bne Lcca0 + +; read checksum nibble, xor, and verify zero +Lccb1: ldy q6l,x + bpl Lccb1 + eor D0800,y + bne Lcc3f ; checksum fail? + + lda D08e7 + beq Lcced + + lda #$03 + sta denib_counter + +; special 13-sector boot sector denibblize, equivalent to +; 13-sector boot ROM code at $cnd1 + ldy #$00 +Lccc6: ldx #$00 + +Lccc8: lda D0800,y + lsr + rol D03cc,x + lsr + rol D0399,x + sta temp + + lda (bufptr),y ; merge in the extra bits + asl + asl + asl + ora temp + sta (bufptr),y + + iny + inx + cpx #$33 + bne Lccc8 + + dec denib_counter + bne Lccc6 + + cpy D0300 + bne Lccf0 + +Lcced: jmp tramp_0301 ; jump via trampoline to $0301 + +Lccf0: jmp Lcde2 + +; The following two instruction trampoline (six bytes) is copied to tramp_0301 +; by loop at Lcc21. +tramp_0301_rom: + bit romoff ; turn off shared ROM + jmp L0301 ; jump into 13-sector stage 2 boot +tramp_0301_len equ *-tramp_0301_rom + + fillto $cd00 + +Scd00: jsr Scd4e + ldx slot16 + lda #$40 + sta D03ce + lda #$00 + sta bufptr + sta sector + sta Z41 + lda #$08 + sta bufptr+1 + rts + +Scd17: tsx + inx + inx + lda D0100,x + asl + asl + asl + asl + sta slot16 + tax + + sta seld12 ; select drive bank for drives 1 and 2 + + lda q7l,x ; set up to read drive + lda q6l,x + lda drv0en,x + lda mtron,x + + jsr Scd00 + +; move to track 0 (assume worst case +; initial position of track 40) + + ldy #80 ; 80 half tracks +Lcd38: lda phoff,x ; stepper motor phase off + tya ; compute next phase + and #$03 ; yields 3,2,1,0 + asl ; yields 6,4,2,0 + ora slot16 ; merge with slot*16 + tax + lda phon,x ; stepper motoro phase on + lda #$56 ; wait (13 sector boot rom had $86) + jsr monwait + dey + bpl Lcd38 + rts + +; generate 16-sector post-nybble conversion table +; From 16-sector boot ROM, c602..?? +; See 16-sector ROM disassembly in Apple Assembly Line V1N11, August 1981 +Scd4e: ldx #$03 + ldy #$00 +Lcd52: stx temp + txa + asl + bit temp + beq Lcd6a + ora temp + eor #$ff + and #$7e +Lcd60: bcs Lcd6a + lsr + bne Lcd60 + tya + sta D0356,x + iny +Lcd6a: inx + bpl Lcd52 + +; Copy two instruction trampoline (six bytes) from tramp_0801_rom to tramp_0801. +Lcd6d: ldy #tramp_0801_len-1 +Lcd6f: lda tramp_0801_rom,y + sta tramp_0801,y + dey + bpl Lcd6f + + lda #$40 + sta D03ce + +Scd7d: ldy #$55 + lda #$00 +Lcd81: sta D0300,y + dey + bpl Lcd81 + rts + +Lcd88: bcs Lcda1 + lda #$ff + sta D03ce + lda #Lc64c & $ff +Lcd91: sta D03c6 + txa + lsr + lsr + lsr + lsr + ora #$c0 + sta D03c7 + jmp (D03c6) +Lcda1: jmp tramp_0801 + +; The following two instruction trampoline (six bytes) is copied to tramp_0801 +; by loop at Lcd6d. +tramp_0801_rom: + bit romoff ; turn off shared ROM + jmp L0801 ; jump into 16-sector stage 2 boot +tramp_0801_len equ *-tramp_0801_rom + +Scdaa: lda #$00 + ldy #$55 +Lcdae: ora D0300,y + dey + bpl Lcdae + and #$f0 + bne Lcdbe + lda #$ff + sta D03ce + rts + +Lcdbe: pla + pla + pla + ldy #$60 + sty D08e3 + ldy #$00 + sty D08e7 + dey + sty D08e6 + jmp read_sector_13 + +Scdd2: ldy D03ce + iny + beq Lcddd + dec D03ce + beq Lcddf +Lcddd: clc + rts + +Lcddf: jmp Lcc03 + +Lcde2: jsr Scd00 + lda #$25 + bne Lcd91 + + fillto $cec2 + fcb "COPYR. 1982 RANA SYSTEMS - KSB" + + fcstrm "COPYR. 1982 RANA SYSTEMS - KSB" + + fcb $01,$03 + + org $cf00 + phase $c600 + +Pc600: ldx #$20 + ldy #$00 + ldx #$03 + ldx #$3c + bit romoff + jsr Scd17 + bne Lc625 + +Lc610: bit romoff + jsr Scdaa + bne Lc627 +Lc618: jsr Scdd2 + bcc Lc625 + + fcb $00,$00,$00,$00,$00 + +Lc622: jsr Scd7d +Lc625: clc +Lc626: PHP +Lc627: lda q6l,x + bpl Lc627 +Lc62c: eor #$d5 ; first byte of mark + bne Lc627 +Lc630: lda q6l,x + bpl Lc630 + cmp #$aa ; second byte of mark + bne Lc62c + nop +Lc63a: lda q6l,x + bpl Lc63a + cmp #$96 ; third byte of address mark (16-sector) + beq Lc683 + plp + bcc Lc618 + eor #$ad ; third byte of data mark + beq Lc6a6 + bne Lc618 + +Lc64c: ldy D03ce + iny + beq Lc622 + dec D03ce + bne Lc622 + jmp Lcddf + +; DOS 3.3 boot reenters the PROM via jmp to $Cn5C +; DOS 3.2.1 boot reenters the PROM via jsr (effectively) to $Cn5D + fillto $c65c +Pc65c: clc +Pc65d: PHP + SEC + bcs Lc610 + + bpl Lc627 +Lc663: eor #$d5 ; first byte of mark + bne Lc627 +Lc667: lda q6l,x + bpl Lc667 + cmp #$aa ; second byte of mark + bne Lc663 + nop +Lc671: lda q6l,x + bpl Lc671 + cmp #$96 ; third byte of address mark + beq Lc683 + plp + bcc Lc618 + eor #$ad ; third byte of data mark + beq Lc6a6 + +Lc681: bne Lc618 +Lc683: ldy #$03 +Lc685: sta Z40 +Lc687: lda q6l,x + bpl Lc687 + rol + sta temp +Lc68f: lda q6l,x + bpl Lc68f + and temp + dey + bne Lc685 + plp + cmp sector + bne Lc681 + lda Z40 + cmp Z41 +Lc6a2: bne Lc64c + bcs Lc626 +Lc6a6: ldy #$56 +Lc6a8: sty temp +Lc6aa: ldy q6l,x + bpl Lc6aa + eor D02d6,y + ldy temp + dey + sta D0300,y + bne Lc6a8 +Lc6ba: sty temp +Lc6bc: ldy q6l,x + bpl Lc6bc + eor D02d6,y + ldy temp + sta (bufptr),y + iny + bne Lc6ba +Lc6cb: ldy q6l,x + bpl Lc6cb + eor D02d6,y + bne Lc6a2 + ldy #$00 +Lc6d7: ldx #$56 +Lc6d9: dex + bmi Lc6d7 + lda (bufptr),y + lsr D0300,x + rol + lsr D0300,x + rol + sta (bufptr),y + iny + bne Lc6d9 + inc bufptr+1 + inc sector + lda sector + cmp D0800 + ldx slot16 + nop + nop + bit romoff + jmp Lcd88 + + fillto $c700 + + dephase