Initial commit.

This commit is contained in:
Eric Smith 2016-12-16 22:20:29 -07:00
commit b76308e29b
4 changed files with 597 additions and 0 deletions

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
*~
*.lst
*.p
*.bin
*.hex
*.sr
*.srec
*.dsk
*.pdf
*.txt
rana-31-orig.bin

13
Makefile Normal file
View File

@ -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

14
README.md Normal file
View File

@ -0,0 +1,14 @@
# a2-rana-elite - Reverse-engineered Rana Elite floppy disk controller firmware
Copyright 2014, 2016 Eric Smith <spacewar@gmail.com>
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.

559
rana-31.asm Normal file
View File

@ -0,0 +1,559 @@
; Reverse-engineered firmware of Rana Elite floppy disk
; controller for Apple II.
; Assembly source code copyright 2014, 2016 Eric Smith <spacewar@gmail.com>
; 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 *<endaddr
if (endaddr-*)>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