a2audit/audit/technote2.asm
Zellyn Hunter 08074672ca add first pass of machine detection to audit.asm
Currently having issues with some plain Apple II and II+, but seems to
work for IIe and IIe enhanced.
2016-12-07 23:05:07 -05:00

401 lines
13 KiB
NASM

;;; From http://www.1000bit.it/support/manuali/apple/technotes/misc/tn.misc.02.html
;;; *********************************************
;;; * *
;;; * Apple II Family Identification Program *
;;; * *
;;; * Version 2.2 *
;;; * *
;;; * March, 1990 *
;;; * *
;;; * Includes support for the Apple IIe Card *
;;; * for the Macintosh LC. *
;;; * *
;;; *********************************************
; First, some global equates for the routine:
!zone technote2 {
IIplain = $01 ;Apple II
IIplus = $02 ;Apple II+
IIIem = $03 ;Apple /// in emulation mode
IIe = $04 ;Apple IIe
IIc = $05 ;Apple IIc
IIeCard = $06 ;Apple IIe Card for the Macintosh LC
.safe = $0001 ;start of code relocated to zp
.location = $06 ;zero page location to use
.test1 = $AA ;test byte #1
.test2 = $55 ;lsr of test1
.test3 = $88 ;test byte #3
.test4 = $EE ;test byte #4
.begpage1 = $400 ;beginning of text page 1
.begpage2 = $800 ;beginning of text page 2
.begsprse = $C00 ;byte after text page 2
.clr80col = $C000 ;disable 80-column store
.set80col = $C001 ;enable 80-column store
.rdmainram = $C002 ;read main ram
.rdcardram = $C003 ;read aux ram
.wrmainram = $C004 ;write main ram
.wrcardram = $C005 ;write aux ram
.rdramrd = $C013 ;are we reading aux ram?
.rdaltzp = $C016 ;are we reading aux zero page?
.rd80col = $C018 ;are we using 80-columns?
.rdtext = $C01A ;read if text is displayed
.rdpage2 = $C01C ;read if page 2 is displayed
.txtclr = $C050 ;switch in graphics
.txtset = $C051 ;switch in text
.txtpage1 = $C054 ;switch in page 1
.txtpage2 = $C055 ;switch in page 2
.ramin = $C080 ;read LC bank 2, write protected
.romin = $C081 ;read ROM, 2 reads write enable LC
.lcbank1 = $C08B ;LC bank 1 enable
.lc1 = $E000 ;bytes to save for LC
.lc2 = $D000 ;save/restore routine
.lc3 = $D400
.lc4 = $D800
.idroutine = $FE1F ;IIgs id routine
; Start by saving the state of the language card banks and
; by switching in main ROM.
IDENTIFY
php ;save the processor state
sei ;before disabling interrupts
lda .lc1 ;save four bytes from
sta .save ;ROM/RAM area for later
lda .lc2 ;restoring of RAM/ROM
sta .save+1 ;to original condition
lda .lc3
sta .save+2
lda .lc4
sta .save+3
lda $C081 ;read ROM
lda $C081
lda #0 ;start by assuming unknown machine
sta MACHINE
sta ROMLEVEL
.IdStart
lda .location ;save zero page locations
sta .save+4 ;for later restoration
lda .location+1
sta .save+5
lda #$FB ;all ID bytes are in page $FB
sta .location+1 ;save in zero page as high byte
ldx #0 ;init pointer to start of ID table
.loop lda .IDTable,x ;get the machine we are testing for
sta MACHINE ;and save it
lda .IDTable+1,x ;get the ROM level we are testing for
sta ROMLEVEL ;and save it
ora MACHINE ;are both zero?
beq .matched ;yes - at end of list - leave
.loop2 inx ;bump index to loc/byte pair to test
inx
lda .IDTable,x ;get the byte that should be in ROM
beq .matched ;if zero, we're at end of list
sta .location ;save in zero page
ldy #0 ;init index for indirect addressing
lda .IDTable+1,x ;get the byte that should be in ROM
cmp (.location),y ;is it there?
beq .loop2 ;yes, so keep on looping
.loop3 inx ;we didn't match. Scoot to the end of the
inx ;line in the ID table so we can start
lda .IDTable,x ;checking for another machine
bne .loop3
inx ;point to start of next line
bne .loop ;should always be taken
.matched ; anop
; Here we check the 16-bit ID routine at idroutine ($FE1F). If it
; returns with carry clear, we call it again in 16-bit
; mode to provide more information on the machine.
!cpu 65816 {
.idIIgs
sec ;set the carry bit
jsr .idroutine ;Apple IIgs ID Routine
bcc .idIIgs2 ;it's a IIgs or equivalent
jmp .IIgsOut ;nope, go check memory
.idIIgs2
lda MACHINE ;get the value for machine
ora #$80 ;and set the high bit
sta MACHINE ;put it back
clc ;get ready to switch into native mode
xce
php ;save the processor status
rep #$30 ;sets 16-bit registers
!al { ;longa on
!rl { ;longi on
jsr .idroutine ;call the ID routine again
sta .IIgsA ;16-bit store!
stx .IIgsX ;16-bit store!
sty .IIgsY ;16-bit store!
plp ;restores 8-bit registers
xce ;switches back to whatever it was before
} ;longi off
} ;longa off
ldy .IIgsY ;get the ROM vers number (starts at 0)
cpy #$02 ;is it ROM 01 or 00?
bcs .idIIgs3 ;if not, don't increment
iny ;bump it up for romlevel
.idIIgs3
sty ROMLEVEL ;and put it there
cpy #$01 ;is it the first ROM?
bne .IIgsOut ;no, go on with things
lda .IIgsY+1 ;check the other byte too
bne .IIgsOut ;nope, it's a IIgs successor
lda #$7F ;fix faulty ROM 00 on the IIgs
sta .IIgsA
.IIgsOut ; anop
}
;;; ******************************************
;;; * This part of the code checks for the *
;;; * memory configuration of the machine. *
;;; * If it's a IIgs, we've already stored *
;;; * the total memory from above. If it's *
;;; * a IIc or a IIe Card, we know it's *
;;; * 128K; if it's a ][+, we know it's at *
;;; * least 48K and maybe 64K. We won't *
;;; * check for less than 48K, since that's *
;;; * a really rare circumstance. *
;;; ******************************************
.exit lda MACHINE ;get the machine kind
bmi .exit128 ;it's a 16-bit machine (has 128K)
cmp #IIc ;is it a IIc?
beq .exit128 ;yup, it's got 128K
cmp #IIeCard ;is it a IIe Card?
beq .exit128 ;yes, it's got 128K
cmp #IIe ;is it a IIe?
bne .contexit ;yes, go muck with aux memory
jmp .muckaux
.contexit
cmp #IIIem ;is it a /// in emulation?
bne .exitII ;nope, it's a ][ or ][+
lda #48 ;/// emulation has 48K
jmp .exita
.exit128
lda #128 ;128K
.exita sta MEMORY
.exit1 lda .lc1 ;time to restore the LC
cmp .save ;if all 4 bytes are the same
bne .exit2 ;then LC was never on so
lda .lc2 ;do nothing
cmp .save+1
bne .exit2
lda .lc3
cmp .save+2
bne .exit2
lda .lc4
cmp .save+3
beq .exit6
.exit2 lda $C088 ;no match! so turn first LC
lda .lc1 ;bank on and check
cmp .save
beq .exit3
lda $C080
jmp .exit6
.exit3 lda .lc2
cmp .save+1 ;if all locations check
beq .exit4 ;then do more more else
lda $C080 ;turn on bank 2
jmp .exit6
.exit4 lda .lc3 ;check second byte in bank 1
cmp .save+2
beq .exit5
lda $C080 ;select bank 2
jmp .exit6
.exit5 lda .lc4 ;check third byte in bank 1
cmp .save+3
beq .exit6
lda $C080 ;select bank 2
.exit6 plp ;restore interrupt status
lda .save+4 ;put zero page back
sta .location
lda .save+5 ;like we found it
sta .location+1
rts ;and go home.
.exitII
lda .lcbank1 ;force in language card
lda .lcbank1 ;bank 1
ldx .lc2 ;save the byte there
lda #.test1 ;use this as a test byte
sta .lc2
eor .lc2 ;if the same, should return zero
bne .noLC
lsr .lc2 ;check twice just to be sure
lda #.test2 ;this is the shifted value
eor .lc2 ;here's the second check
bne .noLC
stx .lc2 ;put it back!
lda #64 ;there's 64K here
jmp .exita
.noLC lda #48 ;no restore - no LC!
jmp .exita ;and get out of here
.muckaux
ldx .rdtext ;remember graphics in X
lda .rdpage2 ;remember current video display
asl ;in the carry bit
lda #.test3 ;another test character
bit .rd80col ;remember video mode in N
sta .set80col ;enable 80-column store
php ;save N and C flags
sta .txtpage2 ;set page two
sta .txtset ;set text
ldy .begpage1 ;save first character
sta .begpage1 ;and replace it with test character
lda .begpage1 ;get it back
sty .begpage1 ;and put back what was there
plp
bcs .muck2 ;stay in page 2
sta .txtpage1 ;restore page 1
.muck1 bmi .muck2 ;stay in 80-columns
sta $c000 ;turn off 80-columns
.muck2 tay ;save returned character
txa ;get graphics/text setting
bmi .muck3
sta .txtclr ;turn graphics back on
.muck3 cpy #.test3 ;finally compare it
bne .nocard ;no 80-column card!
lda .rdramrd ;is aux memory being read?
bmi .muck128 ;yup, there's 128K!
lda .rdaltzp ;is aux zero page used?
bmi .muck128 ;yup!
ldy #.done-.start
.move ldx .start-1,y ;swap section of zero page
lda <.safe-1,y ;code needing safe location during
stx <.safe-1,y ;reading of aux mem
sta .start-1,Y
dey
bne .move
jmp .safe ;jump to safe ground
.back php ;save status
ldy #.done-.start ;move zero page back
.move2 lda .start-1,y
sta .safe-1,y
dey
bne .move2
pla
bcs .noaux
.isaux jmp .muck128 ;there is 128K
;;; * You can put your own routine at "noaux" if you wish to
;;; * distinguish between 64K without an 80-column card and
;;; * 64K with an 80-column card.
.noaux ; anop
.nocard lda #64 ;only 64K
jmp .exita
.muck128
jmp .exit128 ;there's 128K
;;; * This is the routine run in the safe area not affected
;;; * by bank-switching the main and aux RAM.
.start lda #.test4 ;yet another test byte
sta .wrcardram ;write to aux while on main zero page
sta .rdcardram ;read aux ram as well
sta .begpage2 ;check for sparse memory mapping
lda .begsprse ;if sparse, these will be the same
cmp #.test4 ;value since they're 1K apart
bne .auxmem ;yup, there's 128K!
asl .begsprse ;may have been lucky so we'll
lda .begpage2 ;change the value and see what happens
cmp .begsprse
bne .auxmem
sec ;oops, no auxiliary memory
bcs .goback
.auxmem clc
.goback sta .wrmainram ;write main RAM
sta .rdmainram ;read main RAM
jmp .back ;continue with program in main mem
.done nop ;end of relocated program marker
;;; * The storage locations for the returned machine ID:
MACHINE !byte 1 ;the type of Apple II
ROMLEVEL !byte 1 ;which revision of the machine
MEMORY !byte 1 ;how much memory (up to 128K)
.IIgsA !byte 2 ;16-bit field
.IIgsX !byte 2 ;16-bit field
.IIgsY !byte 2 ;16-bit field
.save !byte 6 ;six bytes for saved data
.IDTable
;dc I1'1,1' ;Apple ][
;dc H'B3 38 00'
!byte 1,1
!byte $B3,$38,0
;dc I1'2,1' ;Apple ][+
;dc H'B3 EA 1E AD 00'
!byte 2,1
!byte $B3,$EA,$1E,$AD,0
;dc I1'3,1' ;Apple /// (emulation)
;dc H'B3 EA 1E 8A 00'
!byte 3,1
!byte $B3,$EA,$1E,$8A,0
;dc I1'4,1' ;Apple IIe (original)
;dc H'B3 06 C0 EA 00'
!byte 4,1
!byte $B3,$06,$C0,$EA,0
; Note: You must check for the Apple IIe Card BEFORE you
; check for the enhanced Apple IIe since the first
; two identification bytes are the same.
;dc I1'6,1' ;Apple IIe Card for the Macintosh LC (1st release)
;dc H'B3 06 C0 E0 DD 02 BE 00 00'
!byte 6,1
!byte $B3,$06,$C0,$E0,$DD,$02,$BE,$00,0
;dc I1'4,2' ;Apple IIe (enhanced)
;dc H'B3 06 C0 E0 00'
!byte 4,2
!byte $B3,$06,$C0,$E0,0
;dc I1'5,1' ;Apple IIc (original)
;dc H'B3 06 C0 00 BF FF 00'
!byte 5,1
!byte $B3,$06,$C0,$00,$BF,$FF,0
;dc I1'5,2' ;Apple IIc (3.5 ROM)
;dc H'B3 06 C0 00 BF 00 00'
!byte 5,2
!byte $B3,$06,$C0,$00,$BF,$00,0
;dc I1'5,3' ;Apple IIc (Mem. Exp)
;dc H'B3 06 C0 00 BF 03 00'
!byte 5,3
!byte $B3,$06,$C0,$00,$BF,$03,0
;dc I1'5,4' ;Apple IIc (Rev. Mem. Exp.)
;dc H'B3 06 C0 00 BF 04 00'
!byte 5,4
!byte $B3,$06,$C0,$00,$BF,$04,0
;dc I1'5,5' ;Apple IIc Plus
;dc H'B3 06 C0 00 BF 05 00'
!byte 5,5
!byte $B3,$06,$C0,$00,$BF,$05,0
;dc I1'0,0' ;end of table
!byte 0,0
} ; end of zone technote2