******************************** * * * Machine Detection * * * * Routines * * * * BY MARC GOLOMBECK * * * * VERSION 1.00 / 26.04.2019 * ******************************** * DSK detect MX %11 ORG $901 ; routine starts at $0901 * HOME EQU $FC58 ; CLEAR SCREEN COUT EQU $FDED ; PRINT CHARACTER KYBD EQU $C000 ; READ KEYBOARD STROBE EQU $C010 ; CLEAR KEYBOARD BELL EQU $FBDD ; RING BELL WAIT EQU $FCA8 ; WAIT A BIT PREAD EQU $FB1E ; switch to LORES VERTBLANK EQU $C019 ; vertical blanking -> available only IIe and above MEMCOPY EQU $FE2C ; monitor routine for copying RAM WRITERAM EQU $C081 ; read ROM write RAM - toggle 2 times READROM EQU $C082 ; read ROM no write - toggle 1 time READWRITE EQU $C083 ; read & write RAM - toggle 2 times READRAM EQU $C080 ; read RAM no write - toggle 1 time * bMB EQU $2078 ; MockingBoard available? ($00/No | $01 Yes) bMachine EQU $2079 ; auto detect Apple II machine type bMem EQU $207A ; 128k? ($00 No | $78 Yes) bZC EQU $207B ; ZIPchip installed? ($00/No | $01 Yes) bFC EQU $207C ; FastChip installed? ($00/No | $01 Yes) bLC EQU $207D ; Language Card available? ($00/No | $01 Yes) bMBSlot EQU $207E ; slot of MockingBoard ($01..$07) bRefresh EQU $207F ; byte REFRESH RATE ($00/50Hz | $01/60Hz) b65C02 EQU $20F8 ; byte CPU ($00/6502 | $01/65C02 | $FF/65816) bEmu EQU $20F9 ; emulator detection ($00/No | $01 Yes) * chkMEM EQU $0100 ; adress of AUX mem checking routine dest EQU $F8 ; + $F9 MB_ADDRL EQU $06 MB_ADDRH EQU $07 TICKS EQU $09 charFLAG EQU $FF ; only uppercase letters? * * * FastChip constants * FC_UNLOCK EQU $6A ; FastChip unlock value FC_LOCK EQU $A6 ; FastChip lock value FC_LOCK_REG EQU $C06A ; FastChip lock register FC_EN_REG EQU $C06B ; FastChip enable register FC_SPD_REG EQU $C06D ; FastChip speed register * INIT SEI ; just to be sure... JSR DETECTA2 ; get machine type STA $C000 ; 80STOREOFF STA $C008 ; zero Page = Main (+ $FXXX MAIN) * JSR COPYAUX ; copy main program to AUX-memory JSR COPYROM ; copy MONITOR to language card JMP chkMEM ; jump to short routine in Stack for checking AUX MEM size JSR DETECTCPU JSR DETECTREFRESH * JSR DETECTZIP ; detect and disable a ZIPchip JSR DETECTFC ; detect FastChip and set to 1 MHz JSR DETECTEMU ; detect possible emulator first JSR DETECTLC ; can we also detect a language card? JSR MB_DETECT ; detect MB-slot JSR HOME ; clear screen JSR PRTRES ; print detection results on screen * RTS * * ************************************************* * COPY PROGRAM TO AUX MEMORY * ************************************************* * COPYAUX STA $C002 ; read MAIN STA $C005 ; write AUX LDA #$09 ; set start adress HI-byte STA dest+1 ; for page copy LDA #0 STA dest ; LO-byte * cpAUXlp2 LDY #0 ; loop over Y cpAUXlp1 LDA (dest),Y ; read from MAIN memory STA (dest),Y ; store to AUX memory at same address! INY BNE cpAUXlp1 INC dest+1 ; increase HI-byte +1 LDA dest+1 ; must include the MB-playing routine in code copy! CMP #$0d ; HI-Byte = $14? Copy until reaching $13FF! BNE cpAUXlp2 ; no, copy next page STA $C004 ; write MAIN LDA #>CODE STA dest+1 LDA # copy MEM chk routine to Stack area STA dest LDY #0 STY bMem ; init result byte cpSTACK LDA (dest),Y STA chkMEM,Y INY CPY #15 BNE cpSTACK * RTS * * * copy monitor ROM * COPYROM LDY #$F8 ; copy Monitor-ROM to Language Card STY $3D STY $43 LDY #$FF STY $3E STY $3F INY STY $3C STY $42 LDA WRITERAM ; toggle Language Card RAM for writing LDA WRITERAM JSR MEMCOPY LDA READROM ; toggle Language Card off RTS *============================================================================= * * detect slot with MockingBoard * MB_DETECT LDA #0 STA MB_ADDRL * MB_DET_lp LDA #$07 ; we start in slot 7 ($C7) and go down to 0 ($C0) STA bMBSlot ; slot with MB ORA #$C0 ; make it start with C STA MB_ADDRH LDY #04 ; $CX04 LDX #02 ; 2 tries? MB_CHK_CYC LDA (MB_ADDRL),Y ; timer 6522 (Low Order Counter) * ; count down STA TICKS ; 3 cycles LDA (MB_ADDRL),Y ; + 5 cycles EQU 8 cycles * ; between the two accesses to the timer SEC SBC TICKS ; subtract to see if we had 8 cycles (accepted range 7-9) CMP #$f8 ; -8 BEQ DEC_X CMP #$F9 ; -7 - range is necessary if FastChip is installed BEQ DEC_X CMP #$F7 ; -9 BNE MB_NOT_SLOT DEC_X DEX ; decrement, try one more time BNE MB_CHK_CYC ; loop detection INX ; Mockingboard found (XEQU1) DONE_DET STX bMB ; store result to bMB RTS ; return * MB_NOT_SLOT DEC MB_DET_lp+1 ; decrement the "slot" (self_modify) BNE MB_DET_lp ; loop down to one LDX #00 BEQ DONE_DET *============================================================================= * * detect type of Apple 2 computer * DETECTA2 LDA #$FF STA charFLAG ; allow lower case output LDA $FBB3 CMP #$06 ; IIe/IIc/IIGS = 06 BEQ checkII ; if not II ($38) or II+ ($EA) _G22PLUS STA bMachine ; save $38 or $EA as machine byte LDA #%11011111 ; convert lowercase chars to uppercase STA charFLAG RTS * checkII LDA $FBC0 ; detect IIc BEQ _G2C ; 0 = IIc / Other = no IIc * SEC ; IIgs or IIe ? JSR $FE1F ; test for GS BCS _G2E ; if carry flag is set -> IIE * LDA #$FF ; IIGS -> $FF STA bMachine *============================================================================= * * condition some IIgs settings * LDA $C036 ; put IIgs in 8-bit-mode AND #$7F STA $C036 ; slow speed * LDA $C034 ; AND #$F0 STA $C034 ; black border * LDA $C022 AND #$F0 ; bit 0-3 at 0 = background black ORA #$F0 ; bit 7-4 at 1 = text white STA $C022 ; background black/text white RTS * _G2E LDA #$7F ; IIE -> $7F STA bMachine RTS * _G2C STA bMachine ; IIc -> $00 RTS *============================================================================= * * detect CPU type * DETECTCPU LDA #00 BRA _is65C02 ; results in a BRA +4 if 65C02/65816 or NOPs if 6502 BEQ _contD ; a 6502 drops through directly to the BEQ here _is65C02 INC A ; 65C02/65816 arrives here * ; some 65816 code here XBA ; .byte $eb, put $01 in B accu -> equals a NOP for 65C02 DEC A ; .byte $3a, A=$00 if 65C02 XBA ; .byte $eb, get $01 back if 65816 INC A ; .byte $1a, make $01/$02 _contD STA b65C02 RTS *============================================================================= * * detect and disable a ZIPchip * DETECTZIP LDA #$5A ; unlock ZC STA $C05A STA $C05A STA $C05A STA $C05A LDX #$00 CACHE LDA ALTER,X ; put altering part of the code in the cache! INX BNE CACHE ALTER LDA $C05C ; Get the slot delay status EOR #$FF ; Flip it STA $C05C ; Save it CMP $C05C ; Correct? BNE NOZIP ; No, ZIP CHIP not found. EOR #$FF ; Get back old status STA $C05C ; Save it CMP $C05C ; Correct? BNE NOZIP ; No, ZIP CHIP not found. LDA #$00 ; other value as $5A or $A5 STA $C05A ; will disable ZC LDA #$A5 ; lock ZC STA $C05A LDA #01 STA bZC RTS NOZIP LDA #00 STA bZC RTS *============================================================================= * * detect a FastChip and set speed to 1 MHz * DETECTFC LDA bMachine ; get machine type byte LDX #$00 CMP #$7F ; Apple IIe BEQ chk_slot BNE not_found chk_slot LDY #$04 ; loop 4 times LDA #FC_UNLOCK ; load the unlock value unlock_lp STA FC_LOCK_REG ; store in lock register DEY BNE unlock_lp LDA #$00 ; MegaAudio check STA FC_EN_REG ; enable the Fast Chip LDY FC_EN_REG ; bit 7 will be high when enabled CPY #$80 BNE not_found found LDA #$80 ; reset speed register STA FC_SPD_REG LDA #$09 ; set FC speed to 1.10 MHz STA FC_SPD_REG ; necessary for correct MB-detection! LDA #FC_LOCK STA FC_LOCK_REG ; lock the registers again LDA #$01 STA bFC RTS not_found TXA STA bFC RTS *============================================================================= * * detect Language Card * DETECTEMU LDA #0 STA bEmu ; set value to "real wood" LDX #0 ; read PDL(0) JSR PREAD STY PDL0 ; store value LDX #1 ; read PDL(0) JSR PREAD STY PDL1 ; store value LDX #2 ; read PDL(0) JSR PREAD STY PDL2 ; store value LDX #3 ; read PDL(0) JSR PREAD STY PDL3 ; store value * LDA #0 STA PDL0+1 STA PDL1+1 STA PDL2+1 STA PDL3+1 CLC LDA PDL0 ; adding all read PDL values ADC PDL1 ; emulators mainly return #127 for PDL-read STA PDLsum ; real wood returns 255 if no paddle is connected LDA PDL0+1 ; or anything else (but mostly not 127 for all values) ADC PDL1+1 STA PDLsum+1 CLC LDA PDLsum ; adding all read PDL values ADC PDL2 ; emulators mainly return #127 for PDL-read STA PDLsum LDA PDLsum+1 ADC PDL2+1 STA PDLsum+1 CLC LDA PDLsum ; adding all read PDL values ADC PDL3 ; emulators mainly return #127 for PDL-read STA PDLsum LDA PDLsum+1 ADC PDL3+1 STA PDLsum+1 LDA PDLsum+1 CMP #1 BEQ Pchk1 ; check for 508 as magic number = 4*127 JMP Pchk3 Pchk1 LDA PDLsum CMP #252 BEQ Pchk2 JMP Pchk3 Pchk2 ; magic number found INC bEmu ; bEmu = 1 RTS * Pchk3 LDA PDL0 ; second check if first check fails CMP PDL1 ; PDL(0) = PDL(1)? BEQ Pchk3a ; yes -> check for other two values RTS ; values are different, likely real wood Pchk3a LDA PDL0 ; open gate? (=255) is likely to be real wood here with no joystick connected CMP #255 BNE Pchk3b RTS Pchk3b LDA PDL2 CMP PDL3 BEQ Pchk2 ; assume emulator RTS PDL0 DS 2 ; paddle read values PDL1 DS 2 PDL2 DS 2 PDL3 DS 2 PDLsum DS 2 *============================================================================= * * detect Emulator * DETECTLC LDA $C083 ; turn on LC LDA $C083 LDA $D000 INC $D000 CMP $D000 BEQ noLCARD DEC $D000 LDA #1 ; language card positive STA bLC ; -> might be an emulator! JMP exitEMU noLCARD LDA #0 STA bLC LDA bEmu ; emulator detected? BNE exitEMU LDA #2 ; can't tell if running in an emulator -> sorry! STA bEmu exitEMU LDA $C081 ; turn off LC RTS *============================================================================= * * detect screen refresh rate * DETECTREFRESH LDA bMachine BEQ Refresh_IIC ; IIc -> another refresh detection method is necessary CMP #$EA BEQ _badguy ; II+ -> no detection possible CMP #$38 BEQ _badguy ; II -> no detection possible _L1 CMP VERTBLANK ; works with IIGS/IIE BPL _L1 ; wait until the end of the vertical blank _L2 CMP VERTBLANK ; synchronizing counting algorithm BMI _L2 ; wait until the end of the complete display -> start of vertical blanking _BP3 INC COUNTREF ; 6 increment counter LDX #$09 ; wait for a certain number of cycles _WL3 DEX ; BNE _WL3 ; = 46 cycles ; + 6 + 3 + 3 + 4 + 3 = 65 ! LDA bMachine ; 3 LDA bMachine ; 3 CMP VERTBLANK ; 4 Bpl _BP3 ; 3 -> repeat and increment counter until VBL is done LDA COUNTREF CMP #72 ; >= 72 equals 50 HZ (120*65 cycles of VBL) BCS _GO3 LDA #01 ; 60HZ (VBL = 70x65 cycles) JMP _GO4 _GO3 LDA #00 ; 50HZ (VBL = 120x65 cycles) _GO4 STA bRefresh RTS * _badguy LDA #$FF ; system without VBL-signal is a bad guy STA bRefresh RTS * Refresh_IIC ; specific treatment for Apple IIc STA $C070 STA $C07F STA $C05B _l1 LDA $C019 ; preparation for the beginning of VBL bpl _l1 STA $C070 STA $C07F STA $C05B ; enable VBL interrupt _BP2 INC COUNTREF ; 6 increment counter LDX #$09 ; _WL1 DEX ; BNE _WL1 ; = 46 cycles ; + 6 + 6 + 4 + 3 = 65 ! NOP NOP NOP ; 3*2 = 6 additional cycles LDA $C019 ; waiting for the next VBL to begin bpl _BP2 ; 3 -> wait for vblflag = 1 STA $C058+2 ; disable VBL int. Contains a complete VBL + one display. Exit on the beginning of LDA COUNTREF ; the next VBL gives = 192+70+(50) = $138 or ($106) hence $38 or $06 CMP #$10 ; >= 16 hence 50 HZ BCS _GO1 LDA #01 ; 60HZ JMP _GO2 _GO1 LDA #00 ; 50HZ _GO2 STA bRefresh RTS COUNTREF DS 1 *============================================================== * * print detection results on screen * PRTRES LDA #0 ; set cursor position STA $25 JSR LFEED LDA #6 ; HTAB 6 STA $24 LDX #T_APPLE JSR PRINT JSR LFEED JSR LFEED LDA #7 ; HTAB 7 STA $24 LDX #T_MACH JSR PRINT LDA bMachine BNE comp1 ; //c = $00? LDX #T_COMP3 JSR PRINT JMP NEXT1 comp1 CMP #$7F ; //e? BNE comp2 LDX #T_COMP1 JSR PRINT JMP NEXT1 comp2 CMP #$FF ; IIgs? BNE comp3 LDX #T_COMP2 JSR PRINT JMP NEXT1 comp3 CMP #$38 ; II? BNE comp4 LDX #T_COMP4 JSR PRINT JMP NEXT1 comp4 CMP #$EA ; II? BNE comp5 LDX #T_COMP5 JSR PRINT JMP NEXT1 comp5 LDX #T_COMP6 JSR PRINT NEXT1 JSR LFEED ; print CPU type LDA #7 ; HTAB 7 STA $24 LDX #T_CPU JSR PRINT LDA b65C02 CMP #2 ; 65816 in any machine setting! BEQ _s2_cpu LDA b65C02 BEQ _s1_cpu ; 0 (6502) BMI _s2_cpu ; >$7F (65816 or 65C802) LDX #T_CPU2 JSR PRINT JMP NEXT1a _s1_cpu LDX #T_CPU1 JSR PRINT JMP NEXT1a _s2_cpu ; CPU is 65816 or 65C802 LDA bMachine CMP #$FF BEQ cpu816 ; is 65816 LDX #T_CPU4 JSR PRINT JMP NEXT1a cpu816 LDX #T_CPU3 JSR PRINT NEXT1a JSR LFEED ; output RAM LDA #7 ; HTAB 7 STA $24 LDX #T_RAM JSR PRINT LDA bMem CMP #$78 ; $78 is flag byte for 128k! BNE not128 ; 64 or 48k LDA bMachine ; check for Apple ][ and ][+ -> no 128k supported CMP #$38 BEQ not128 CMP #$EA BEQ not128 LDX #T_128 JSR PRINT JMP NEXT1b not128 LDA bLC BEQ only48 LDX #T_64 JSR PRINT JMP NEXT1b only48 LDX #T_48 JSR PRINT NEXT1b JSR LFEED ; output Language Card LDA #7 ; HTAB 7 STA $24 LDX #T_LANG JSR PRINT LDA bLC BEQ noLC LDX #T_YES JSR PRINT JMP NEXT2 noLC LDX #T_NO JSR PRINT NEXT2 JSR LFEED ; print refresh rate LDA #7 ; HTAB 7 STA $24 LDX #T_REFRESH JSR PRINT LDA bRefresh BMI _s2_rate BEQ _s1_rate LDX #T_RATE2 JSR PRINT JMP NEXT3 _s1_rate LDX #T_RATE1 JSR PRINT JMP NEXT3 _s2_rate LDX #T_RATE3 JSR PRINT NEXT3 JSR LFEED ; output MockingBoard detection results LDA #7 ; HTAB 7 STA $24 LDX #T_MOCK JSR PRINT LDA bMB BEQ noMB ; no MB detected LDX #T_SLOT JSR PRINT LDA bMBSlot ; get slot no and convewrt to ASCII-value CLC ADC #$B0 JSR COUT ; output ASCII-value! JMP NEXT4 noMB LDX #T_NONE JSR PRINT NEXT4 JSR LFEED ; output FastChip detection LDA #7 ; HTAB 7 STA $24 LDX #T_FC JSR PRINT LDA bFC BEQ noFC ; no FC detected LDX #T_YES JSR PRINT JMP NEXT5 noFC LDX #T_NO JSR PRINT NEXT5 JSR LFEED ; output ZipChip detection result LDA #7 ; HTAB 7 STA $24 LDX #T_ZC JSR PRINT LDA bZC BEQ noZC ; no ZC detected LDX #T_YES JSR PRINT JMP NEXT6 noZC LDX #T_NO JSR PRINT NEXT6 JSR LFEED ; output Emulator detection JSR LFEED LDA #7 ; HTAB 7 STA $24 LDX #T_EMU JSR PRINT LDA bEmu BEQ pnoEmu CMP #1 BEQ pyesEmu LDX #T_UNCLEAR JSR PRINT JMP prtSHK pnoEmu LDX #T_RATE3 JSR PRINT JMP prtSHK pyesEmu LDX #T_POS JSR PRINT prtSHK JSR LFEED ; output copyright notice JSR LFEED JSR LFEED LDA #4 ; HTAB 4 STA $24 LDX #T_SHACK JSR PRINT resRTS RTS * * * text output routines * LFEED LDA #$8D ; print a line feed JSR COUT RTS * PRINT ; x = LO-Byte Text, y = HI-Byte Text !zone STX ba+1 STY ba+2 LDX #00 ba LDA $1000,X BEQ rtsPRINT CMP #$E1 ; "a" char in lower case range? BCC doCOUT ; no -> direct output CMP #$FB ; "z" BCS doCOUT ; no -> direct output AND charFLAG ; lowercase conversion if necessary doCOUT JSR COUT ; output ASCII on screen INX BNE ba rtsPRINT RTS *============================================================================= * * AUX-memory detection code * CODE HEX 8D03C0AD01098D02 HEX C08D7A204C1409 * * * text output data * T_APPLE ASC "* Hardware Autodetection *" HEX 00 T_SHACK ASC "* V.1.00 by 8-BIT-SHACK 2019 *" HEX 00 T_MACH ASC "Machine: " HEX 00 T_COMP1 ASC "Apple //e" HEX 00 T_COMP2 ASC "Apple IIgs" HEX 00 T_COMP3 ASC "Apple //c" HEX 00 T_COMP4 ASC "Apple ][" HEX 00 T_COMP5 ASC "Apple ][+" HEX 00 T_COMP6 ASC "Other" HEX 00 T_RAM ASC "RAM: " HEX 00 T_48 ASC "48kB " HEX 00 T_64 ASC "64kB (LC) " HEX 00 T_128 ASC ">= 128kB " HEX 00 T_MOCK ASC "MockingBoard: " HEX 00 T_NONE ASC "None " HEX 00 T_SLOT ASC "Slot #" HEX 00 T_FC ASC "FastChip: " HEX 00 T_YES ASC "Yes" HEX 00 T_ZC ASC "ZIPChip: " HEX 00 T_NO ASC "No" HEX 00 T_CPU ASC "CPU-Type: " HEX 00 T_REFRESH ASC "Refresh Rate: " HEX 00 T_LANG ASC "Language Card: " HEX 00 T_EMU ASC "Emulator: " HEX 00 T_CPU1 ASC "6502" HEX 00 T_CPU2 ASC "65C02" HEX 00 T_CPU3 ASC "65816" HEX 00 T_CPU4 ASC "65C802" HEX 00 T_RATE1 ASC "50Hz" HEX 00 T_RATE2 ASC "60Hz" HEX 00 T_RATE3 ASC "Not detected!" HEX 00 T_POS ASC "Detected!" HEX 00 T_UNCLEAR ASC "Unclear..." HEX 00 * * end of file *