Lisa_Boot_ROM_RM248
.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