.IF EXTERNAL = 1 .NOLIST .ENDC .PAGE .ABSOLUTE ;makes listing look nicer .PROC LISAROM,0 .ORG 0 ; ORG'ED AT 0 BUT RUNS AT $00FE0000 ; Reset vectors here to pick up SP and PC values BASE .WORD $0000 ;initial SP .WORD STKBASE .WORD ROMSLCT ;initial PC (assumes use of MMU reg 127) .WORD BEGIN ; Set up next locations for exception vectors BUSVCT .WORD ROMSLCT ; BUS ERROR VECTOR .WORD EXCPERR ADRVCT .WORD ROMSLCT ; ADDRESS ERROR .WORD EXCPERR ILLVCT .WORD ROMSLCT ; ILLEGAL INSTRUCTION .WORD EXCPERR DIV0VCT .WORD ROMSLCT ; DIVIDE BY ZERO ERROR .WORD EXCPERR CHKVCT .WORD ROMSLCT ; CHK INSTRUCTION .WORD EXCPERR TRAPVCT .WORD ROMSLCT ; TRAPV INSTRUCTION .WORD EXCPERR PRIVCT .WORD ROMSLCT ; PRIVILEGE VIOLATION .WORD EXCPERR TRCVCT .WORD ROMSLCT ; TRACE OPERATION .WORD EXCPERR L10VCT .WORD ROMSLCT ; OPCODE 1010 DETECTED .WORD EXCPERR L11VCT .WORD ROMSLCT ; OPCODE 1111 DETECTED .WORD EXCPERR ;------------------------------------------------------------------ ; Exception and interrupt vector handler for ROM - resets SP and ; tries a restart ;------------------------------------------------------------------ EXCPERR MOVEA #STKBASE,SP ;reset stack ptr CLR.L D7 ;clear error indicator CHG004 BRA ROMTST ;and restart diags CHG004 .PAGE ;-------------------------------------------------------------------- ; Subroutine for saving registers and stack pointers ;-------------------------------------------------------------------- SAVEREGS MOVE.L SP,SUPSTK ;save sup stack ptr SAVEREG2 MOVE.L A6,A6SAV ;save other regs (that aren't reset) MOVE.L USP,A6 MOVE.L A6,USPSAV MOVE #A6SAV,A6 ;set ptr for saving regs MOVEM.L D0-D7/A0-A5,-(A6) RTS ; use spare bytes for message SVCMSG .ASCII 'SERVICE MODE' ; RM000 .BYTE 0 ; RM000 .ORG $60 ; The next set of vectors cover spurious and autovector interrupts SPURVCT .WORD ROMSLCT ; SPURIOUS INTERRUPT .WORD EXCPERR LVL1VCT .WORD ROMSLCT ; INTERNAL I/O INTERRUPTS (DISK,VERT TRACE,ETC.) .WORD EXCPERR LVL2VCT .WORD ROMSLCT ; KEYBOARD INTERRUPT .WORD EXCPERR LVL3VCT .WORD ROMSLCT ; I/O SLOT 2 INTERRUPT .WORD EXCPERR LVL4VCT .WORD ROMSLCT ; I/O SLOT 1 .WORD EXCPERR LVL5VCT .WORD ROMSLCT ; I/O SLOT 0 .WORD EXCPERR LVL6VCT .WORD ROMSLCT ; RS-232 .WORD EXCPERR LVL7VCT .WORD ROMSLCT ; NMI .WORD NMIEXCP ; RM010 .IF EXTERNAL = 1 .LIST .ENDC .PAGE .ORG $80 ;------------------------------------------------------------------------- ; Jump Table for calling by external routines ;------------------------------------------------------------------------- JMPTBL JMP DORESET ;go to restart point RM000 JMP INITMON ;jump to ROM Monitor .IF USERINT = 0 JMP DSPMSG ;display a message .ELSE JMP CONVRTD5 ;convert row ptr and display message .ENDC JMP WRTMMU ;write to set of MMU registers JMP PROREAD ;Profile read a block routine JMP TWGREAD ;Twiggy read a sector routine .IF DIAGS = 1 JMP RAMTEST ;basic memory test NOP ; CHG015 RTS ; CHG015 NOP ; CHG015 RTS ; CHG015 .ELSE NOP RTS NOP RTS NOP RTS .ENDC JMP READMMU ;read MMU registers JMP COPSCMD ;Send COPS command .IF DIAGS = 1 JMP READCLK ;Read clock setting .ELSE NOP RTS .ENDC JMP DSPDEC ;display hex error code in decimal JMP CONSET2 ;for setting contrast JMP TONE ;to beep speaker JMP VFYCHKSM ;verify checksum .IF ROM4K = 0 JMP WRTSUM ;rewrite parameter memory CHG017 JMP RDSERN ;go read system serial # .ENDC ;******************** Loop point for ROM test failure ******************************** SPIN BRA.S SPIN ;hang system CHG007 ;************************************************************************************* .IF EXTERNAL = 1 .NOLIST .ENDC ;---------------------------------------------------------------------------- ; NMI Exception Handler RM010 ;---------------------------------------------------------------------------- NMIEXCP CLR.B SETUP ;enable memory access RM010 BTST #1,STATREG ;parity error? RM010 BNE.S @1 ;skip if not to ignore RM010 MOVE MEALTCH,ADRLTCH ;save address if yes RM010 TST.B PAROFF ;and toggle to clear error bit RM010 TST.B PARON ; RM010 @1 TST.B SETUPON ;return to SETUP state RM010 RTE ; RM010 .PAGE ;---------------------------------------------------------------------------- ; First do "warm-start" no reset check - scan I/O MMU regs to see if set up ;---------------------------------------------------------------------------- BEGIN .IF NORESET = 1 MOVE MMU126L,D0 ;check reg 126 for special I/O space ANDI #$0FFF,D0 ;ignore don't care bits CMPI #IOLMT2,D0 ;for no reset, 126L = $x901 (x = random value) BNE.S BEGIN2 ;skip if not set up ANDI #$0FFF,MMU126B ;else also check 126B = $x000 BNE.S BEGIN2 ; Check OK - set MMU for ROM access and change SETUP before vectoring MOVE #MEMLMT,MMU0L ;set low memory for r/w (to save regs,etc.) MOVE #IOLMT2,MMU126L ;set for I/O space access (reset value) MOVE #SPLMT,MMU127L ;set access for ROM space MOVE #0,MMU127B CLR.B SETUP ;enable memory access MOVE.L SP,SUPSTK ;save supervisor stack ptr MOVEA #STKBASE,SP ;move stack pointer for ROM use BSR.S SAVEREG2 ;save other registers ; Restore ROM Monitor environment BSR4 CONSET ;go set default contrast SUBA.L A2,A2 ;set for no icons CLR.L D0 ; error codes SUBA.L A3,A3 ; or messages BRA INIT1 ;exit directly to monitor (avoid resaving regs) .ENDC ;------------------------------------------------------------------------- ; Do second warm-start check to see if contrast should be reset ;------------------------------------------------------------------------- BEGIN2 CLR.L D7 ;clear for error use MOVE MMU127L,D0 ;check reg 127 for ROM space ANDI #$0FFF,D0 ;ignore don't care bits CMPI #SPLMT,D0 ;expect 127L = $xF00 (x = random value) BNE.S ROMTST ;skip if not ANDI #$0FFF,MMU127B ;else check if 127B = $x000 BNE.S ROMTST ; Check OK - set MMU for I/O and ROM access and go set contrast BSET #WRMSTRT,D7 ;set warm start indicator MOVEQ #0,D0 ;clear for use MOVE #IOLMT,MMU126L ;set access for I/O space MOVE D0,MMU126B MOVE #SPLMT,MMU127L ;set access for ROM space BEGIN3 RESET ;ensure clean I/O state for "warm-start" .IF NEWLISA = 1 BSR4 CONOFF ;and go disable contrast .ELSE BSR4 CONSET ;go set default contrast .ENDC .PAGE ;------------------------------------------------------------------------- ; Start diagnostics - do ROM checksum test first; expected result = 0 ;------------------------------------------------------------------------- ROMTST .IF DIAGS = 1 CLR.L D0 ;clear for checksum use LEA BASE,A0 ;init ROM address ptrs LEA LAST,A1 DOSUM ADD (A0)+,D0 ;read location and add to sum ROL #1,D0 ;rotate to catch multiple bit errors CMPA.L A0,A1 ;loop until done BNE.S DOSUM ADD (A0)+,D0 ;add checksum word BNE SPIN ;loop if error CHG007 TST.L D7 ;in loop mode? BMI.S ROMTST ;restart test if yes .ENDC .PAGE ;---------------------------------------------------------------------------- ; Next do read/write and address test of MMU supervisor regs ; Register Usage (by this routine and/or its subroutines): ; A0 = MMU reg pointer D0 = test pattern ; A1 = last MMU limit reg addr D1 = contents read from MMU reg ; A2 = MMU address increment D2 = OR mask of results ; A3 = last MMU base reg addr D3 = pattern expected at last error ; A4 = used for return address D4 = final value for MMU reg ; A5 = MMU address of last error D5 = unused ; A6 = used for return address D6 = unused ; A7 = stack pointer D7 = error indicator (0 = R/W error) ;---------------------------------------------------------------------------- MMUTST .IF DIAGS = 1 BSR4 MMUINIT ;initialize test variables BSR6 MMURW ;and go do read/write test BNE.S MMUERR ;abort if error BSRS4 MMUINIT ;reinitialize BSR6 MMUACHK ;and do address test BNE.S @2 ;skip if error BRA SETMMU ;else go do initial MMU setup @2 NOT D7 ;set address error indicator .PAGE ;---------------------------------------------------------------------------- ; The following code is used to toggle every address and data line ; going to the MMU if an error in the MMU context 0 tests is found. ; Reset signals indicate read/write or addressing error. ;---------------------------------------------------------------------------- MMUERR TST D7 ;check error type BEQ.S @2 RESET ;two reset signals for address error @2 RESET ;only one for R/W error ; Toggle every data and address bit MMULP MOVE.L #$00028000,A0 ;set MMU limit reg start address MOVEQ #1,D1 ;and starting data pattern MOVEQ #7,D2 ;and loop count BSRS4 TSTLOOP ;go toggle for limit regs MOVE.L #$00028008,A0 ;set MMU base reg start address MOVEQ #5,D2 ;and loop count BSRS4 TSTLOOP ;go test base regs BRA.S MMUERR ;and loop indefinitely ; Subroutine to do reg testing TSTLOOP MOVE.L A0,D0 ;save starting address REGTST MOVE D1,(A0) ;do write MOVE (A0),D3 ;then read LSL #1,D1 ;update pattern SWAP D0 ;get address LSL #1,D0 ;update and restore SWAP D0 MOVE.L D0,A0 SUBQ #1,D2 ;loop until done BNE.S REGTST RTS4 ;exit .PAGE ;---------------------------------------------------------------------------- ; Subroutine to do initial setup for MMU testing ;---------------------------------------------------------------------------- MMUINIT MOVE #PATRN2,D0 ;set test pattern MOVEQ #0,D1 ;clear for result/error use MOVEQ #0,D2 ; use MOVEQ for speed MOVE.L #ADR128K,A2 ;set up increment value ORI #$0710,SR ;set extend bit and disable interrupts RTS4 .PAGE ;---------------------------------------------------------------------------- ; Subroutine to do MMU Read/Write Test for all registers in one context. ; Zero bit set in CCR if no errors. ;---------------------------------------------------------------------------- MMURW MOVE.L #MMUSADRL,A0 ;SET MMU LIMIT START ADDR MOVE.L #MMUEADRL,A1 ;SET MMU LIMIT END ADDR MOVE.L #MMUEADRB,A3 ;SET MMU BASE END ADDR RWCHK1 BSR4 CHKRW ;GO DO READ/WRITE CHECK NOT D0 ;INVERT FOR NEXT PASS BSRS4 CHKRW ;GO DO AGAIN RWCHK2 NOT D0 ;INVERT BACK TO ORIGINAL PATTERN BSRS4 CHKRW ;ONE MORE TIME RWCHK3 ROXL #1,D0 ;SET UP NEW PATTERN CMPA.L A0,A1 ;CHECK IF DONE BEQ.S CHKBASE ;IF YES GO CHECK FOR BASE REG TESTING ADDA.L A2,A0 ;ELSE BUMP MMU ADDR BRA.S RWCHK1 CHKBASE CMPA.L A0,A3 ;DONE WITH BASE? BEQ.S @2 ;EXIT IF YES MOVE.L #MMUSADRB,A0 ;ELSE SET STARTING BASE ADDRESS MOVEA.L A3,A1 ; AND ENDING ADDRESS BRA.S RWCHK1 ;GO CHECK BASE REGS @2 TST D2 ;check for errors RTS6 ;and exit test .PAGE ;---------------------------------------------------------------------------- ; Subroutine to do MMU address check ; Leaves limit registers with invalid page value, base regs with 0 ;---------------------------------------------------------------------------- MMUACHK MOVE.L #MMUSADRL,A0 ;SET MMU LIMIT START ADDR MOVE.L #MMUEADRL,A1 ;SET MMU LIMIT END ADDR MOVE.L #MMUEADRB,A3 ;SET MMU BASE END ADDR MOVE #INVPAG,D4 ;SET FINAL VALUE FOR LIMIT REGS ACHK1 MOVE (A0),D1 ;READ REG EOR D0,D1 ;CHECK IF EXPECTED ANDI #$0FFF,D1 ;MASK DON'T CARES BNE.S MADRERR ;EXIT IF ERROR MMUSET MOVE D4,(A0) ;SET FINAL REG VALUE ROXL #1,D0 ;SET UP NEW PATTERN CMPA.L A0,A1 ;CHECK IF DONE BEQ.S ACHK2 ;IF YES GO CHECK FOR BASE REG TESTING ADDA.L A2,A0 ;ELSE BUMP MMU ADDR BRA.S ACHK1 ACHK2 CMPA.L A0,A3 ;DONE WITH BASE? BEQ.S @2 ;EXIT IF YES MOVE.L #MMUSADRB,A0 ;ELSE SET STARTING BASE ADDRESS MOVEA.L A3,A1 ; AND ENDING ADDRESS MOVEQ #0,D4 ;SET FINAL VALUE FOR BASE REGS BRA.S ACHK1 ;GO CHECK BASE REGS @2 TST D2 ;check for errors RTS6 ;and exit test ; Handle MMU address error MADRERR OR D1,D2 ;save error bits BRA.S MMUSET ; and continue test .ELSE CLR.L D2 ;for error patterns BRA.S SETMMU .ENDC .PAGE ;---------------------------------------------------------------------------- ; Subroutine to do MMU actual read/write ;---------------------------------------------------------------------------- CHKRW MOVE D0,(A0) ;do write MOVE (A0),D1 ;read back EOR D0,D1 ;compare ANDI #$0FFF,D1 ;mask don't cares BNE.S RWERR ;skip if error RTS4 ;else return ; Error collection RWERR OR D1,D2 ;save error bits RTS4 ;and return .PAGE ;-------------------------------------------------------------------------- ; Now do setup of MMU supervisor registers for RAM and I/O space access. ; Also do read check after write and abort if error. ;-------------------------------------------------------------------------- ; Do origin registers first SETMMU MOVE.L #MMUSADRB,A0 ;GET MMU PTR MOVEQ #0,D0 ;clear for use MOVEQ #0,D1 MOVE D2,D4 ;SAVE PREVIOUS RESULTS IF ANY MOVEQ #0,D2 MOVEQ #0,D6 MOVE.L #ADR128K,A2 ;ADDRESS INCREMENT MOVE.L #PAG128K,A3 ;SET UP BASE ADDRESS INCREMENT MOVEQ #16,D6 ;LOOP COUNT LOADORG BSRS4 CHKRW ;DO WRITE/READ CHECK ADD.L A3,D0 ;COMPUTE NEXT MEMORY BASE ADDRESS ADDA.L A2,A0 ;BUMP MMU ORG PTR SUBQ #1,D6 BNE.S LOADORG ;LOOP UNTIL DONE ; Set base for I/O and special I/O space MOVEA.L #MMU126B,A0 ;PT TO ORG REG 126 MOVEQ #0,D0 ;set data value BSRS4 CHKRW ADDA.L A2,A0 ;BUMP PTR TO REG 127 BSRS4 CHKRW ; Now do limit registers MOVEA.L #MMUSADRL,A0 ;GET MMU LIMIT REG PTR MOVE #MEMLMT,D0 ;LIMIT FOR 128K MEMORY SEGMENTS MOVEQ #0,D1 ;use as working reg MOVEQ #16,D6 ;LOOP COUNT LOADLMT BSRS4 CHKRW ADDA.L A2,A0 ;BUMP MMU PTR SUBQ #1,D6 BNE.S LOADLMT ;LOOP UNITL DONE ; Now do MMU limit reg setup for I/O and Special I/O access MOVEA.L #MMU126L,A0 ;PT TO LMT REG 126 MOVE #IOLMT,D0 ;SET FOR I/O SPACE, FULL ACCESS BSRS4 CHKRW ADDA.L A2,A0 ;BUMP PTR TO REG 127 MOVE #SPLMT,D0 ;SET FOR SPECIAL I/O, FULL ACCESS BSRS4 CHKRW .IF DIAGS = 1 ; Check if errors detected TST D2 ;CHECK ERROR MASK BNE MMUERR ;ABORT IF ERROR MOVE D4,D2 ;ELSE RESTORE PREVIOUS RESULTS .ENDC .PAGE ;-------------------------------------------------------------------------- ; Complete testing of MMU by checking other context regs. ; Uses reg D6 for context indicator. ;-------------------------------------------------------------------------- .IF DIAGS = 1 MMUTST2 MOVEQ #0,D6 ;FOR CONTEXT INDICATOR BSR4 MMUINIT ;REINITIALIZE FOR TESTING TST.B SEG1ON ;SET FOR CONTEXT 1 MOVEQ #1,D6 ;SET CONTEXT INDICATOR BSR4 CONCHK ;CHECK IF MMU CONTEXT CHANGED BEQ MMUERR2 ;EXIT IF NO - SEG BIT ERROR BSR6 MMURW ;ELSE GO DO R/W TEST BNE MMUERR2 ;exit if error TST.B SEG2ON ;SET FOR CONTEXT 3 MOVEQ #3,D6 BSR4 CONCHK ;CHECK IF MMU CONTEXT CHANGED BEQ.S MMUERR2 ;EXIT IF NO - SEG BIT ERROR BSR6 MMURW ;ELSE GO TEST BNE.S MMUERR2 ;exit if error TST.B SEG1OFF ;SET FOR CONTEXT 2 MOVEQ #2,D6 BSRS4 CONCHK ;CHECK IF MMU CONTEXT CHANGED BEQ.S MMUERR3 ;EXIT IF NO - SEG BIT ERROR BSRS6 MMURW ;ELSE GO TEST BNE.S MMUERR3 ;exit if error TST.B SEG2OFF ;RESET FOR CONTEXT 0 REGS ; Now do MMU addressing check of remaining context regs BSR4 MMUINIT ;REINITIALIZE TST.B SEG1ON ;SET FOR CONTEXT 1 MOVEQ #1,D6 BSR6 MMUACHK ;TEST CONTEXT 1 BNE.S MMUERR2 ;exit if error TST.B SEG2ON ;TEST CONTEXT 3 MOVEQ #3,D6 BSR6 MMUACHK BNE.S MMUERR2 ;exit if error TST.B SEG1OFF ;TEST CONTEXT 2 MOVEQ #2,D6 BSR6 MMUACHK BNE.S MMUERR3 ;exit if error TST.B SEG2OFF ;RESET TO CONTEXT 0 BRA.S MMULPCHK ;go check for loop mode MMUERR2 TST.B SEG1OFF ;ENSURE RESET FOR CONTEXT 0 MMUERR3 TST.B SEG2OFF ROR #4,D6 ;get context indicator OR D6,D2 ;save with error bits (if any) BSET #MMU,D7 ;set error indicator MMULPCHK TST.L D7 ;in loop mode? BMI.S MMUTST ;restart full MMU test if yes BRA.S START ;else continue to next test .PAGE ;------------------------------------------------------------------------- ; Subroutine to verify context change made - does comparison to ensure ; destruction of context 0 mapping avoided. Zero bit set if error. ;------------------------------------------------------------------------- CONCHK MOVE MMU126L,D4 ;check limit reg for I/O space ANDI #$0FFF,D4 ;mask don't care CMPI #IOLMT,D4 ;still in same context? BNE.S CONOK ;exit if not MOVE MMU127L,D4 ;else also check reg for ROM space ANDI #$0FFF,D4 ;mask don't care CMPI #SPLMT,D4 ;also set up? BNE.S CONOK ;exit if not MOVE MMU0L,D4 ;else do final check on reg for memory access ANDI #$0FFF,D4 CMPI #MEMLMT,D4 ;return with match results to caller CONOK RTS4 .ENDC .IF ROM4K = 0 .IF DIAGS = 0 ;------------------------------------------------------------------------- ; Initialize other MMU regs for invalid access ;------------------------------------------------------------------------- TST.B SEG1ON ;SET FOR CONTEXT 1 MOVEQ #1,D6 ;SET CONTEXT INDICATOR BSR6 INITMMU TST.B SEG2ON ;SET FOR CONTEXT 3 MOVEQ #3,D6 BSR6 INITMMU TST.B SEG1OFF ;SET FOR CONTEXT 2 MOVEQ #2,D6 BSR6 INITMMU TST.B SEG2OFF ;RESET FOR CONTEXT 0 REGS CLR.L D6 TST D2 ;CHECK IF ERRORS BEQ.S START ;exit if ok ROR.L #8,D6 ;GET CONTEXT INDICATOR OR.L D6,D2 ;SAVE WITH ERROR BITS BSET #MMU,D7 ;SET ERROR CODE FOR LATER MESSAGE BEQ.S START ;AND CONTINUE .PAGE ;------------------------------------------------------------------------- ; Routine to init MMU regs ;------------------------------------------------------------------------- INITMMU MOVE.L #MMUSADRL,A0 ;MMU limit start addr MOVE.L #MMUEADRL,A1 ;MMU limit end addr MOVE.L #ADR128K,A2 ;increment value MOVE.L #MMUEADRB,A3 ;MMU base end addr MOVE #INVPAG,D0 ;set pattern for limit regs RWLOOP BSR4 CHKRW ;go initialize and check CMPA.L A0,A1 ;done? BEQ.S CHKBASE ;if yes go check for base reg testing ADDA.L A2,A0 ;else bump addr BRA.S RWLOOP CHKBASE CMPA.L A0,A3 ;done with base? BEQ.S @2 ;exit if yes MOVE.L #MMUSADRB,A0 ;else set starting base address MOVEA.L A3,A1 ; and ending address CLR.L D0 ;set base value BRA.S RWLOOP ;go do base regs @2 RTS6 ;AND EXIT TEST .ENDC ;{DIAGS} .ENDC ;{ROM4K} .PAGE ;------------------------------------------------------------------------- ; Reset SETUP bit to enable system access and continue with testing ;------------------------------------------------------------------------- START CLR.B SETUP ;TURN OFF SETUP TO ENTER MAP LAND ... ;---------------------------------------------------------------------------- ; Now do memory sizing - assumes 128K minimum memory increment ; Register usage: ; A0 = minimum physical address D0 = scratch use ; A1 = maximum physical address/scratch D1 = incr for search address ; A2 = unused D2 = unused ; A3 = next base memory addr to test D3 = inverted sizing test pattern ; A4 = return address D4 = sizing test pattern ; A5 = unused D5 = retry count ; A6 = saved error mask D6 = error mask ;---------------------------------------------------------------------------- MEMSIZ CLR.L D0 ;setup regs for loop MOVE.L D0,A0 MOVE.L D0,A1 MOVE.L D0,A3 MOVE.L D0,A6 MOVEQ #2,D1 ;size at 128K boundaries RM000 SWAP D1 ; RM000 MOVE.L #PATRN,D4 ;set test patterns for sizing CHG002 MOVE D4,D3 ;use only lower word NOT D3 ;and its inverse CHKLO BSR4 CHKMEM ;first search for low memory address TST D6 ;memory found? BEQ.S SAVELO ;yes - go save address NOT D6 ;else invert to check if all bits in error TST D6 ;if not, assume memory error BNE.S @3 ; and go save address @2 ADDA.L D1,A3 ;else bump search address MOVEA.L A3,A1 ;set as next working address CMPA.L #MAXADR,A1 ;at max address? BNE.S CHKLO ;continue search if not ; No memory found - toggle LED and check for I/O board; if no I/O (bus error) CHG004 ; diagnostics are restarted CHG004 MOVE.B #DEFVID2,VIDLTCH ;set LED on and default video latch setting (PAGE 2F) CHG004 MOVE #TNTHSEC,D0 ;delay for .1 sec CHG004 @9 SUBQ #1,D0 ; CHG004 BNE.S @9 ; CHG004 MOVE.B #DEFVID,VIDLTCH ;reset LED and leave video latch setting CHG004 MOVE.L #VIA1BASE,A0 ;check for I/O board CHG004 TST.B (A0) ;bus error will occur if not installed CHG004 ; Go into read/write loop if no memory found but I/O installed BSR2 LOTONE ;beep speaker for error BSR4 CONSET ;set contrast MOVE.L #ONEMEG-2,A0 ;set default memory address (to span both boards) CHG002 @4 MOVE.L D4,(A0) ;go into read/write loop CHG002 MOVE.L (A0),D3 ; CHG002 BRA.S @4 ; Low memory address found - save and continue @3 NOT D6 ;reinvert and MOVE D6,A6 ; save results SAVELO MOVEA.L A3,A0 ;save low address CMPA.L #ONEMEG,A0 ;check for min low address BLE.S @1 ;skip if OK MOVEA.L #ONEMEG,A0 ;else set at min value (one 512K board in slot 1) .PAGE ;----------------------------------------------------------------------------- ; Now check for high memory address; search to max address of 2 meg ;----------------------------------------------------------------------------- @1 MOVEA.L A3,A2 ;save low address as first high address TSTHI ADDA.L D1,A3 ;compute next 128K increment MOVEA.L A3,A1 ;use as new search value CMPA.L #MAXADR,A1 ;done? BEQ.S SIZXIT ; Following patch added to detect for wraparound problem of old memory boards MOVE.L A0,D0 ;check low address RM015 BNE.S CHKHI ;old memory boards start at address 0 RM015 CMP (A1),D3 ;are we wrapped back to already tested location? BEQ.S WRAPXIT ;skip if yes (i.e., old memory board) RM015 ; Else continue with check for high address CHKHI BSRS4 CHKMEM ;go do memory search TST D6 ;any errors? BEQ.S SAVEHI ;skip if not to save address NOT D6 ;else invert to see if all bits in error TST D6 BEQ.S TSTHI ;skip if yes to ignore address MOVE A6,D0 ;else get previous results NOT D6 ;reinvert and OR D6,D0 ; add new results MOVE D0,A6 ;save for later SAVEHI MOVEA.L A3,A2 ;save as new potential high address CLR (A3) ;clear test pattern RM015 BRA.S TSTHI ; and continue loop WRAPXIT CLR (A1) ;clear test pattern RM015 SIZXIT ADDA.L D1,A2 ;high address = last valid addr + 128K MOVEA.L A2,A1 ;save for later use BRA.S RSTMMU ;continue on .PAGE ;---------------------------------------------------------------------------- ; Subroutine to do memory check for sizing. If error, tries successive ; memory locations up to retry count (D5). Returns with error mask in D6. ;---------------------------------------------------------------------------- CHKMEM MOVEQ #RETRYCNT,D5 ; set retry count in case of errors CLR D6 ; clear for error mask @1 MOVE D4,(A1) ; check if true data stores MOVE D3,2(A1) ; and try complement to next location CMP (A1),D4 BEQ.S @2 ; continue if yes MOVE (A1),D0 ; else get error bits EOR D4,D0 OR D0,D6 ; and save them @2 CMP 2(A1),D3 ; check second location BEQ.S @3 ; exit if data correct MOVE 2(A1),D0 ; else read again EOR D3,D0 ; get error bits OR D0,D6 ; save in error mask @3 MOVE D4,2(A1) ; now try in reverse order MOVE D3,(A1) CMP 2(A1),D4 ; check second location BEQ.S @4 ; skip if OK MOVE 2(A1),D0 ; else save error bits EOR D4,D0 OR D0,D6 @4 CMP (A1),D3 ; and check first BEQ.S @5 ; continue if yes MOVE (A1),D0 ; else get error bits EOR D3,D0 OR D0,D6 ; and save them @5 TST D6 ; any errors? BEQ.S @6 ; skip if no TST.L (A1)+ ; else bump search address to next pair SUBQ #1,D5 ; decr retry count BNE.S @1 ; continue until count exhausted @6 RTS4 ; return with results in D6 .PAGE ;------------------------------------------------------------------------- ; Subroutine to set parms for lo tone from speaker ;------------------------------------------------------------------------- LOTONE MOVEQ #$60,D0 ;set frequency MOVE #250,D1 ;and duration MOVEQ #4,D2 ;and volume (medium) BSR4 TONE2 ;go do tone RTS2 .PAGE ;--------------------------------------------------------------------------- ; Now reset MMU regs according to low and high physical address ; Remainder of MMU regs in context 0 are set to invalid page ; ; Register Usage: ; A0 - low physical address D0 - scratch/value stored in base reg ; A1 - high physical address D1 - value stored in limit reg ; A2 - MMU base reg ptr D2 - unused ; A3 - MMU limit reg ptr D3 - holds base reg page incr value ; A4 - used for return address D4 - used for count of regs to set ; A5 - MMU address increment D5 - low physical page ; A6 - not used D6 - high physical page ;--------------------------------------------------------------------------- ; First translate memory addresses to 512 byte page values for MMU use RSTMMU MOVE.L A0,D5 ;GET MEMORY ADDRESS VALUES MOVE.L A1,D6 MOVEQ #9,D0 ;SET SHIFT COUNT LSR.L D0,D5 ;TRANSLATE TO PAGE VALUES LSR.L D0,D6 ; Now initialize for MMU write operations MOVEA.L #MMUSADRB,A2 ;SET MMU BASE REG PTR MOVEA.L #MMUSADRL,A3 ;SET LIMIT REG PTR MOVE.L #ADR128K,A5 ;SET INCREMENT VALUE FOR MMU ADDRESSES MOVE.L #PAG128K,D3 ;SET INCR VALUE FOR BASE REG CONTENTS MOVEQ #126,D4 ;SET REG COUNT - NO RESETTING OF REGS 126,127 MOVE D5,D0 ;SET BASE VALUE MOVE #MEMLMT,D1 ;SET LIMIT VALUE ; Remap MMU regs for existing memory REMAP BSRS4 WRTMMU ;REWRITE SET OF MMU REGS SUBQ #1,D4 ;DECR REG COUNT ADD.L D3,D0 ;BUMP PAGE ADDRESS CMP.L D0,D6 ;CHECK IF AT UPPER LIMIT BNE.S REMAP ;LOOP IF NO ; Now map remainder of regs for invalid access CLR D0 ;SET NEW BASE REG VALUE MOVE #INVPAG,D1 ; AND LIMIT REG VALUE MAPINV BSRS4 WRTMMU ;GO DO REWRITE SUBQ.L #1,D4 ;DECR COUNT BNE.S MAPINV ;LOOP UNTIL DONE ; Finally reset video page to last page of memory LSR.L #6,D6 ;compute address for video page SUBQ #1,D6 ;decr to last page MOVE.B D6,VIDLTCH ;and set video latch BRA.S MEMTST1 ;SKIP TO NEXT TEST .IF EXTERNAL = 1 .LIST .PAGE .ENDC ;------------------------------------------------------------------------- ; Subroutine to set MMU regs (context 0) - can also be called by external ; routines that provide the following register inputs: ; ; A2 = base reg address D0 = value for base reg ; A3 = limit reg address D1 = value for limit reg ; A5 = reg address increment ;------------------------------------------------------------------------- WRTMMU TST.B SETUPON ;TURN SETUP ON TO ENABLE MMU ACCESS MOVE D0,(A2) ;SET BASE REG MOVE D1,(A3) ;SET LIMIT REG ADDA.L A5,A2 ;BUMP MMU PTRS ADDA.L A5,A3 CLR.B SETUP ;BACK TO MAP LAND RTS4 ;AND BACK TO CALLER .IF ROM16K = 1 ;------------------------------------------------------------------------- ; Subroutine to read MMU regs - for call by external routines. ; Inputs: ; D2 = context to read (0-3) ; A2 = base reg address ; A3 = limit reg address ; A4 = return address ; A5 = reg address increment ; Outputs: ; D0 = value of base reg ; D1 = value of limit reg ; A2,A3 incremented by value in A5 ; Side Effects: ; D3 trashed ;------------------------------------------------------------------------- READMMU MOVE #$0FFF,D3 ;set mask for result TST.B SETUPON ;turn setup on to enable MMU access TST D2 ;check context BEQ.S @9 ;skip if context 0 CMP.B #1,D2 ;context 1? BEQ.S @2 CMP.B #2,D2 ;context 2? BEQ.S @1 TST.B SEG2ON ;must be context 3 BRA.S @2 ;set both seg bits @1 TST.B SEG2ON ;set for context 2 BRA.S @9 @2 TST.B SEG1ON ;set for context 1 and 3 ; read the regs @9 MOVE (A2),D0 ;read base reg AND D3,D0 ;clear junk MOVE (A3),D1 ;read limit reg AND D3,D1 ;clear junk ADDA.L A5,A2 ;incr ptrs ADDA.L A5,A3 TST.B SEG1OFF ;restore to context 0 TST.B SEG2OFF CLR.B SETUP ;back to map land RTS4 ;and back to caller .ENDC .IF EXTERNAL = 1 .NOLIST .ENDC .PAGE ;-------------------------------------------------------------------------- ; Begin memory testing by checking first 800 hex locations (2K). ; If error here, abort other testing and go into loop since can't relay ; meaningful results. ;-------------------------------------------------------------------------- MEMTST1 MOVEA.L A0,A2 ;save memory lo, hi addresses MOVEA.L A1,A3 .IF DIAGS = 1 SUBA.L A0,A0 ;set test addresses MOVEA #LOMEM,A1 ;upper address RM000 BSR4 RAMTEST ;go do memory test BEQ.S INITMEM ;skip if OK ; Error in low memory - reset video latch, beep speaker and go into R/W loop MOVE.L A2,D0 ;get low physical address LSR.L #8,D0 ;convert to page value LSR.L #7,D0 MOVE.B D0,VIDLTCH ;set video latch to bad area BSR4 CONSET ;ensure contrast on BSR2 LOTONE ;beep speaker twice for low memory error MOVE #TNTHSEC,D0 ;delay for about 1/10 sec RM000 TONEDLY SUBQ #1,D0 BNE.S TONEDLY BSR2 LOTONE ;do second beep SUBA.L A0,A0 ;loop at first address MOVE #PATRN2,D0 ;set pattern for use @2 MOVE D0,(A0) MOVE (A0),D1 BRA.S @2 ;loop with random display on screen .ELSE MOVEQ #0,D3 ;set results reg MOVEQ #-1,D0 ;set for memory "clear" pattern CLRMEM MOVE.L D0,(A0)+ ;do "clear" CMPA.L A0,A1 ;done? BNE.S CLRMEM ;loop until yes .ENDC ;{DIAGS} ; Now attempt to initialize status areas and save results INITMEM MOVEA #STATUS,A0 ;get ptr to start of status area RM000 MOVEQ #127,D0 ;set count @2 CLR.L (A0)+ ;clear it DBF D0,@2 ;until done MOVE D3,MEMRSLT ;save test results MOVE A6,SIZRSLT ;save sizing results MOVE.L A2,MINMEM ;save min memory address MOVE.L A3,MAXMEM ;save max memory address SUBA.L A2,A3 ;compute total memory MOVE.L A3,TOTLMEM ;and save also MOVE.L #HEX32K,A0 ;compute base address for screen SUBA.L A0,A3 MOVE.L A3,SCRNBASE ;and save MOVE D2,MMURSLT ;and save MMU results also MOVE.L #KBDQ,KBDQPTR ;init COPS buffer pointer for later use .PAGE ;------------------------------------------------------------------------ ; Initialize exception and trap vectors to catch unexpected errors ;------------------------------------------------------------------------ INITVCT BSR.S SETVCTRS ;init vectors BRA SCCSET ;continue testing CHG027 ; Subroutine to set up default vectors SETVCTRS LEA MISC,A0 SUBA.L A1,A1 MOVEQ #64,D0 @1 MOVE.L A0,(A1)+ ; fill with unknown ones SUBQ #1,D0 BGT @1 BSR.S SETBUSVCT ; then, with special ones RM000 LEA AERR,A0 MOVE.L A0,ADRVCTR LEA IERR,A0 MOVE.L A0,ILLVCTR LEA NMI,A0 MOVE.L A0,NMIVCT LEA TRPERR,A0 ; same routine for line 1010 and 1111 MOVE.L A0,L10VCTR MOVE.L A0,L11VCTR .IF USERINT = 0 MOVEQ #FIRSTROW,D5 ;set default row and MOVEQ #FIRSTCOL,D6 ; column cursor ptrs .ENDC RTS ;----------------------------------------------------------- ; Subroutine to setup bus error vector RM000 ;----------------------------------------------------------- SETBUSVCT LEA BERR,A3 ;setup default vector RM000 MOVE.L A3,BUSVCTR ; RM000 RTS ; RM000 ;----------------------------------------------------------- ; Exception Handler routines ;----------------------------------------------------------- MISC MOVE.L D7,D7SAV ;save incoming value MOVEQ #0,D7 BSET #MISEXCP,D7 ;set error indicator BRA.S EXCP1 IERR MOVE.L D7,D7SAV ;save incoming value MOVEQ #0,D7 BSET #ILLEXCP,D7 ;set error indicator BRA.S EXCP1 NMI MOVE.L D7,D7SAV ;save incoming value MOVEQ #0,D7 BSR TSTSTAT ;check status reg for parity error CHG015 BNE.S NOTPE ;skip if not BSET #MPAR,D7 ;set error indicator BSR GETPADDR ;get and save error address CHG015 TST.B PAROFF ;toggle to clear error bit BTST #5,D1 ;video error? CHG015 BEQ.S @1 ;skip if not CHG015 ANDI.L #VMSK,D1 ;mask if yes CHG015 @1 MOVE.L D1,PEADDR ;save converted error address CHG015 BRA.S EXCP1 ;go to exit NOTPE BSET #CPUINTR,D7 ;else set NMI code BRA.S EXCP1 ; and exit TRPERR MOVE.L D7,D7SAV ;save incoming value MOVEQ #0,D7 BSET #TRPEXCP,D7 ;set error indicator BRA.S EXCP1 BERR MOVE.L D7,D7SAV ;save incoming value MOVEQ #0,D7 BSET #BUSEXCP,D7 ;set error indicator BRA.S EXCP0 AERR MOVE.L D7,D7SAV ;save incoming value MOVEQ #0,D7 BSET #ADREXCP,D7 ;set error indicator EXCP0 ; GROUP 0 EXCEPTIONS HERE MOVE (SP)+,EXCFC ; SAVE THE EXTRA DATA MOVE.L (SP)+,EXCADR MOVE (SP)+,EXCIR EXCP1 ; GROUP 1 EXCEPTIONS HERE MOVE (SP)+,EXCSR ; SAVE COMMON INFO MOVE.L (SP)+,EXCPC MOVE D0,EXCTYPE ; save error type BRA TSTCHK ; and go display error .PAGE ;------------------------------------------------------------------------- ; Initialize SCC chip for Applebus use. CHG027 ; Bus error vector setup in case of problems. ;------------------------------------------------------------------------- SCCSET LEA NOIO,A3 ;set bus error vector in case no IO board CHG027 MOVE.L A3,BUSVCTR ; CHG027 BSR RSTSCC ;go do setup CHG027 ;------------------------------------------------------------------------- ; Now test VIA for parallel port and contrast latch. ; A read/write test on the timer 1 latches is done, then contrast ; is set if OK. ;------------------------------------------------------------------------- VIA2TST .IF DIAGS = 1 VIA2CHK .IF ROM16K = 1 LEA VIA2VCT,A3 ;OK - set up special bus vector MOVE.L A3,BUSVCTR MOVE.L #,A0 ;set base address of timer low latch MOVEQ #8,D0 ;set offset to high latch BSRS6 VIATST ;and go do test BEQ.S @2 ;if OK, continue BSET #VIA2,D7 ;else set error bit TST.L D7 ;check if in loop mode BMI.S VIA2CHK ;restart if yes BRA.S @3 ;else skip contrast setting .ENDC @2 TST.L D7 ;in loop mode? BMI.S VIA2CHK ;restart if yes BSRS4 CONOFF ;go turn off contrast .ENDC ;{DIAGS} @3 BRA.S SCRNTST ;else skip to next test .IF DIAGS = 1 ;------------------------------------------------------------------------ ; Bus error handler for VIA #2 use ;------------------------------------------------------------------------ VIA2VCT MOVEQ #EVIA2,D0 ;SET ERROR CODE BSET #VIA2,D7 ;set indicator BRA IOVCT ;AND GO HANDLE I/O EXCEPTION .ENDC ;{DIAGS} .IF ROM16K = 1 .PAGE ;------------------------------------------------------------------------- ; Subroutine to do VIA testing ; A0 = address of first timer latch ; D0 = offset to other latch ;------------------------------------------------------------------------- VIATST MOVE.L A0,A1 ;set up address for second latch ADDA.L D0,A1 MOVEQ #0,D0 ;for error use CLR.B D2 ;clear old data value MOVE.B #0,(A0) ;and the timer latches MOVE.B #0,(A1) MOVE #$FF,D3 ;set up start value BSRS4 VIARW ;go do read/write test RTS6 ;and return ; Subroutine to do read/write test - loops thru all 256 values VIARW CMP.B (A0),D2 ;check for old values first BNE.S VIAFAIL CMP.B (A1),D2 BNE.S VIAFAIL MOVE.B D3,(A0) ;set new value in low timer latch CMP.B (A1),D2 ;ensure high latch not affected BNE.S VIAFAIL CMP.B (A0),D3 ;verify new low latch setting BNE.S VIAFAIL MOVE.B D3,(A1) ;set new value in high timer latch CMP.B (A0),D3 ;ensure low latch not affected BNE.S VIAFAIL CMP.B (A1),D3 ;verify new high latch setting BNE.S VIAFAIL MOVE.B D3,D2 ;the new value becomes the old DBF D3,VIARW ;loop thru all 256 values BRA.S VIARWEND VIAFAIL ADDQ #1,D0 ;set for error VIARWEND TST D0 ;set zero bit indicator RTS4 .ENDC .PAGE ;-------------------------------------------------------------------------- ; Subroutine to set contrast latch - sets for default, off or value in D0 ;-------------------------------------------------------------------------- CONSET MOVE.B #$80,D0 ;set mid range value default BRA.S CONSET2 CONOFF MOVEQ #-1,D0 ;set for contrast off CONSET2 ;for external entry MOVE.L #VIA2BASE,A0 ;GET 6522 BASE ADDR MOVE.B #$84,DDRB2(A0) ;ENSURE NO STRAY DATA TO CONTRAST MOVE.B #4,ORB2(A0) ; LATCH BY DISABLING DRIVERS MOVE.B #$FF,DDRA2(A0) ;NOW SET PORT A AS OUTPUTS MOVE.B D0,ORA2(A0) ;set contrast value BSET #7,ORB2(A0) ;AND STROBE IT RTS4 ;RETURN TO CALLER .PAGE ;------------------------------------------------------------------------- ; Test memory to be used for screen. The screen can then be ; used for test icon display. Default choice is last 32K of memory. ; If this is invalid, do backwards scan through memory until a valid ; area is found. ; Assumes: location SCRNBASE = base address of default screen (set by ; sizing routine) ;------------------------------------------------------------------------- SCRNTST .IF DIAGS = 1 MOVE.L SCRNBASE,A0 ;get base address of screen MOVE.L TOTLMEM,A1 ;set end address BSR4 RAMTEST ;and go do test BEQ.S INVTST ;continue if no error BSET #MEM,D7 ;else set memory read/write error ; save error results and then start search for good video page BSR TSTINIT ;initialize for further testing BSR.S SCRNSAV ;save results MOVE.L SCRNBASE,A1 ;set new search end address MOVE.L A1,A0 MOVE.L #HEX32K,A2 ;screen size is 32K SUBA.L A2,A0 ;set new start addr (end-32K) @1 MOVEM.L A0-A2,-(SP) ;save search addresses BSR4 RAMTEST ;go test MOVEM.L (SP)+,A0-A2 ;restore addresses (no effect on CCR) BEQ.S SCRNOK ;skip if OK (non-zero CCR if error) MOVE.L A0,D4 ;else go save results BSR.S SCRNSAV MOVE.L A0,A1 ;set next end SUBA.L A2,A0 ; and start addresses MOVE.L A0,D0 ;continue thru all of memory if necessary BGT.S @1 SCRNERR BRA.S INVTST ;continue testing, leave screen at default SCRNOK MOVE.L A0,SCRNBASE ;save new screen base BSR.S SETVLTCH ;and go set video latch BRA.S INVTST ;and exit to next test ;------------------------------------------------------------------------- ; Subroutine to save error results from screen test routine ; Inputs: ; A3 = ptr to base of save result area ; D4 = base address of test area ; Outputs: ; None ; Side Effects: ; D1/D3-D4 trashed ;------------------------------------------------------------------------- SCRNSAV MOVEQ #17,D1 ;divide base address by 128K LSR.L D1,D4 ADD D4,D4 ;double for word index to save area MOVE.L D3,D1 ;combine error results SWAP D3 OR D1,D3 OR D3,0(A3,D4) ;save and exit RTS ;------------------------------------------------------------------------- ; Subroutine to set the video latch ; Inputs: ; Location SCRNBASE = logical base address for screen ; Outputs: ; None ; Side Effects: ; D0-D1 trashed ;------------------------------------------------------------------------- SETVLTCH MOVE.L SCRNBASE,D2 ;get logical screen base address MOVE.L TOTLMEM,D1 ;get physical amount of memory SUB.L D2,D1 ;compute screen base offset MOVE.L MAXMEM,D0 ;get max physical address SUB.L D1,D0 ;compute physical screen base address LSR.L #8,D0 ;convert to page value LSR.L #7,D0 MOVE.B D0,VIDLTCH ;set latch RTS ;and exit .PAGE ;------------------------------------------------------------------------- ; Now check state of INVID bit to see if inverse video is installed. ; If yes, rewrite last 4 words of screen page to avoid retrace line. ;------------------------------------------------------------------------- INVTST .IF INVERTCK = 1 ; CHG013 MOVEA.L #STATREG,A5 ;set ptr to status register BTST #INVIDBIT,(A5) ;check if inverse video installed BNE.S VIA1TST ;go on to next test if not ; Inverse video requires zeroing of last bit in video page (32K) MOVE.L SCRNBASE,A0 ;get base address of screen ADD.L #HEX32K,A0 ;set ptr to end of screen CLR.L -(A0) ;rewrite last 4 words CLR.L -(A0) .ENDC ;{INVERTCK} CHG013 .ENDC ;{DIAGS} ;------------------------------------------------------------------------- ; Continue testing by now doing COPS VIA test ;------------------------------------------------------------------------- VIA1TST .IF USERINT = 1 ; Draw desktop on screen for test icon display BSR DRAWDESK ;draw the desk BSR.S DSPCPURM ;and CPU ROM id CHG001 .ENDC BSR4 CONSET ;set default contrast .IF ROM16K = 1 VIA1CHK LEA VIA1VCT,A3 ;first set up bus error vector MOVE.L A3,BUSVCTR MOVE.L #,A0 ;set base address of timer low latch MOVEQ #2,D0 ;set offset to high latch BSR6 VIATST ;go test BEQ.S @2 ;skip if OK BSET #VIA1,D7 ;else set error bit TST.L D7 ;loop? BMI.S VIA1CHK ;yes - test again BRA TSTCHK ;else abort further testing @2 TST.L D7 ;check for loop mode BMI.S VIA1CHK BRA.S COPSENBL ;else go test COPS ;------------------------------------------------------------------------ ; Subroutine to display CPU ROM id ;------------------------------------------------------------------------ DSPCPURM MOVE.B REV,D0 ;read ROM rev CHG001 MOVEQ #ROMIDROW,D5 ;setup cursor ptrs CHG001 MOVEQ #ROMIDCOL,D6 ; CHG001 BSR DSPVAL ;do display CHG001 RTS ; CHG001 .ENDC .PAGE ;------------------------------------------------------------------------- ; Try turning COPS on so that keyboard commands can be received ;------------------------------------------------------------------------- COPSENBL LEA COPSVCT,A3 ;set up bus error vector first MOVE.L A3,BUSVCTR BSR.S CPSINIT ;enable COPS BCS.S COPSBAD ;skip if error TST.L D7 ;looping desired? BMI.S COPSENBL ;go repeat test MOVE.L D7,D0 ;get error indicator ANDI.L #CPIOMSK,D0 ;mask off don't care bits BEQ RSTSCAN ;continue if OK to do reset scan BRA TSTCHK ;else go report error COPSBAD BSET #IOCOPS,D7 ;else set COPS error TST.L D7 ;looping desired? BMI.S COPSENBL ;go repeat test BRA TSTCHK ;else abort further testing ;----------------------------------------------------------------------------- ; Bus error handler for COPS testing with entry point for other I/O tests ;----------------------------------------------------------------------------- COPSVCT MOVEQ #EIOCOP,D0 ;SET ERROR CODE IOVCT BSET #IOEXCP,D7 ;SET I/O EXCEPTION ERROR BRA EXCP0 ;AND GO HANDLE EXCEPTION ;----------------------------------------------------------------------------- ; Subroutine to initiialize COPS interface for use ;----------------------------------------------------------------------------- CPSINIT MOVEA.L #VIA1BASE,A0 ;GET VIA BASE ADDRESS MOVE.B #$01,ACR1(A0) ;SET PORT A LATCH ENABLE OR.B #$09,PCR1(A0) ;SET HANDSHAKE ENABLE MOVE.B #$7F,IER1(A0) ;CLEAR ALL INTRPT ENABLES MOVE.B #$7F,IFR1(A0) ;AND CLEAR FLAGS ; Now turn COPS on, disabling mouse and NMI key TURNON CLR D0 ;SET FOR PORT ON CMD BSR.S COPSCMD ;SEND TO COPS BCS.S @1 ;EXIT IF TIMEOUT ERROR MOVEQ #$70,D0 ;DISABLE MOUSE BSR.S COPSCMD BCS.S @1 .IF DEBUG = 0 MOVEQ #$50,D0 ;disable NMI key BSR.S COPSCMD BCS.S @1 MOVEQ #$60,D0 BSR.S COPSCMD .ENDC @1 RTS ;AND EXIT .PAGE ;----------------------------------------------------------------------------- ; Subroutine to send cmd to COPS ; Assumes registers: ; D0 = cmd value ; If COPS does not respond, timeout error indicated by setting carry bit. ;----------------------------------------------------------------------------- COPSCMD MOVEM.L D0-D4/A0-A2,-(SP) ;save regs DISABLE ;disable all interrupts MOVEA.L #VIA1BASE,A0 ;set COPS VIA interface ptr MOVEA.L A0,A1 ;save for use as port B output reg address MOVEA.L A0,A2 ADDA #DDRA1,A2 ;compute address for port A data direction reg MOVEQ #$40,D2 ;set up constants for later use MOVEQ #-1,D3 MOVEQ #6,D4 MOVE.B D0,PORTA1(A0) ;set cmd in data reg (no handshake) ;--------------------------------------------------------------------------- ; First find a ready state (CRDY low) ; Each of the following loops take about 32 machine cycles = 6.4 us plus ; a variable amount of time for sync with 6522 (max = 2us) ;--------------------------------------------------------------------------- MOVE #$061A,D1 ;set timeout for about 10 ms @3 SUBQ #1,D1 BEQ.S @1 ;exit if timeout BTST D4,(A1) ;else wait for "ready" (bit 6 = CRDY) BNE.S @3 ; Now find the next ready state to insure enough time available for data MULU #1,D0 ;kill some time (about 15.2 us) to get ; out of previous CRDY MOVE #$061A,D1 ;reinit timeout count @4 SUBQ #1,D1 BEQ.S @1 ;exit if timeout BTST D4,(A1) ;wait for another "ready" BNE.S @4 MOVE.B D3,(A2) ; ok, jam out the data ; Now wait for CRDY high and then hold data for COPS to read MOVE #$061A,D1 ;set timeout for about 10 ms @5 SUBQ #1,D1 BEQ.S @1 ;exit if timeout BTST D4,(A1) ;wait for "not-ready" BEQ.S @5 MOVEQ #$A,D0 ; force about a 40 ms @6 SUBQ #1,D0 ; delay for COPS hold time BGT.S @6 CLR.B (A2) ; reset direction reg now MOVE.B #$82,IER1(A0) ; and, enable CA1 BRA.S @2 ; go to normal exit ; Timeout occurred - set error indicator @1 ENABLE ;reenable ORI.B #$01,CCR ;set carry bit BRA.S @9 ;skip to exit @2 ENABLE ;restore interrupt levels @9 MOVEM.L (SP)+,D0-D4/A0-A2 ;restore regs RTS ;and return to caller .PAGE ;------------------------------------------------------------------------- ; Scan COPS for proper reset codes. Delay added for normal COPS power-up ; time of about 1.7 seconds. ; ; Send reset signal and then scan keyboard/mouse interface. First "clears" ; COPS of any pending codes, and then issues reset. Works via ; a "state machine" that checks codes received and sets flags as follows: ; ; D1 = 0 - reset signal in place ; = 1 - reset signal removed ; ; D3 = 0 - no keyboard codes received => keyboard disconnected ; = 1 - keyboard disconnect code ($80/$FD) received ; => ignore, may be old keyboard ; = 2 - keyboard disconnect/connect codes ($80/$FD/$80/id) received ; => keyboard connected ; ; D4 = 0 - no mouse codes received => mouse connected ; = 1 - only mouse connect code ($87) received => ignore, may be old sys ; = 2 - mouse connect/disconnect ($87/$07) codes received ; => mouse disconnected ;-------------------------------------------------------------------------- RSTSCAN MOVE.L KBDQPTR,A1 ;setup buffer ptrs MOVEA #QEND,A2 @1 BSR.S GETJMP ;clear COPS queue, saving data BCC.S @1 BSR RSTKBD ;do reset of keyboard/mouse interfaces .IF ROM4K = 0 CLR.L D1 ;init some flags CLR.L D3 CLR.L D4 BSR.S GETJMP ;check for data BCS.S RSTXIT ;exit if none (may be old keyboard) ; State 0 - waiting for reset flag or mouse connect code RST0 CMPI.B #RSTCODE,D0 ;reset flag? BEQ.S RST1 ;skip if yes to state 1 CMPI.B #MSPLG,D0 ;mouse connect code? BEQ.S RST2 ;skip if yes to state 2 CMPI.B #MSUNPLG,D0 ;mouse disconnect code only? BNE.S GET0 MOVEQ #2,D4 ;set flag for disconnect state GET0 BSR.S GETJMP ;go get next code BCS.S RSTXIT ;exit if no more codes BRA.S RST0 ;else continue scan loop ; State 2 - waiting for mouse unplugged code RST2 MOVEQ #1,D4 ;set flag for mouse connect received BSR.S GETJMP ;go get next byte BCS.S RSTXIT ;exit if none or queue full CMPI.B #MSUNPLG,D0 ;mouse disconnect code? BNE.S RST0 ;no - return to state 0 MOVEQ #2,D4 ;yes - set flag BRA.S GET0 ;and return to state 0 ; State 1 - waiting for reset code RST1 BSR.S GETJMP ;go get next byte BCS.S RSTXIT ;exit if no more CMPI.B #KUNPLG,D0 ;keyboard unplugged code? BNE.S @1 ;skip if not MOVEQ #1,D3 ;else set flag BRA.S GET0 ;and return to state 0 @1 CMPI.B #$DF,D0 ;id code? BHI.S @2 ;skip if not MOVE.B D0,KEYID ;else save for later use MOVEQ #2,D3 ;update flag BRA.S GET0 ;and return to state 0 @2 CMPI.B #KCERR,D0 ;Keyboard COPS error? BNE.S @3 ;skip if not BSET #KBDCOPS,D7 ;else set error indicator @3 CMPI.B #ICERR,D0 ;I/O COPS error code? BNE.S @4 ;skip if not BSET #IOCOPS,D7 ;else set error indicator @4 BRA.S GET0 ;continue scan from state 0 ; Insert to save code space GETJMP BSR.S GETDATA ;go get COPS data RTS ;and return to caller ; Reset exit - analyze results RSTXIT TST.B D1 ;reset signal lifted? BNE.S @1 ;skip if yes BSR CLRRST ;else remove reset signal MOVEQ #1,D1 ;set "removed flag" BSR.S GETDATA ;any data? BCC.S RST0 ;go decode if yes @1 .IF FINKBD = 1 TST.B D3 ;any keyboard data detected? BNE.S MSCHK ;skip if yes - assume keybd connected BSET #KBDOUT,D7 ;if none, keyboard is disconnected MSCHK TST.B D4 ;any mouse data? BEQ.S SCANXIT ;skip if none - mouse connected @1 SUBQ #1,D4 ;flag = 1? BEQ.S SCANXIT ;ignore if yes BSET #MOUSOUT,D7 ;else mouse disconnected BRA.S SCANXIT ;and go to exit .ELSE BRA.S SCANXIT .ENDC ;{FINKBD} ; Error exits - set appropriate indicator SCANERR BSET #IOKBD,D7 ;I/O or keyboard failure BRA.S SCANXIT IOCERR BSET #IOCOPS,D7 ;I/O COPS error .ELSE @1 BSR.S GETDATA ;clear COPS queue BCC.S @1 BSR.S CLRRST ;clear reset signal @2 BSR.S GETDATA ;any data? BCC.S @2 ;clear the queue .ENDC ;{ROM4K} SCANXIT MOVE.L A1,KBDQPTR ;save queue ptr for later use .IF ROM4K = 0 MOVE.L D7,D0 ;check error codes ANDI.L #SCANMSK,D0 ; for scan errors TST.L D0 ;any found? BNE TSTCHK ;skip if yes .ENDC BRA.S BEEP ;else continue testing .PAGE ;------------------------------------------------------------------------- ; Subroutine to get COPS data ; Assumes registers: ; D0 - scratch use A0 - VIA address ; D1 - unused A1 - Ptr to data save area ; D2 - scratch use A2 - Ptr to end of data area ; Puts data in save area and also leaves in register D0. ; Carry bit set if timeout error or keyboard queue full. ;------------------------------------------------------------------------- GETDATA CMPA.L A1,A2 ;check if at end of queue BEQ.S @2 ;exit if yes MOVE.L #$1FF,D2 ;else set timeout for about 5 ms MOVEA.L #VIA1BASE,A0 ;set COPS VIA interface ptr @1 MOVE.B IFR1(A0),D0 ;check if data avail BTST #1,D0 BNE.S GETIT ;skip if yes SUBQ #1,D2 BNE.S @1 ;else continue @2 ORI.B #$01,CCR ;set timeout error RTS GETIT MOVE.B ORA1(A0),D0 ;read data MOVE.B D0,(A1)+ ;save it RTS ;and exit with results .PAGE ;------------------------------------------------------------------------- ; Subroutine to do reset of keyboard and mouse interfaces ; Inputs: ; None ; Outputs: ; None ; Side Effects: ; D0/A0 trashed ;------------------------------------------------------------------------- RSTKBD MOVEA.L #VIA1BASE,A0 ;set VIA ptr BCLR #0,ORB1(A0) ;set reset signal ORI.B #$01,DDRB1(A0) ;send it MOVE.L #3000,D0 ;do delay for 12 ms BSR.S DELAY RTS ;------------------------------------------------------------------------- ; Subroutine to remove reset signal for keyboard and mouse interfaces ; Inputs: ; A0 = ptr to parallel port VIA (set in RSTKBD routine) ; Outputs: ; None ; Side Effects: ; D0 trashed ;------------------------------------------------------------------------- CLRRST BSET #0,ORB1(A0) ;remove reset signal BSR.S KBDDELAY ;delay for keyboard reset time RTS ;---------------------------------------------------------------------------- ; Subroutine to delay for count in D0 (each count = 4 us). Additional ; entry points set up for fixed delays. ;---------------------------------------------------------------------------- .IF ROM4K = 0 DELAY_1 MOVE.L #TNTHSEC,D0 ;.1 second delay BRA.S DELAY DELAY5 MOVE.L #FIVESEC,D0 ;5 second delay BRA.S DELAY KBDDELAY MOVE.L #KBDDLY,D0 ;delay for COPS debounce loop .ENDC DELAY SUBQ.L #1,D0 ;loop until count = 0 BNE.S DELAY RTS .PAGE ;------------------------------------------------------------------------- ; Sound starting "tone" ;------------------------------------------------------------------------- BEEP BSR.S CLICK ;go click speaker BRA VIDTST ;then go do video test ;------------------------------------------------------------------------- ; Subroutine to set parms for speaker "click" ;------------------------------------------------------------------------- CLICK MOVE.B #$A0,D0 ;set frequency MOVEQ #0,D1 ;and duration MOVEQ #8,D2 ;and volume (medium) RM000 ;then fall thru to tone routine RM000 ;------------------------------------------------------------------------- ; Routine to beep the speaker ; Assumes regs set up as ; D0 = desired frequency ($00 - $AA) ; D1 = duration (0 = .5 msec) ; D2 = volume (0,2,4,...,E) ;------------------------------------------------------------------------- TONE MOVEM.L A0/A4/D3,-(SP) ;save regs BSRS4 TONE2 ;go do tone MOVEM.L (SP)+,A0/A4/D3 ;restore and exit RTS ; separate entry point for call without memory usage TONE2 MOVEA.L #VIA1BASE,A0 ;set VIA ptr ORI.B #$0E,DDRB1(A0) ;set volume bits for output ANDI.B #$F1,ORB1(A0) ;clear and then OR.B D2,ORB1(A0) ; set volume bits ANDI.B #$E3,ACR1(A0) ;clear shift mode bits ORI.B #$10,ACR1(A0) ;set shift reg for continuous rotate ; check system type TST.B DISKROM ;test for Lisa 1 board CHG014 BPL.S @3 ;no changes if yes CHG014 BTST #SLOTMR,DISKROM ;else check if slow timers CHG029 BNE.S @3 ;skip if yes CHG029 MOVE.B D0,D3 ;else adjust input parm CHG014 LSR.B #2,D3 ; by factor of .25 CHG014 ADD.B D3,D0 ; CHG014 @3 MOVE.B D0,T2CL1(A0) ;set frequency MOVE.B #$0F,SHR1(A0) ;set for square wave and trigger ; Do time delay - enter with count in D1 (about .5 msec per count) @1 MOVE.W #$00D0,D3 ;set delay constant @2 DBF D3,@2 DBF D1,@1 SILENCE ANDI.B #$E3,ACR1(A0) ;disable tone RTS4 ;and return .IF DIAGS = 1 ;------------------------------------------------------------------------- ; Routine to handle I/O board selection errors. Does check for access ; of other I/O board devices to try to pinpoint error. ;------------------------------------------------------------------------- NOIO BSET #RS232B,D7 ;set SCC port B access error CHG027 MOVE #STKBASE,SP ;restore stack pointer ; try access of other I/O board devices LEA NOIO2,A3 ;set up new bus error vector MOVE.L A3,BUSVCTR MOVE.L #VIA2BASE,A0 ;set base address CHG027 TST.B (A0) ;try access BRA VIA2TST ;return to testing if OK CHG027 NOIO2 BSET #VIA2,D7 ;set VIA #2 error also CHG027 LEA NOIO3,A3 ;try final access to VIA #1 CHG027 MOVE.L A3,BUSVCTR MOVE.L #VIA1BASE,A0 ;set base address CHG027 TST.B (A0) BRA.S SCRNTST ;exit if OK CHG027 NOIO3 BSET #CPUSEL,D7 ;most likely CPU board error BRA TSTCHK ;go report errors CHG027 .ENDC