Lisa_Boot_ROM_RM248
.PAGE
;--------------------------------------------------------------------------
; Monitor code - first displays requested icons, error codes or messages,
; and then outputs menu of options to user and awaits input
;--------------------------------------------------------------------------
INITMON ;entry point for displays
.IF ROM4K = 0
BSR SAVEREGS ;save registers
CLR.L D7 ;reset reg for error indicators
CLR.B STATFLGS ; and status flags
BSET #NOCONT,STATFLGS ;set external entry indicator
INIT1
MOVEM.L D0/A2-A3,-(SP) ;save incoming arguments
BSR DSABLDSK ;disable ints from both drives
BSR RSTKBD ;reset keyboard
BSR CLRRST ;and clear reset
BSR CursorInit ;init cursor and mouse
MOVEM.L (SP)+,D0/A2-A3 ;restore arguments
INIT2 ;internal entry point
.IF DEBUG = 0
MOVEA #STKBASE,SP ;reset stack pointer RM000
.ENDC
.IF USERINT = 1
MOVEM.L D0/A2-A3,-(SP) ;save incoming arguments
.ENDC
.ENDC ;{ROM4K}
BSR SETVLTCH ;set video latch
.IF USERINT = 0
BSR CLRSCRN ;go clear screen
MOVEQ #FIRSTROW,D5 ;set initial cursor ptrs
MOVEQ #FIRSTCOL,D6
.ELSE
BSR DRAWDESK ;display the desktop
BSR MAKEALERT ;draw alert box (in case no icon display)
INIT3 MOVEM.L (SP)+,D0/A2 ;restore arguments
MOVE.L A2,D1 ;icon display?
BEQ.S @0 ;skip if no
BSR DSPALRTICON ;go do icon display
@0 TST D0 ;error code display?
BEQ.S @2 ;skip if no
MOVE.L A2,D1 ;icon displayed?
BNE.S @1 ;skip if yes
MOVEQ #MSGROW,D5 ;else display error code on same line
MOVEQ #CODECOL,D6 ; as error msg
BSR DSPDEC ;display as decimal #
BRA.S @2
@1 BSR DSPCODE ;output error code under icon
@2 MOVE.L (SP)+,A3 ;restore msg ptr
.ENDC
MOVE.L A3,D0 ;message display?
BEQ.S MONITOR
.IF USERINT = 0
BSR DSPMSGR ;go display it
.ELSE
BSR DSPALRTMSG ;go display message in alert box
.ENDC
MONITOR ;entry point for no screen setup
.IF ROM4K = 0
ORI #$0700,SR ;disable all interrupts
BSR SETVCTRS ;set vectors for ROM space CHG028
.ELSE
@1 NOP ;hang for 2716 version of ROM
BRA.S @1
.ENDC
.IF ROM4K = 0
;---------------------------------------------------------------------------
; Now output first level menu, prompt line and cursor. Do preliminary
; check to see if CONTINUE option can be displayed. This is the Customer
; mode level of the monitor code.
;---------------------------------------------------------------------------
LEVEL1
.IF USERINT = 1
CLR RECTCNT ;clear active rectangle count
ANDI.B #$0F,STATFLGS ;init flags
BSET #BTN,STATFLGS ;set operating with buttons flag
BTST #NOCONT,STATFLGS ;display continue?
BNE.S OTHRBTNS ;skip if no
MOVE.L STATUS,D0 ;get test status
ANDI.L #CONTMSK,D0 ;mask don't cares
BNE.S @1 ;skip if error that disallows continuing
TST BOOTMEM ;check boot memory area for R/W errors
BNE.S @1 ;skip if any errors
MOVE #BTN2STRT,A1 ;display CONTINUE button
MOVE.B #KEY2,D0 ;with alternate keycode
LEA CONTMSG,A3 ;and description
MOVEA #BTN2MSG,A2 ;and location RM000
CLR.L D1 ;don't append '...' string
BSR MAKEBUTN
BRA.S OTHRBTNS ;and go make other buttons
@1 BSET #NOCONT,STATFLGS ;set indicator for no CONTINUE option
OTHRBTNS
.ENDC
DOMENU
.IF USERINT = 0
LEA LEV1MSG,A3 ;display rest of menu line and get input
BSR WRTMENU
.ELSE
BTST #NORSTRT,STATFLGS ;display RESTART button?
BNE.S @1 ;skip if not
MOVE #BTN1STRT,A1 ;else do display
MOVE.B #KEY1,D0
LEA RTRYMSG,A3
MOVEA #BTN1MSG,A2 ; RM000
CLR.L D1 ;don't append '...' string
BSR MAKEBUTN
@1 MOVE #BTN3STRT,A1 ;display STARTUP button
MOVE #KEY3,D0
LEA STRTMSG,A3
MOVEA #BTN3MSG,A2 ; RM000
MOVEQ #-1,D1 ;append '...' string
BSR MAKEBUTN
; MOVE.L #KBDBFR,KBDQPTR ;init queue ptr
BSR CursorDisplay ;display mouse cursor
BSET #CHKCMD,STATFLGS ;require user keyboard input to be prefaced
; by the CMD key
GETL1 BSR GETINPUT ;and go wait for input
BCS GETERR ;exit if error
BSR CursorHide ;remove cursor from screen
.ENDC
; Check if input valid. If invalid, beep speaker.
CMP.B #KEY3,D0 ;alternate boot?
BNE.S @2
.IF USERINT = 0
LEA DVCEMSG,A3 ;request input
BSR WRTBOX1
BSR READKEY ;get input
CMP.B #CMDKEY,D0 ;command key?
BEQ.S @1 ;continue if yes
BSR CLRBOX ;else clear box
BRA.S GETL1XIT ;and exit
@1 BSR READKEY ;get device input
.IF NEWTWIG = 1
BSR XLATE ;translate to boot id and save
.ELSE
MOVE.B D0,BOOTDVCE ;save boot device keycode
BSET #ALTBOOT,D7 ;set alternate boot indicator
.ENDC
BRA DOBOOT ;and go attempt boot
.ELSE
BSR CLRDESK ;close the alert box
BRA BOOTMENU ;and go display boot menu
.ENDC
@2 BTST #NORSTRT,STATFLGS ;RESTART button displayed?
BNE.S CONTCHK ;skip if not
CMP.B #KEY1,D0 ;retry?
BNE.S CONTCHK ;skip if not
DORESET
CLR.L D7 ;clear error reg RM000
TST.B SETUPON ;turn on setup bit RM000
BRA BEGIN3 ;and restart diags RM000
CONTCHK
.IF USERINT = 1
BTST #NOCONT,STATFLGS ;continue option displayed?
BNE.S @4 ;skip if not
CMP.B #KEY2,D0 ;continue option selected?
BNE.S @4
; continue from point of failure
BSR CLRDESK ;clear desktop CHG008
ANDI.L #ALTBMSK,D7 ;erase error indicators
MOVE.L STATUS,D0 ;get power-up status
BTST #MMU,D0 ;MMU error?
BNE VIA2TST ;yes - continue from VIA tests
ANDI.L #BOOTMSK,D0 ;check if error that continues to boot attempt
BEQ BOOTCHK ;skip if yes
MOVE.L D0,-(SP) ;else save status
BSR MAKETEST ;make test window
; do init for continue to other tests
MOVE.B #$70,D0 ;turn off mouse
BSR COPSCMD
MOVE.L (SP)+,D0 ;restore status
BTST #VID,D0 ;serial # error?
BEQ.S @1 ;skip if not
MOVEA #CPUSTRT,A1 ;display CPU icon
BSR INVICON
BRA PARTST ;continue with parity test
@1 LSR.L #7,D0 ;skip other CPU errors
TST.B D0 ;clock error?
BNE CONFIG ;yes - continue with config check
LSR.L #2,D0
TST.B D0 ;RS232 error?
BEQ.S @2 ;skip if not
MOVEA #IOSTRT,A1 ;else display I/O board icon
BSR INVICON
BRA DSKTST ;cont with disk test
@2 TST.B PARON ;must be memory error - reenable parity
BRA IOTST ; and continue with I/O board testing
.ENDC
@4
.IF USERINT = 0
CMP.B #CMDKEY,D0 ; command?
BNE.S GETL1XIT
BSR ReadKey ; go get next input
.ENDC
CMP.B #SKEY,D0 ; service mode desired?
BEQ LEVEL2 ; skip if yes
; Indicate invalid by beeping speaker
GETL1XIT
BSR SQUAWK ; sorry charlie
.IF USERINT = 0
BRA.S LEVEL1 ; go wait for another try
.ELSE
LEV1LOOP
BSR CursorDisplay ;redisplay cursor
BRA.S GETL1 ;go get more input
; Error exit - go output error and return to level 1
GETERR
LEA IOBRD,A2 ;get I/O board icon
SUBA.L A3,A3 ;no error message
BRA INIT2
.ENDC
.ENDC ;{ROM4K}
.PAGE
;-------------------------------------------------------------------------
; Subroutine to clear video page of memory or write arbitrary long word
; pattern to entire screen (WRTSCRN entry point).
;-------------------------------------------------------------------------
CLRSCRN CLR.L D0 ; write 0's for white screen
WRTSCRN ; entry pt for write to screen (assumes D0 set)
MOVE.L SCRNBASE,A0 ; get screen base address
MOVE #HEX8K-3,D1 ; set longs count
@1 MOVE.L D0,(A0)+ ; clear for video page
DBF D1,@1
RTS
.IF ROM4K = 0
.IF USERINT = 0
;-------------------------------------------------------------------------
; Subroutine to clear "dialog box" in display row 1.
;-------------------------------------------------------------------------
CLRBOX MOVEM.L D5-D6/A0,-(SP) ;save cursor ptrs and working reg
MOVEQ #1,D5 ;clear from 1,0 to 3,0
MOVEQ #0,D6
BSR SETCRSR ;get address for start
MOVE.L A6,A0 ;save
MOVEQ #2,D5 ;get ending address in A6
BSR SETCRSR
CLRIT CLR (A0)+ ;do clear
CMPA.L A0,A6
BNE.S CLRIT
MOVEM.L (SP)+,D5-D6/A0 ;restore and
RTS ; exit
;-------------------------------------------------------------------------
; Subroutine to display menu line
;-------------------------------------------------------------------------
WRTMENU MOVEM.L D5-D6,-(SP) ;save current cursor ptrs
CLR D5 ;set menu line ptrs
MOVEQ #5,D6
BSR DSPMSG
BSR SETCUR ;draw cursor
BSR DRWLINE ;and underline
BSR ReadKey ;go wait for input
BSR CLRCUR ;clear cursor
MOVEM.L (SP)+,D5-D6
RTS
;-------------------------------------------------------------------------
; Draw underline subroutine
;-------------------------------------------------------------------------
DRWLINE MOVEM.L D0/D5-D6,-(SP) ;save cursor ptrs and working reg
ADDQ #1,D5 ;draw line just above next row
MOVEQ #0,D6
BSR SETCRSR ;get address
SUBA.L #180,A6 ;decrement to bottom of last line
MOVEQ #45,D0 ;set loop count
DRWIT MOVE #$FFFF,(A6)+ ;draw black line
SUBQ #1,D0
BNE.S DRWIT
MOVEM.L (SP)+,D0/D5-D6 ;restore and
RTS ; exit
;-------------------------------------------------------------------------
; Subroutine to write to dialog box
;-------------------------------------------------------------------------
WRTBOX1 MOVEM.L D0/D5-D6,-(SP) ;save D0 and current cursor ptrs
MOVEQ #1,D5 ;set box 1 coordinates
CLR.L D6
BSR SETCRSR ;get address in A6
MOVE #RLONGS,D0
@1 CLR.L (A6)+ ;clear box
SUBQ #1,D0
BNE.S @1
MOVEQ #1,D6 ;space over for neatness
BSR DSPMSG ;write msg
BSR DRWLINE
MOVEM.L (SP)+,D0/D5-D6 ;restore
RTS ;and exit
.ENDC
.PAGE
.IF USERINT = 0
;-------------------------------------------------------------------------
; Subroutine to read keycode from COPS - returns down transitions in D0
;-------------------------------------------------------------------------
ReadKey
BSR ReadCOPS
TST.B D0 ;ignore "up" transitions
BPL.S ReadKey
RTS ;exit with data
.ELSE
;-------------------------------------------------------------------------
; Subroutine to read keycode from COPS - returns down transitions in D0
;-------------------------------------------------------------------------
ReadKey
BSR WT4INPUT
TST.B D0 ;ignore "up" transitions and mouse data
BPL.S ReadKey
RTS ;exit with data
.ENDC
;-------------------------------------------------------------------------
; Subroutine to beep speaker for invalid input
;-------------------------------------------------------------------------
SQUAWK MOVEQ #$20,D0 ; set frequency
MOVE #250,D1 ; 1/8 sec duration
MOVEQ #4,D2 ; low volume
BSR TONE ; and go do it
RTS
;-------------------------------------------------------------------------
; Subroutine to convert keycodes to Ascii
; Inputs: D0 = keycode (word)
; Outputs: D0 = Ascii (byte) or =2 if input invalid
;-------------------------------------------------------------------------
KeyToAscii
MOVEM.L D1/A0,-(SP) ;save regs
LEA AsciiTable,A0 ;keycode to ascii table
MOVE D0,D1 ;keycode to convert
ANDI #$007F,D1 ;ensure valid
SUBI #32,D1 ;decrement for table RM000
BPL.S @1 ;skip if valid RM000
MOVEQ #2,D0 ;else set for invalid char RM000
BRA.S @2 ; RM000
@1 MOVE.B 0(A0,D1.W),D0 ;get ascii
@2 MOVEM.L (SP)+,D1/A0 ;restore
RTS ;exit
.PAGE
;-------------------------------------------------------------------------
; Monitor level 2 (Service mode) - enables access to memory and disk
;-------------------------------------------------------------------------
LEVEL2
.IF USERINT = 0
BSR CLRSCRN ;clear screen
MOVE #$0201,CRTROW ;set starting display ptrs
.ELSE
BSR CLRDESK ;display the desktop
.IF BMENU = 0
MOVEA #MENULOC,A1 ;set up menu start point RM000
BSR GETROWCOL
LEA MENUHDG,A3 ;and display it
BSR DSPMSG
SUB.W #91,A1 ;decrement start pt by 1 row + 1 byte
LEA MENUHDG,A3 ;get length of menu heading
BSR GETLENGTH
ADDQ #1,D2 ;add an extra byte
ANDI.B #$FE,D2 ;ensure its even
MOVE D2,D0 ;save as width of menu heading "box"
MOVEQ #14,D1 ;set height for "box"
MOVEQ #-1,D2 ;set fill pattern
BSR INVERSE ;go hilite it
.ENDC
; make window for output, and display menu line and pull down menu
BSR MAKESVCW ;output service window
DSPMENU BSR WRTMENU
; do final initialization and await input
BSR CursorDisplay ;display cursor
;----------------------------------------------------------------------
; Program NMI key
;
; MOVEQ #$5A,D0 ;set / key for NMI
; BSR COPSCMD
; MOVEQ #$61,D0
; BSR COPSCMD
;----------------------------------------------------------------------
GETLEV2
BSR GETINPUT ;and go await input
BCS GETERR ;exit if error
BSR CursorHide ;else remove cursor from screen and go
; analyze input
.ENDC
.IF USERINT = 0
DSPMENU
LEA LEV2MSG,A3 ;output menu and get input
BSR WRTMENU
.ENDC
; Check for valid input
CMP.B #KEY1,D0 ; display memory?
BEQ DSPMEM
CMP.B #KEY2,D0 ; set memory?
BEQ SETMEM
CMP.B #KEY3,D0 ; call routine
BEQ CALLRTN
.IF ROM16K = 1
CMP.B #KEY4,D0 ; loop?
BEQ LOOPTST
.ENDC
CMP.B #KEY5,D0 ; video adjust?
BEQ VIDAJST
.IF BURNIN = 1
CMP.B #KEY6,D0 ; power cycle?
BEQ PowerCycle
.ENDC
CMP.B #KEY7,D0 ; quit?
BNE.S @1
BCLR #NORSTRT,STATFLGS ;clear no reset status flag
CLR.L D0 ;set parms for level1 - no error code
SUBA.L A2,A2 ;no icon display
SUBA.L A3,A3 ;no message display
BRA INIT2 ;and go back to level1
@1 BRA INVALID ; else invalid input
.PAGE
.IF USERINT = 1
;---------------------------------------------------------------------------
; Routine to display the preliminary pull-down menu
;---------------------------------------------------------------------------
WRTMENU
.IF BMENU = 0
MOVEQ #MITEMS,D1 ;set # of items in menu
LEA DISPMSG,A3 ;set ptr to menu entries
CLR RectCnt ;clear active rectangle count
ANDI.B #$07,STATFLGS ;init flags
BSET #MENU,STATFLGS ;set working with menu flag
MOVE.L D1,D4 ;save item count
MOVEQ #MENUWIDTH,D0 ;set menu parms
MULU #MENULEN,D1 ;length depends on # of items
ADDQ #2,D1 ;incr for bottom border
MOVE #MENUSTRT,A1 ;set start point for menu "box"
MOVE #MENU1MSG,A2 ;display menu items
LEA MENUID,A4 ;ptr to id's for menu entries
BSR MAKEMENU ;go do it
.ELSE
CLR RectCnt ;clear active rectangle count
ANDI.B #$0F,STATFLGS ;init flags
MOVEQ #MENUWIDTH,D0 ;set menu parms
MOVEQ #MITEMS,D1 ;set # of items in menu
MULU #MENULEN,D1 ;length depends on # of items
LEA MENUHDG,A3 ;set ptr for menu heading
BSR.S DSPMENUBOX ;go display blank menu box w/ heading
MOVEQ #MITEMS,D4 ;set # of items in menu
MOVE #MENUSTRT,A1 ;set menu starting point
MOVE #MENU1MSG,A2 ;menu items display address
LEA DISPMSG,A3 ;set ptr to menu entries
LEA MENUID,A4 ;ptr to id's for menu entries
BSR MAKEMENU ;go fill in the menu
.ENDC ;{MENU}
RTS
.IF BMENU = 1
;---------------------------------------------------------------------------
; Subroutine to display blank menu box with heading
; Inputs:
; D0 = menu width
; D1 = menu length
; A3 = menu heading
; Outputs:
; None
; Side Effects:
; D2/A1,A3 trashed
;---------------------------------------------------------------------------
DSPMENUBOX
MOVEM.L D0-D1,-(SP) ;save regs
BSET #MENU,STATFLGS ;set working with menu flag
BSR CLRMENU ;first clear the menu bar
ADDQ #2,D1 ;bump length for bottom border
MOVE #MENUSTRT,A1 ;set menu starting point
BSR MAKEBOX ;display the box
MOVEA #MENULOC,A1 ;set up menu heading display point
BSR GETROWCOL ;convert to screen ptrs
CLR.L D1 ;don't display '...' string
BSR DSPSTRING ;display the title
SUBA.L A2,A3 ;get length of menu title
MOVE.L A3,D2 ;move to working reg
ADDQ #2,D2 ;add extra bytes to cover entire title
ANDI.B #$FE,D2 ;ensure it's even
MOVE D2,D0 ;save as width of menu heading "box"
MOVEQ #14,D1 ;set height for "box"
MOVEQ #-1,D2 ;set fill pattern
SUB.W #91,A1 ;decrement start pt by 1 row + 1 byte
BSR INVERSE ;go hilite it
MOVEM.L (SP)+,D0-D1 ;restore regs
RTS
.ENDC ;{MENU}
;---------------------------------------------------------------------------
; Subroutine to create Service mode window
;---------------------------------------------------------------------------
MAKESVCW
MOVEA #SVCSTRT,A1 ;left corner point RM000
MOVEQ #SVCWIDTH,D0 ;width of window
MOVE.L #SVCHIGH,D1 ;height
LEA SVCMSG,A3 ;title
BSR MAKEWINDOW ;go do it
MOVE #FIRSTROW,CRTROW ;init screen ptrs
MOVE #FIRSTCOL,CRTCOL
RTS
.ENDC ;{USERINT}
;---------------------------------------------------------------------------
; Do display memory operation
;---------------------------------------------------------------------------
DSPMEM BSR GETA ;go get address
BCS INVALID
TST D3 ;if no input go back to menu line
.IF USERINT = 0
BEQ.S DSPMENU
.ELSE
BEQ LEV2LOOP
.ENDC
BCLR #0,D2 ;ensure even address
MOVE.L D2,A2 ;and save
; Check for all input on one line
BSR GETCH ;read queue to see if more input
BCS.S @1 ;skip if not
CMPI.B #' ',D0 ;must be a space separator
BEQ.S RDCNT ;skip if yes
@1 LEA CNTMSG,A3 ;display count prompt
BSR PROMPT
; Decode count input and do display
RDCNT MOVEQ #4,D1 ;go get count (max of $FFFF)
BSR GETPARM
BCS INVALID
BSR PUTLF ;set display ptrs and space 1 line
TST D3 ;set default count if no input
BEQ.S @4
BRA.S @5
@4 MOVEQ #16,D2 ;set default count
; Do display of memory
@5 MOVE.L A2,D0 ;get display address
MOVEQ #8,D1 ;and display it
BSR OUTCH
.IF USERINT = 0
MOVEQ #15,D6 ;set col ptr for data display
.ELSE
ADDQ #4,D6 ;bump col for data display
.ENDC
MOVEQ #8,D4 ;set loop count
@6 MOVE (A2)+,D0 ;read data word
MOVEQ #4,D1 ;display it
BSR OUTCH
ADDQ #1,D6 ;add space
SUBQ #1,D4 ;loop for one line
BNE.S @6
SUBQ.L #8,D2 ;decr data count RM000
SUBQ.L #8,D2 ; RM000
BLE.S @7 ;exit if done
BSR PUTLF ;go to next line
BRA.S @5 ;and continue until done
@7 BSR PUTLF ;add blank line
.IF USERINT = 0
BRA DSPMENU ;go wait for next command
.ELSE
BRA LEV2LOOP ;continue level2 loop
.ENDC
.PAGE
;---------------------------------------------------------------------------
; Do set memory operation - enables setting of bytes, words or longs
; up to 24 bytes max. Decodes data length to determine type of operation.
;---------------------------------------------------------------------------
SETMEM BSR GETA ;go get address
BCS INVALID ;abort if invalid
TST D3 ;any input?
.IF USERINT = 0
BEQ DSPMENU ;abort if none
.ELSE
BEQ LEV2LOOP ;abort if none
.ENDC
MOVE.L D2,A2 ;save target address
; Check for all input on one line
BSR GETCH ;read queue to see if more input
BCS.S @1 ;skip if not
CMPI.B #' ',D0 ;must be a space separator
BEQ.S RDDTA ;skip if yes
@1 LEA DATAMSG,A3 ;else output data prompt
BSR PROMPT
; Decode parameter input and do operation
RDDTA MOVEQ #8,D1 ;get max of 8 chars
BSR GETPARM
BCS INVALID
TST D3 ;any input?
.IF USERINT = 0
BEQ DSPMENU ;abort if none
.ELSE
BEQ LEV2LOOP
.ENDC
; write data to memory
CMP.B #2,D3 ;first test for byte operation
BGT.S @1
MOVE.B D2,(A2)+ ;write byte
BRA.S @3
@1 MOVE.L A2,D0 ;ensure even address for word or long op
BCLR #0,D0
MOVE.L D0,A2
CMP.B #4,D3 ;test for word op
BGT.S @2
MOVE D2,(A2)+ ;write word
BRA.S @3
@2 MOVE.L D2,(A2)+ ;write long
@3 BSR GETCH ;read input queue
BCS.S @4 ;skip if none
CMPI.B #' ',D0 ;must be a space separator
BNE INVALID ;exit if error
BRA.S RDDTA ;else continue operation
@4
.IF USERINT = 0
BRA DSPMENU ;go wait for next command
.ELSE
BRA LEV2LOOP ;continue level2 loop
.ENDC
.PAGE
;---------------------------------------------------------------------------
; Do 'call' function - ensures address is on word boundary.
;---------------------------------------------------------------------------
CALLRTN BSR GETA ;go get address
BCS INVALID
TST D3 ;abort if no input
.IF USERINT = 0
BEQ DSPMENU ;go wait for next command
.ELSE
BEQ LEV2LOOP ;continue level2 loop
.ENDC
BCLR #0,D2 ;else ensure on word boundary
MOVE.L D2,A6SAV ;save for jump
; load registers from save area before jumping
LEA DATARGS,A6 ;get ptr
MOVEM.L (A6)+,D0-D7/A0-A5 ;load regs
MOVE.L A6SAV,A6 ;restore address
JSR (A6) ;and do call
BSR SAVEREGS ;save registers on exit
.IF USERINT = 0
BRA DSPMENU ;go wait for next command
.ELSE
BRA LEV2LOOP ;continue level2 loop
.ENDC
.IF ROM16K = 1
.PAGE
;---------------------------------------------------------------------------
; Do loop on diagnostic
;---------------------------------------------------------------------------
LOOPTST
.IF USERINT = 1
BSR MAKESVCW ;redraw service window
BSR PUTLF ;add blank line and setup ptrs
LEA TSTMENU,A3 ;set ptr to test choices
MOVEQ #FIRSTCOL,D4 ;set left margin
BSR DSPMSG ;and go do display choices
.ENDC
LEA TSTMSG,A3 ;display test routine prompt
BSR PROMPT
BCS INVALID ;skip if bad input
TST D3 ;any input?
.IF USERINT = 0
BEQ DSPMENU ;abort if none
.ELSE
BNE.S @0 ;skip if yes
BSR MAKESVCW ;else redraw service window
BRA LEV2LOOP ;and return to level 2
.ENDC
@0 SUBQ #1,D3 ;ensure only one char input
BNE INVALID ;skip if more than one
MOVEQ #1,D1 ;go get one character of input
BSR GETPARM
CMP.B #MAXTEST,D2 ;check if within max range
BHI INVALID ;exit if not
SUBQ #1,D2 ;decr for index
BMI INVALID ;skip if negative (i.e., 0 was input)
;----------------------------------------------------------------------------
; Program NMI key to exit loop
;
; LEA LOOPEND,A3 ;set NMI vector
; MOVE.L A3,NMIVCT
; MOVEQ #$5A,D0 ;set / key for NMI
; BSR COPSCMD
; MOVEQ #$61,D0
; BSR COPSCMD
;----------------------------------------------------------------------------
.IF USERINT = 1
.IF FULLSCC = 0
CMP.B #7,D2 ;SCC test selected?
BEQ.S NOSCCTST ;skip if yes
.ENDC
MOVE.L D2,-(SP) ;save test #
BSR CLRDESK ;clear desktop except for menu bar
BSR MAKETEST ;draw test window
MOVE.L (SP)+,D2 ;restore test #
CMP.B #4,D2 ;CPU test?
BGE.S @1 ;skip if not
MOVEA #CPUSTRT,A1 ;else set ptr for CPU board icon RM000
BRA.S @4 ;and go hilite it
@1 CMP.B #10,D2 ;I/O board test?
BGE.S @2
MOVEA #IOSTRT,A1 ;set ptr for I/O board icon RM000
BRA.S @4
@2 CMP.B #11,D2 ;memory test?
BGE.S @3
MOVEA #MEMSTRT,A1 ;set ptr for memory board icon RM000
BRA.S @4
@3 MOVEA #XCRDSTRT,A1 ;else must be I/O slot card RM000
@4 BSR INVICON ;display in test window
.ENDC
ADD D2,D2 ;double test # for table index
BSET #LOOP,D7 ;set loop flag
LEA LOOPTBL,A0 ;and jump to requested routine
ADD 0(A0,D2.W),A0
JMP (A0)
;---------------------------------------------------------------------------
; Loop exit via NMI routine
;
;LOOPEND BTST #1,STATREG ;parity error?
; BEQ NMI ;skip if yes to report error
; MOVE.L #STKBASE,SP ;else restore stack
; BRA LEVEL2 ;and redisplay service mode
;---------------------------------------------------------------------------
; special entry points for routines that require initial setup
MMUTSTE1
TST.B SETUPON ;turn on SETUP bit for MMU tests
BRA MMUTST ;go do main test
.IF FULLSCC = 0
NOSCCTST ;SCC test not available
BSR CLRDESK ;clear desktop
BSR MAKESVCW ;redraw service window
BRA NOTAVAIL ;and exit
.ENDC
MEMTST3 BSET #6,MEMCODE ;set for extended memory test
MOVEQ #PROFILE,D0 ;and for normal boot default (Profile)
BSR SAV2PM ;save in parameter memory
BRA MEMLOOP ;and go do memory testing
; jump table for looping on start-up diagnostics
LOOPTBL .WORD ROMTST-LOOPTBL ;1 = ROM checksum test
.WORD MMUTSTE1-LOOPTBL ;2 = MMU test
.WORD VIDCHK-LOOPTBL ;3 = Video test
.WORD PARTST-LOOPTBL ;4 = Parity logic test
.WORD VIA2TST-LOOPTBL ;5 = Parallel port VIA test
.WORD VIA1CHK-LOOPTBL ;6 = Keyboard port VIA test
.WORD COPSENBL-LOOPTBL ;7 = I/O board COPS test
.IF FULLSCC = 1
.WORD SCCTEST-LOOPTBL ;8 = SCC test
.ELSE
.WORD NOSCCTST-LOOPTBL ;SCC available only with final LISA's
.ENDC
.WORD DSKTST-LOOPTBL ;9 = disk controller test
.WORD CLKTST-LOOPTBL ;A = clock test
.WORD MEMTST3-LOOPTBL ;B = memory test
.WORD CONFIG2-LOOPTBL ;C = configuration check
.ENDC
.PAGE
;---------------------------------------------------------------------------
; Display video adjust pattern
;---------------------------------------------------------------------------
VIDAJST MOVEQ #-1,D0 ;first erase the screen
BSR WRTSCRN
; Next draw the horizontal lines
CLR.L D0 ;set scan line
BSR.S DRWHORZ ;go draw white line
MOVEQ #27,D0 ;set next scan line
MOVEQ #28,D1 ;set increment value also
MOVEQ #12,D2 ;set line count
@1 BSR.S DRWHORZ ;draw some more
ADD D1,D0 ;incr to next line position
DBF D2,@1 ;loop until done
; Now draw the vertical lines
CLR.L D0 ;set pixel #
BSR.S DRWVERT ;draw a vertical line
MOVEQ #44,D0 ;set next pixel position
MOVEQ #45,D1 ;set incr value also
MOVEQ #15,D2 ;set line count
@2 BSR.S DRWVERT ;draw some more
ADD D1,D0 ;incr to next pixel position
DBF D2,@2 ;loop until done
; Wait for any keystroke to terminate display
BSR READKEY
BRA LEVEL2 ;return to menu display
.PAGE
;----------------------------------------------------------------------------
; Subroutine to draw horizontal lines. Requires inputs:
; D0 = scan line (0 to 363 decimal)
; $110 = base address of screen
;----------------------------------------------------------------------------
DRWHORZ MOVEM.L D0/D1/A0,-(SP) ;save regs
MOVEQ #90,D1 ;line length in bytes
MULU D1,D0 ;compute address offset
MOVE.L SCRNBASE,A0 ;get base screen address
ADDA.L D0,A0 ;add offset
@1 CLR.B (A0)+ ;draw the line
SUBQ #1,D1
BNE.S @1
MOVEM.L (SP)+,D0/D1/A0 ;restore
RTS
;----------------------------------------------------------------------------
; Subroutine to draw vertical lines. Requires inputs:
; D0 = pixel position (0 to 719 decimal)
; $110 = base address of screen
;----------------------------------------------------------------------------
DRWVERT MOVEM.L D0-D3/A0,-(SP) ;save regs
MOVEQ #8,D1 ;pixels per byte
DIVU D1,D0 ;compute address offset
CLR.L D2
MOVE D0,D2 ;save offset
MOVE.L SCRNBASE,A0 ;get base screen address
ADDA.L D2,A0 ;add offset
SWAP D0 ;get remainder
SUB D0,D1 ;compute bit position to set
SUBQ #1,D1
MOVEQ #90,D2 ;distance to next pixel
MOVE #364,D3 ;line length
@1 BCLR D1,(A0) ;draw the line
ADDA.L D2,A0 ;compute next pixel to set
SUBQ #1,D3
BNE.S @1 ;loop until done
MOVEM.L (SP)+,D0-D3/A0 ;restore
RTS
.PAGE
.IF BURNIN = 1
;-----------------------------------------------------------------------------
; Power cycle entry point - branches to cycling routine
;-----------------------------------------------------------------------------
PowerCycle
BSR CLRDESK ;clear desktop
BRA CHKPAS2 ;go start power cycle
.ENDC
.PAGE
;----------------------------------------------------------------------------
; Invalid input detected - beep speaker and notify user
;----------------------------------------------------------------------------
INVALID BSR SQUAWK ;that's a no no
.IF USERINT = 0
LEA WHATMSG,A3
BSR WRTBOX1
BRA DSPMENU ;let's try again
.ELSE
LEA WHATMSG,A3 ;output question mark
BSR DBOXDSPLY ;display in dialog box
BRA.S INVXIT
LEV2LOOP
BSR CLRDBOX ;go remove dialog box
INVXIT
BSR WRTMENU ;redisplay pull-down menu
BSR CursorDisplay ;redisplay cursor
BRA GETLEV2 ;and go get more input
.ENDC
.IF ROM16K = 1
.IF FULLSCC = 0
; Routine for not available message
NOTAVAIL
BSR SQUAWK ;alert user with a beep
LEA NOTAMSG,A3 ;set ptr for message
BSR DBOXDSPLY ;display in dialog box
BRA.S INVXIT ;and go return for more input
.ENDC ;{FULLSCC}
.ENDC ;{ROM16K}
.PAGE
.IF USERINT = 0
;-------------------------------------------------------------------------
; Cursor Routines for Service mode
;-------------------------------------------------------------------------
; Routine to display rectangular cursor
SETCUR BSR SETCRSR ; set A6 with cursor location
CLR.B (A6) ; set white first
CLR.B R1(A6)
CLR.B R2(A6)
CLR.B R3(A6)
CLR.B R4(A6)
CLR.B R5(A6)
CLR.B R6(A6)
CLR.B R7(A6)
; Entry point to erase cursor
CLRCUR BSR SETCRSR ; set A6 with cursor location
NOT.B (A6) ; then complement it
NOT.B R1(A6)
NOT.B R2(A6)
NOT.B R3(A6)
NOT.B R4(A6)
NOT.B R5(A6)
NOT.B R6(A6)
NOT.B R7(A6)
RTS ; and thats all there is...
;--------------------------------------------------------------------------
; SCROLL - move contents of screen up one whole line except for top 3
; lines which are saved for menu display.
; We assume that we are at bottom line when called. D6 (column) will be
; left alone, but D5 (row) will be set at 32.
;--------------------------------------------------------------------------
SCROLL MOVEM.L A0/D6,-(SP) ;save current column and bfr ptr
MOVEQ #FIRSTROW,D5 ;and set to beginning row
CLR.L D6
BSR SETCRSR ;get address of screen
MOVE.L A6,A0 ;set as from ptr
ADDA #RBYTES,A0
MOVE #30*RLONGS,D1 ;set loop for long copies
@1 MOVE.L (A0)+,(A6)+ ;scroll it
SUBQ #1,D1
BGT.S @1
MOVEQ #LASTROW,D5 ;peg at bottom
MOVEM.L (SP)+,A0/D6 ;restore old column and bfr ptr
RTS
.PAGE
; PUTLF - advance to next row; this may cause a scroll if at bottom
PUTLF MOVE.B CRTROW,D5 ;get last state
MOVEQ #FIRSTCOL,D6 ;update
ADDQ #1,D5
CMPI #LASTROW,D5
BLE.S @9 ;skip if its ok
BSR.S SCROLL ; else, do a scroll operation
@9 MOVE.B D5,CRTROW ;save updates
MOVE.B D6,CRTCOL
RTS
; PUTBS - move cursor left one position.
PUTBS SUBQ.B #1,D6
CMP.B #10,D6 ;stop at 10th col
BGE.S @9
MOVEQ #10,D6
@9 RTS
;-----------------------------------------------------------------------------
; Subroutine to output prompt line and gather input
;-----------------------------------------------------------------------------
PROMPT MOVEM.L D5-D6/A2,-(SP) ;save screen ptrs and target address
MOVEQ #1,D5
CLR.L D6
BSR SETCRSR ;get address in A6
MOVE #RLONGS,D0
@1 CLR.L (A6)+ ;clear box
SUBQ #1,D0
BNE.S @1
MOVEQ #1,D6 ;add space
BSR DSPMSG ;write msg
BSR SETCUR
BSR DRWLINE
BSR RDINPUT ;go handle input
MOVEM.L (SP)+,D5-D6/A2 ;restore and exit
RTS
;-----------------------------------------------------------------------------
; Subroutine to read keyboard input and save in buffer. Accepts max of
; 64 characters.
;-----------------------------------------------------------------------------
RDINPUT
MOVEA #KBDBFR,A0 ;set buffer ptrs RM000
MOVE.L A0,A1 ;same for head and tail
CLR.L D3 ;clear for result use
READIN BSR READKEY ;get char
BSR KeyToASCII ;convert to ASCII
TST.B D0 ;ignore CMD, Option, Shift, Alpha lock
BEQ.S READIN
.LIST
CMP.B #BS,D0 ;backspace key?
BNE.S @2
TST D3 ;any input
BEQ.S READIN ;no - ignore
SUBQ #1,D3 ;decrement count
TST.B -(A1) ;delete char from queue
BSR CLRCUR
BSR PUTBS ;do backspace on screen
BSR SETCUR
BRA.S READIN ;and continue
@2 CMP.B #RET,D0 ;return key?
BEQ.S @3 ; yes - exit
CMP.B #64,D3 ;at max?
BLT.S @4 ;skip if no
BSR SQUAWK ;else notify user
BRA.S READIN ;and ignore input
@4 ADDQ #1,D3 ;incr char count
BSR ENQKBD ;queue it
BSR DSPVAL ;and output it
BSR SETCUR ;advance cursor
BRA.S READIN ;and continue read
@3 BSR CLRCUR ;erase cursor to signify input accepted
RTS
.ELSE
;-----------------------------------------------------------------------------
; Subroutine to output prompt line and gather input
;-----------------------------------------------------------------------------
PROMPT MOVEM.L D5-D6/A2,-(SP) ;save screen ptrs and target address
BSR MAKEDBOX ;make dialog box
MOVE #DBOXROW,D5 ;set msg ptrs
MOVE #DBOXCOL,D6
BSR GETLENGTH ;get message length
ADDQ #2,D2 ;incr for spacing
MOVE D2,MSGLEN ;save as message length
BSR DSPMSG ;write msg
BSR RDINPUT ;go handle input
MOVEM.L (SP)+,D5-D6/A2 ;restore and exit
RTS
;-----------------------------------------------------------------------------
; Subroutine to read keyboard input and save in buffer. Accepts max of
; 48 characters.
;-----------------------------------------------------------------------------
RDINPUT
MOVE.L #KBDBFR,A0 ;set buffer ptrs
MOVE.L A0,A1 ;same for head and tail
CLR.L D3 ;clear for result use
READIN BSR READKEY ;get char
BSR KeyToASCII ;convert to ASCII
TST.B D0 ;ignore CMD, Option, Shift, Alpha lock
BEQ.S READIN
CMP.B #BS,D0 ;backspace key?
BNE.S @2
TST D3 ;any input
BEQ.S READIN ;no - ignore
SUBQ #1,D3 ;decrement count
TST.B -(A1) ;delete char from queue
BSR PUTBS ;do backspace on screen
BSR CLRIT ;clear char on screen
BRA.S READIN ;and continue
@2 CMP.B #RET,D0 ;return key?
BEQ.S @3 ; yes - exit
CMP.B #48,D3 ;at max?
BLT.S @4 ;skip if no
BSR SQUAWK ;else notify user
BRA.S READIN ;and ignore input
@4 ADDQ #1,D3 ;incr char count
BSR ENQKBD ;queue it
BSR DSPVAL ;and output it
BRA.S READIN ;and continue read
@3 RTS
;--------------------------------------------------------------------------
; SCROLL - move contents of Service Window up one whole line. Assumed
; that we are at bottom line when called. D6 (column) and D5 (row) are
; set to start of last line.
;--------------------------------------------------------------------------
SCROLL MOVEM.L D0-D2/A0,-(SP) ;save data regs and bfr ptr
MOVEQ #FIRSTROW+ROWLINES,D5 ;set beginning character row +1
MOVEQ #FIRSTCOL,D6 ; and beginning column
BSR SETCRSR ;get address of screen
MOVE.L A6,A0 ;set as to ptr
ADDA #,A0 ;set from ptr down one character row RM000
MOVE #NROWS,D2 ;number of rows to move
@1 MOVE #ROWLINES,D1 ;number of pixel lines per character row
@2 MOVE #ROWLEN,D0 ;length of a pixel line in window
@3 MOVE (A0)+,(A6)+ ;scroll it
SUBQ #2,D0 ;do entire pixel line
BGT.S @3
ADDQ #1,D5 ;bump to next row
@4 MOVEQ #FIRSTCOL,D6 ;set first col
BSR SETCRSR ;compute address
MOVE.L A6,A0 ;set as to ptr
ADDA #,A0 ;set from ptr down one character row RM000
SUBQ #1,D1 ;do all pixel lines
BNE.S @2
SUBQ #1,D2 ;finished a character row
BNE.S @1 ; loop until done
MOVE #LASTROW,D5 ;peg at bottom
MOVE #FIRSTCOL,D6
MOVEM.L (SP)+,D0-D2/A0 ;restore data regs and bfr ptr
RTS
.PAGE
; PUTLF - advance to next row; this may cause a scroll if at bottom
PUTLF MOVE CRTROW,D5 ;get last state
MOVEQ #FIRSTCOL,D6 ;update column to left edge of window
ADD #ROWLINES,D5 ;bump row by number of pixel lines per row
CMPI #LASTROW,D5
BLE.S @9 ;skip if its ok
BSR.S SCROLL ; else, do a scroll operation
@9 MOVE D5,CRTROW ;save updates
MOVE D6,CRTCOL
RTS
; PUTBS - move cursor left one position.
; Assumes location MSGLEN = left most column for window.
PUTBS SUBQ #1,D6
CMP MSGLEN,D6 ;stop at left edge
BGE.S @9
MOVE MSGLEN,D6
@9 RTS
; Routine to erase data on screen
CLRIT MOVE #' ',D0 ; output a space
BSR DSPVAL
SUBQ #1,D6 ; reposition col ptr
RTS ; and that's all there is...
.ENDC
.PAGE
;-----------------------------------------------------------------------------
; Subroutine to save keyboard input in buffer - ignores data if buffer full.
;-----------------------------------------------------------------------------
ENQKBD MOVE.L A2,-(SP) ;save working reg
MOVEA #KBDEND,A2 ;get ptr to end of buffer RM000
CMPA.L A1,A2 ; at end of buffer?
BEQ.S @9 ; exit if yes
MOVE.B D0,(A1)+ ; else do save
@9 MOVE.L (SP)+,A2 ;restore
RTS
;-----------------------------------------------------------------------------
; This code gets the next byte from the keyboard queue and delivers it to
; caller in D0.
;-----------------------------------------------------------------------------
GETCH CMPA.L A0,A1 ;check if any data
BEQ.S @1 ;exit if none
MOVE.B (A0)+,D0 ;get data
BRA.S @2
@1 ORI.B #$01,CCR ;set empty indicator
@2 RTS
.PAGE
;-------------------------------------------------------------------------
; Subroutine to get address parameter
;-------------------------------------------------------------------------
GETA LEA ADDRMSG,A3 ;output prompt and get input
BSR PROMPT
MOVEQ #8,D1 ;decode address (max of 8 digits)
BSR.S GETPARM
RTS
.PAGE
;-------------------------------------------------------------------------
; Subroutine to get input parameters. Reads Ascii values from keyboard
; buffer and calls conversion routine to return hex values. Stops after
; reading requested input or 'space' separator encountered.
; Inputs: D1 = max chars to read
; Outputs: D2 = value read
; D3 = # of chars read
; Carry bit set if invalid chars.
;-------------------------------------------------------------------------
GETPARM CLR.L D3 ;use for counter
CLR.L D2 ;use for result
READQ BSR GETCH ;check input queue
BCS.S GETEXIT ;exit if no chars
CMPI.B #' ',D0 ;space separator?
BNE.S @3 ;if not, go response
TST.B -(A0) ;replace on queue
BRA.S GETEXIT ;and exit
@3 CMPI.B #'0',D0 ;check if valid hex char
BLT.S INVPARM
CMPI.B #'9',D0
BLS.S OKCH ;OK if 0-9
CMPI.B #'A',D0 ; or A-F
BLT.S INVPARM
CMPI.B #'F',D0
BGT.S INVPARM
OKCH BSR.S CONVERT ;convert to hex digit
LSL.L #4,D2 ;save char
OR.B D0,D2
ADDQ #1,D3 ;bump counter
CMP.B D3,D1 ;at max?
BNE.S READQ ;continue if no
GETEXIT ANDI.B #$FE,CCR ;clear error indicator
BRA.S GETXIT2 ;and exit
INVPARM ORI.B #$01,CCR ;set error indicator
GETXIT2 RTS
;-------------------------------------------------------------------------
; Subroutine to convert Ascii character to hex. Expects input in D0
; and returns converted value in D0.
;-------------------------------------------------------------------------
CONVERT CMP.B #$40,D0 ;check if number or letter
BGT.S @1 ;skip if letter
SUBI.B #$30,D0 ;simple operation for number
BRA.S @9
@1 SUBI.B #$41,D0 ;a little different for letters
ADDI.B #$0A,D0
@9 RTS
.PAGE
.IF USERINT = 1
;-------------------------------------------------------------------------
; Subroutine to write to dialog box
;-------------------------------------------------------------------------
DBOXDSPLY
MOVEM.L D0/D5-D6,-(SP) ;save D0 and current cursor ptrs
BSR MAKEDBOX ;clear dialog box and redraw
MOVE #DBOXROW,D5 ;set box coordinates
MOVE #DBOXCOL,D6
BSR SETCRSR ;get address in A6
BSR DSPMSG ;write msg
MOVEM.L (SP)+,D0/D5-D6 ;restore
RTS ;and exit
;-------------------------------------------------------------------------
; Subroutine to remove dialog box from screen
;-------------------------------------------------------------------------
CLRDBOX MOVEQ #ROWBYTES,D0 ;set pixel line length RM000
MOVEA #DESKLINE,A6 ;set starting point as bottom of menu line RM000
CLR.L D1
MOVE.L A6,A5 ;set limit as bottom of dialog box
MOVE.L #,D1 ; by adding box heigth to start pt
ADD.L #DBOXTOP,D1
ADDA.L D1,A5
BSR GRAY ;redraw gray pattern
RTS
;-----------------------------------------------------------------------------
; GETINPUT routine - waits for inputs from mouse or keyboard and returns
; with keycode in D0 if keyboard input, or rectangle ID if active rect is
; selected with the mouse. If CMD flag is set, keyboard input returned
; only when prefaced by the CMD key.
;-----------------------------------------------------------------------------
; State 1 - General wait
GETINPUT
BTST #CMDFLG,STATFLGS ;command key still down?
BNE.S GET2 ;skip if yes
GET1 BSR WT4INPUT ;else go wait for COPS input
CHKIT
CMP.B #MOUSUP,D0 ;mouse button up?
BNE.S @1
BCLR #MOUSE,STATFLGS ;clear mouse flag
BRA.S GET1 ;and go wait for more input
@1 CMP.B #MOUSDWN,D0 ;mouse button down?
BNE.S @2
BSET #MOUSE,STATFLGS ;set reminder flag
BRA.S @3
@2 TST.B D0 ;mouse data?
BNE.S @5 ;skip if not
BSR CursorHide ;else clear old cursor
BSR CursorDisplay ;and redisplay cursor in new position
BTST #MOUSE,STATFLGS ;is mouse button down?
BEQ.S GET1 ;skip if not
@3 BSR CHKPOSN ;else go check mouse position
BEQ.S GET1 ;continue if not over a rect
BRA GET3 ;else go to state 3
@5 CMP.B #CmdDwn,D0 ;command key down?
BNE.S @6
BSET #CMDFLG,STATFLGS ;set flag if yes
BRA.S GET2 ;and go to state 2
@6 CMP.B #CmdUp,D0 ;command key up?
BNE.S @4
BCLR #CMDFLG,STATFLGS ;clear flag if yes
BRA.S GET1 ;and continue in loop
@4 BTST #CHKCMD,STATFLGS ;CMD key prefix required?
BNE.S GET1 ;loop if yes
@7 TST.B D0 ;else check if downstroke
BPL.S GETINPUT ;skip upstrokes
BSR CHKINPUT ;go check if rectangle selected
RTS ;and return with keycode
; State 2 - Command (apple) button down
GET2
WAIT2 BSR WT4INPUT ;else go wait for COPS input
CHKIT2 CMP.B #CMDUP,D0 ;command key up?
BNE.S @2 ;skip if not
BCLR #CMDFLG,STATFLGS ;else clear flag
BRA.S GET1 ;and return to state 1
@2 CMP.B #MOUSUP,D0 ;mouse button up?
BNE.S @3
BCLR #MOUSE,STATFLGS ;clear mouse flag
BRA.S GET2 ;and go wait for more input
@3 CMP.B #MOUSDWN,D0 ;mouse button down?
BNE.S @4
BSET #MOUSE,STATFLGS ;set reminder flag
BRA.S @5
@4 TST.B D0 ;mouse data?
BNE.S @6
BSR CursorHide ;else clear old cursor
BSR CursorDisplay ;and redisplay cursor in new position
BTST #MOUSE,STATFLGS ;is mouse button down?
BEQ.S GET2 ;skip if not
@5 BSR CHKPOSN ;else go check mouse position
BEQ.S GET2 ;continue if not over a rect
BRA.S GET3 ;else go to state 3
@6 BPL.S WAIT2 ;ignore upstrokes
BSR CHKINPUT ;go check if rectangle selected
RTS ;and return with keycode
; State 3 - Mouse button down and over an active rectangle
GET3 MOVE D0,D1 ;save rectangle ID
WAIT3 BSR WT4INPUT ;go wait for input
CMP.B #MOUSUP,D0 ;mouse button up?
BNE.S @1 ;skip if not
BCLR #MOUSE,STATFLGS ;clear indicator
MOVE D1,D0 ;restore rectangle ID
RTS ;and go analyze input
@1 TST.B D0 ;mouse data?
BNE.S WAIT3 ;continue wait if not - ignore keyboard input
@2 BSR CursorHide ;move cursor to new position
BSR CursorDisplay
BSR CHKPOSN ;check if over a rect
BNE.S GET3 ;stay in this state if yes
BRA GETINPUT ;else return to state 1
;-------------------------------------------------------------------------
; WT4INPUT
;
; Routine to wait for input from COPS. Returns with keycode in D0
; or sets D0 = 0 if mouse data received.
;
;-------------------------------------------------------------------------
WT4INPUT
; State 0 - general wait
COPS0 BSR ReadCOPS ;get input from COPS
TST.B D0 ;mouse data?
BEQ.S COPS1 ;go to state 1 if yes
CMP.B #RSTCODE,D0 ;reset code?
BEQ.S COPS2 ;skip to state 2 if yes
RTS ;else return with the keycode
; State 1 - waiting for mouse data
COPS1 BSR.S ReadCOPS ;get COPS input
MOVE.B D0,MousDx ;save mouse delta-x
BSR.S ReadCOPS ;read and
MOVE.B D0,MousDy ;save mouse delta-y
BSR MouseMovement ;record the mouse movement
CLR D0 ;set mouse flag
RTS ;and exit
; State 2 - waiting for reset code
COPS2 BSR.S ReadCOPS ;get COPS input
CMP.B #$DF,D0 ;reset code <= $DF?
BLS.S @1 ;branch if yes
CMP.B #$EF,D0 ;reset code <= $EF?
BLS.S @2 ;skip if yes
CMP.B #$FB,D0 ;reset code <= $FB
BLO.S @3 ;branch if < $FB
BEQ.S @4 ;branch if = $FB
CMP.B #$FD,D0 ;reset code <= $FD?
BLS.S @3 ;branch if <= $FD
BRA.S @5 ;branch if > $FD
; $00 - $DF Keyboard ID number - save and return to state 0
@1 MOVE.B D0,KeyID ;save new ID
BRA.S COPS0 ;return to general wait
; $E0 - $EF Clock data - save first nibble, and go to state 4
@2 MOVE.B D0,ClockBytes ;save it
BRA.S COPS4 ;and go get rest of data
; $F0 - $FA Reserved --- ignored
; $FC - $FD Clock timer interrupt, keyboard unplugged --- ignored
@3 BRA.S COPS0 ;go back to general wait
; $FB Soft on/off button - go to power-off routine
@4 BRA.S PowerOff ;go shutdown the system
; $FE - $FF COPS failure codes - go to error routine
@5 CMP.B #$FE,D0 ;I/O board COPS?
BNE.S @6
MOVEQ #EIOCOP,D0 ;else set I/O COPS error code
BRA.S @7
@6 MOVEQ #EKBDCOP,D0 ;set keyboard COPS error code
@7 ORI.B #$01,CCR ;set return error indicator
RTS
; State 4 - waiting for clock data; use timeout routine to guard against error
COPS4 MOVEM.L D1-D2/A0-A2,-(SP) ;save regs
LEA ClockBytes+1,A1 ;set ptrs to save area
LEA ClockBytes+6,A2
MOVEQ #5,D1 ;5 more bytes expected
@1 BSR GETDATA ;get COPS data
BCS.S @2 ;skip if any errors
SUBQ #1,D1 ;loop until done
BNE.S @1
@2 MOVEM.L (SP)+,D1-D2/A0-A2 ;restore regs and
BRA.S COPS0 ;go back to general wait
.ENDC ;{USERINT}
;------------------------------------------------------------------------
; ReadCOPS
;
; Routine to get data from COPS. Returns with data in D0.
;
;------------------------------------------------------------------------
ReadCOPS
MOVE.L A0,-(SP)
MOVE.L #VIA1BASE,A0 ;get interface ptr
@1 MOVE.B IFR1(A0),D0 ;poll for data
BTST #1,D0
BEQ.S @1 ;loop until data received
MOVE.B ORA1(A0),D0 ;read
MOVE.L (SP)+,A0 ;and return
RTS
.IF USERINT = 1
;-------------------------------------------------------------------------
; PowerOff - routine to shutdown the system
;-------------------------------------------------------------------------
PowerOff
BTST #DISK,D7 ;disk controller error? CHG023
BNE.S @9 ;skip if yes CHG023
MOVE.L #DISKMEM,A0 ;set ptr for shared memory
BSR.S ENBLDRVS ;enable both drives
MOVE.B #DRV1,DRV(A0) ;eject diskette in drive 1
BSR EJCTDSK
MOVE.B #DRV2,DRV(A0) ;and drive 2
BSR EJCTDSK
MOVE.B #DIE,(A0) ;get Twiggy controller out of memory
BSR CMDCHK ;wait until command taken
@9 BSR4 CONOFF ;turn off contrast CHG003
MOVE.L #ONESEC,D0 ;wait for it to happen CHG003
BSR DELAY ; CHG003
MOVEQ #$21,D0 ;power off, timer off, clock on RM000
BSR COPSCMD ;go do it
BSR KBDDELAY ;wait about 1.7 secs for power-off
BSR SQUAWK ;error if still on
LEA IOBRD,A2
MOVEQ #EIOCOP,D0 ;set error code
BRA TSTXIT ;display error and go back to level1 monitor
;------------------------------------------------------------------------
; Subroutine to enable drives
;------------------------------------------------------------------------
ENBLDRVS
MOVE.B #$88,CMD(A0) ;enable both drives
MOVE.B #ENBLINT,(A0)
BSR CMDCHK
MOVE.L #VIA1BASE,A3 ;and enable FDIR
BCLR #FDIR,DDRB1(A3)
RTS
;------------------------------------------------------------------------
; CHKPOSN
;
; Routine to check mouse position versus active rectangle table.
; If over a rectangle, inverts it and returns with its ID.
; If not over a rectangle, ensures all rectangles not inverted, and
; returns with D0 = 0.
;
; Active rectangle table has following format:
;
; Word 1 : number of entries in table
; Word 2 : ID for first entry, MSB = 1 if inverted on screen
; Next 4 words contain X,Y pixel coordinates for upper left
; and bottom right corners
; Each successive entry follows same format, with 5 words per entry
;
; Register usage:
; A0 = ptr to rectangle table
; D0 = # of entries in table
; D1 = ID for current entry
; D2 = X-coordinate for upper left
; D3 = Y-coordinate for upper left
; D4 = X-coordinate for bottom right
; D5 = Y-coordinate for bottom right
; D6 = X-coordinate for current cursor location
; D7 = Y-coordinate for current cursor location
;
; On exit, D0 = ID code of rectangle cursor is over or
; = 0 if not over any rectangle
;
;-------------------------------------------------------------------------
CHKPOSN MOVEM.L D1-D7/A0,-(SP)
MOVE CrsrX,D6 ;get current cursor location
MOVE CrsrY,D7
LEA RectTable,A0 ;set ptr to table
MOVE (A0)+,D0 ;get count
BEQ.S CHKPXIT ;exit if 0
GETNTRY MOVEM (A0)+,D1-D5 ;else get entry (5 words)
; check if cursor over rectangle
CMP D2,D6 ;CrsrX < upper left X?
BLT.S @1 ;branch if cursor to left of rectangle
CMP D4,D6 ;CrsrX > bottom right X?
BGT.S @1 ;branch if cursor to right of rectangle
CMP D3,D7 ;CrsrY < upper left Y?
BLT.S @1 ;branch if cursor above rectangle
CMP D5,D7 ;CrsrY > bottom right Y?
BGT.S @1 ;branch if cursor below rectangle
BRA.S @3 ;cursor over this entry - go invert it
; not over this entry - check if inverted, then continue through table
@1 TST D1 ;entry inverted?
BPL.S @2 ;skip if not
BSR INVERT ;else go reinvert
@2 SUBQ #1,D0 ;decrement entry count
BNE.S GETNTRY ;check next entry if not done
BRA.S CHKPXIT ;else exit with D0 = 0
; over the rectangle - if not already, invert it and data saved
@3 TST D1 ;already inverted?
BMI.S @6 ;exit if yes
BSR INVERT ;go invert rectangle
; check if any other entries previously inverted
@4 SUBQ #1,D0 ;done?
BEQ.S @6 ;skip if yes
TST (A0)+ ;else check next entry
BMI.S @5 ;skip if inverted
ADDQ #8,A0 ;else bump to next entry
BRA.S @4 ;and continue loop
@5 MOVEM (A0)+,D2-D5 ;get coordinates
BSR INVERT ;and go reinvert and then exit
;since at most one rect inverted
@6 MOVE D1,D0 ;set return code
CHKPXIT MOVEM.L (SP)+,D1-D7/A0
RTS ;and exit
;------------------------------------------------------------------------
; CHKINPUT
;
; Routine to check keyboard input versus active rectangle table.
; If rectangle selected, inverts it and returns.
;
; Active rectangle table has following format:
;
; Word 1 : number of entries in table
; Word 2 : ID for first entry, MSB = 1 if inverted on screen
; Next 4 words contain X,Y pixel coordinates for upper left
; and bottom right corners
; Each successive entry follows same format, with 5 words per entry
;
; Register usage:
; A0 = ptr to rectangle table
; D0 = keyboard input
; D1 = ID for current entry
; D2 = X-coordinate for upper left
; D3 = Y-coordinate for upper left
; D4 = X-coordinate for bottom right
; D5 = Y-coordinate for bottom right
; D6 = # of entries in table
;
;-------------------------------------------------------------------------
CHKINPUT
MOVEM.L D1-D6/A0,-(SP)
LEA RectTable,A0 ;set ptr to table
MOVE (A0)+,D6 ;get count
RDENTRY MOVEM (A0)+,D1-D5 ;get entry (5 words)
CMP.B D0,D1 ;match with keyboard input?
BEQ.S @1 ;skip if yes
SUBQ #1,D6 ;else loop thru all entries
BNE.S RDENTRY
BRA.S @2 ;skip to exit
@1 BSR.S INVERT ;go invert rectangle
@2 MOVEM.L (SP)+,D1-D6/A0 ;restore regs
RTS ;and return
;-----------------------------------------------------------------------------
; INVERT
;
; Routine to invert buttons, menu or icon. Computes upper left address,
; width and heigth of rectangle, then calls INVERSE and other routines
; as needed.
;
; Register inputs: D2 = upper left X-coordinate
; D3 = upper left Y-coordinate
; D4 = bottom right X-coordinate
; D5 = bottom right Y-coordinate
; A0 = ptr to start of next entry in rectangle table
;
;-----------------------------------------------------------------------------
INVERT MOVEM.L D0-D4/A1,-(SP)
BSR CursorHide ;remove cursor
BCHG #7,-10(A0) ;flip the invert bit indicator for entry
MOVE D4,D0 ;compute width
SUB D2,D0
DIVU #8,D0 ;convert to bytes
MOVE D5,D1 ;compute height in pixel rows
SUB D3,D1
ADDQ #1,D1 ;bump by 1 to do bottom line also
SUBA.L A1,A1 ;use for upper left address
LSR #3,D2 ;divide pixel column by 8 for bytes
ADD D2,A1 ;add to address
MOVEQ #MaxX/8,D4 ;bytes per row on screen
MULU D4,D3 ; * pixel row
ADD D3,A1 ;address of upper left corner
BTST #MENU,STATFLGS ;doing menu item?
BEQ.S @0 ;skip if not
ADDA #ROWBYTES,A1 ;else add 1 scan line to avoid menu RM000
; bar line inversion
SUBQ #1,D1 ;and decr length to avoid inverting bottom line
; of menu box
@0 MOVEQ #-1,D2 ;set fill pattern
MOVEM.L D0-D2/A1,-(SP) ;save args
BSR INVERSE ;invert it
MOVEM.L (SP)+,D0-D2/A1 ;restore args
BTST #BTN,STATFLGS ;doing buttons?
BEQ.S @1 ;skip if not
BSR DRAWBUTN ;redraw button
BRA.S @9 ;and exit
@1 BTST #MENU,STATFLGS ;doing menu?
BEQ.S @9 ;skip if not
BSR DRAWSIDES ;just redraw sides
@9 BSR CursorDisplay ;redisplay cursor
MOVEM.L (SP)+,D0-D4/A1 ;restore regs
RTS ;and return
.PAGE
;-----------------------------------------------------------------------------
;
; Hardware Interface for the Mouse
;
; Written by Rick Meyers
; (c) Apple Computer Incorporated, 1983
;
; The routines below provide an assembly language interface to the mouse.
; Input parameters are passed in registers, output parameters are returned
; in registers. Unless otherwise noted, all registers are preserved.
;
; The Mouse
;
; The mouse is a pointing device used to indicate screen locations. Mouse
; coordinates are located between pixels on the screen. Therefore, the
; X-coordinate can range from 0 to 720, and the Y-coordinate from 0 to 364.
; The initial mouse location is 0,0.
;
; Mouse Scaling
;
; The relationship between physical mouse movements and logical mouse
; movements is not necessary a fixed linear mapping. Three alternatives
; are available: 1) unscaled, 2) scaled for fine movement and 3) scaled
; for coarse movement.
;
; When mouse movement is unscaled, a horizontal mouse movement of x units
; yields a change in the mouse X-coordinate of x pixels. Similiarly, a
; vertical movement of y units yields a change is the mouse Y-coordinate
; of y pixels. These rules apply independent of the speed of the mouse
; movement.
;
; When mouse movement is scaled, horizontal movements are magnified by 3/2
; relative to vertical movements. This is intended to compensate for the
; 2/3 aspect ratio of pixels on the screen. When scaling is in effect, a
; distinction is made between fine (small) movements and coarse (large)
; movements. Fine movements are slightly reduced, while coarse movements
; are magnified. For scaled fine movements, a horizontal mouse movement of
; x units yields a change in the X-coordinate of x pixels, but a vertical
; movement of y units yields a change of (2/3)*y pixels. For scaled coarse
; movements, a horizontal movement a x units yields a change of (3/2)*x
; pixels, while a vertical movements of y units yields a change of y pixels.
;
; The distinction between fine movements and coarse movements is determined
; by the sum of the x and y movements each time the mouse location is
; updated. If this sum is at or below the 'threshold', the movement is
; considered to be a fine movement. Values of the threshold range from 0
; (which yields all coarse movements) to 256 (which yields all fine
; movements). Given the default mouse updating frequency, a threshold of
; about 8 (threshold's initial setting) gives a comfortable transition between
; fine and coarse movements.
;---------------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;
; Mouse Movement
;
; This routine is called by the GETINPUT routine when the COPS has
; reported mouse movement. All registers are preserved.
;
;
; Register Assignments:
;
; D0 -- Mouse X-Coordinate (integer)
; D1 -- Mouse Y-Corrdinate (integer)
; D2 -- Mouse Dx (integer)
; D3 -- Mouse Dy (integer)
;
MouseMovement MOVEM.L D1-D5,-(SP) ; save registers
MOVE.W MousX,D0 ; mouse X-coordinate
MOVE.W MousY,D1 ; mouse Y-coordinate
MOVE.B MousDx,D2 ; mouse Dx (byte)
EXT.W D2 ; mouse Dx (integer)
MOVE.B MousDy,D3 ; mouse Dy (byte)
EXT.W D3 ; mouse Dy (integer)
Scale MOVE.W D2,D4 ; mouse Dx
BGE.S @1 ; branch if >= 0
NEG.W D4 ; ABS(mouse Dx)
@1 MOVE.W D3,D5 ; mouse Dy
BGE.S @2 ; branch if >= 0
NEG.W D5 ; ABS(mouse Dy)
@2 ADD.W D5,D4 ; ABS(Dx) + ABS(Dy)
SUB.W MousThresh,D4 ; - MouseThreshold
BGT.S Coarse ; branch if coarse movement
Fine ADD.W D2,D0 ; new X-coordinate (scale 1)
MOVE.W D3,D2 ; save Dy
ADD.W D3,D3 ; Dy*2
ADD.W D3,D3 ; Dy*4
ADD.W D2,D3 ; Dy*5
ADDQ #2,D3 ; (Dy*5)+2
BLT.S @3 ; branch if negative
ADDQ #3,D3 ; (Dy*5)+5
@3 ASR.W #3,D3 ; Dy*(5/8) with rounding
ADD.W D3,D1 ; new Y-coordinate (scale 5/8)
BRA.S Bounds ; continue
Coarse ADD.W D3,D1 ; new Y-coordinate (scale 1)
MOVE.W D2,D3 ; save Dx
ADD.W D3,D2 ; Dx*2
ADD.W D3,D2 ; Dx*3
BLT.S @4 ; branch if negative
ADDQ.W #1,D2 ; (Dx*3)+1
@4 ASR.W #1,D2 ; Dx*(3/2) with rounding
ADD.W D2,D0 ; new X-coordinate (scale 3/2)
Bounds TST.W D0 ; new X-coordinate >= 0
BGE.S @5 ; branch if >= 0
MOVE.W #0,D0 ; minimum X of 0
@5 CMP.W #MaxX,D0 ; new X-coordinate <= 720
BLE.S @6 ; branch if <= 720
MOVE.W #MaxX,D0 ; maximum X of 720
@6 TST.W D1 ; new Y-coordinate >= 0
BGE.S @7 ; branch if >= 0
MOVE.W #0,D1 ; minimum Y of 0
@7 CMP.W #MaxY,D1 ; new Y-coordinate <= 364
BLE.S @8 ; branch if <= 364
MOVE.W #MaxY,D1 ; maximum Y of 364
@8 MOVE.W D0,MousX ; update Mouse X-coordinate
MOVE.W D1,MousY ; update Mouse Y-coordinate
MOVE.W D0,CrsrX ; also update cursor coordinates
MOVE.W D1,CrsrY
MOVEM.L (SP)+,D1-D5 ; restore registers
RTS ; return
;-----------------------------------------------------------------------------
;
; Routine to initialize mouse handling
;
;-----------------------------------------------------------------------------
MousInit
MOVE.W #360,MousX ; set inital mouse location
MOVE.W #182,MousY ; to center of screen
MOVE.W #8,MousThresh ; set scaling threshold
MOVEQ #$7C,D0 ; and enable mouse data
BSR COPSCMD
RTS
;-----------------------------------------------------------------------------
;
; Hardware Interface for the Cursor
;
; Written by Rick Meyers
; (c) Apple Computer Incorporated, 1983
;
;
; The routines below provide an assembly language interface to the cursor.
; Input parameters are passed in registers, output parameters are returned
; in registers. Unless otherwise noted, all registers are preserved.
;
; The Cursor
;
; The cursor is a small image that is displayed on the screen. It's shape
; is specified by two bitmaps, called 'data' and 'mask'. These bitmaps are
; 16 bits wide and from 0 to 32 bits high. The rule used to combine the
; bits already on the screen with the data and mask is
;
; screen <- (screen and (not mask)) xor data.
;
; The effect is that white areas of the screen are replaced with the cursor
; data. Black areas of the screen are replaced with (not mask) xor data.
; If the data and mask bitmaps are identical, the effect is to 'or' the data
; onto the screen.
;
; The cursor has both a location and a hotspot. The location is a position
; on the screen, with X-coordinates of 0 to 720 and Y-coordinates of 0 to 364 .
; The hotspot is a position within the cursor bitmaps, with X- and Y-coordi-
; nates ranging from 0 to 16. The cursor is displayed on the screen with it's
; hotspot at location. If the cursor's location is near an edge of the screen,
; the cursor image may be partially or completely off the screen.
;
;------------------------------------------------------------------------------
;
; Routine: CursorInit
; Arguments: None
; Function: Sets up the initial defaults used by the ROM cursor. Initial
; position is set for center of the screen.
;
;------------------------------------------------------------------------------
CursorInit MOVE.W #0,CrsrHotX ; cursor hotspot X-coordinate
MOVE.W #0,CrsrHotY ; cursor hotspot Y-coordinate
MOVE.W #16,CrsrHeight ; cursor hieght, 0-32
MOVE.W #360,CrsrX ; initial cursor X-coordinate
MOVE.W #182,CrsrY ; initial cursor Y-coordinate
BSR.S MousInit ; init mouse for cursor control
RTS ; return
;-----------------------------------------------------------------------------
;
; Cursor Hide and Display
;
; Care must be taken when updating the screen image which is 'under' the
; cursor. The simplest approach is to remove the cursor from the screen
; (hide), do the screen modification, then redisplay the cursor (display).
;
; Each hide operation must be followed by a corresponding display
; operation. The operations are paired and can be nested. The first of a
; series of hides removes the cursor from the screen; it's corresponding
; display redisplays the cursor. Intervening operations have no apparent
; effect.
;
;------------------------------------------------------------------------------
;---------------------------------------------------------------------------------
; Routine: CursorHide
; Arguments: None
; Function: Remove the cursor from the screen. Note that every call to
; CursorHide must be followed by exactly one call to CursorDisplay.
;---------------------------------------------------------------------------------
CursorHide MOVEM.L D0-D1/A0-A1,-(SP) ; save registers
LEA SavedData,A0 ; saved data address
MOVE.L SavedAddr,A1 ; saved data screen address
MOVE.W SavedRows,D0 ; rows of saved data
MOVE.W #MaxX/8,D1 ; bytes per row on screen
BRA.S @2 ; test of rows=0
@1 MOVE.L (A0)+,(A1) ; from saved to screen
ADD.W D1,A1 ; screen address of next row
@2 DBF D0,@1 ; loop 'SavedRows' times
MOVEM.L (SP)+,D0-D1/A0-A1 ; restore registers
RTS ; return
;------------------------------------------------------------------------------
;
; Routine: CursorDisplay
; Arguments: none
; Function: Redisplay the cursor. Note that every call to CursorDisplay
; must be preceeded by exactly one call to CursorHide.
;
; Register Assignments:
;
; D0 -- saved data X-coordinate, cursor data
; D1 -- saved data Y-coordinate, cursor mask
; D2 -- left shift count
; D3 -- 32-bit mask
; D4 -- rows of saved data
; D5 -- bytes per row on screen
;
; A0 -- saved data address
; A1 -- saved data screen address
; A2 -- cursor data address
; A3 -- cursor mask address
;------------------------------------------------------------------------------
CursorDisplay MOVEM.L D0-D5/A0-A3,-(SP) ; save registers
LEA SavedData,A0 ; saved data address
MOVE.L ScrnBase,A1 ; screen memory address
LEA CrsrData,A2 ; cursor data bitmap address
LEA CrsrMask,A3 ; cursor mask bitmap address
MOVE.W CrsrHotX,D0 ; cursor hotspot X-coordinate
MOVE.W CrsrHotY,D1 ; cursor hotspot Y-coordinate
MOVE.W CrsrHeight,D4 ; cursor height
; Compute and bounds check the X-coordinate of the data under the cursor.
@11 SUB.W CrsrX,D0 ; cursor X-coordinate
NEG.W D0 ; - cursor hotspot X-coordinate
MOVE.W D0,D2 ; upper left X-coordinate
AND.W #$000F,D2 ; bit offset within word
NEG.W D2 ; negated and converted to
ADD.W #16,D2 ; left shift count
CLR.L D3 ; 32-bit mask RM000
NOT D3 ; D3 = $0000FFFF RM000
LSL.L D2,D3 ; shifted into position
AND.W #$FFF0,D0 ; upper left X-coord rounded down
BGE.S @0 ; branch if >= 0
MOVE.W #0,D0 ; minimum upper left X-coord of 0
LSL.L #8,D3 ; adjust 32-bit mask
LSL.L #8,D3 ; adjust 32-bit mask
ADD.W #16,D2 ; adjust left shift count
@0 CMP.W #MaxX-32,D0 ; upper left X-coord <= 720-32
BLE.S @2 ; branch if <= 720-32
CMP.W #MaxX,D0 ; cursor off right edge ?
BNE.S @1 ; branch if not off right edge
MOVEQ #0,D3 ; mask off all bits
@1 MOVE.W #MaxX-32,D0 ; maximum X-coord of 720-32
LSR.L #8,D3 ; adjust 32-bit mask
LSR.L #8,D3 ; adjust 32-bit mask
ADD.W #16,D2 ; adjust left shift count
; Compute and bounds check the Y-coordinate of the data under the cursor.
@2 SUB.W CrsrY,D1 ; cursor Y-coordinate
NEG.W D1 ; - cursor hotspot Y-coordinate
BGE.S @3 ; branch if upper left Y >= 0
ADD.W D1,D4 ; decrease rows of saved data
ADD.W D1,D1 ; double for byte count
SUB.W D1,A2 ; increase cursor data address
SUB.W D1,A3 ; increase cursor mask address
MOVE.W #0,D1 ; minimum upper left Y of 0
BRA.S @4 ; continue
@3 MOVE.W #MaxY,D5 ; maximum Y-coordinate
SUB.W D4,D5 ; - cursor height
CMP.W D5,D1 ; cursor bottom <= 364-CrsrHeight ?
BLE.S @5 ; branch if <= 364-CrsrHeight
MOVE.W #MaxY,D4 ; last row on screen
SUB.W D1,D4 ; adjust rows of saved data
@4 TST.W D4 ; rows of saved data >= 0 ?
BGE.S @5 ; branch if >= 0
MOVE.W #0,D4 ; minimum rows of saved data
@5 MOVE.W D0,SavedX ; saved data X-coordinate
MOVE.W D1,SavedY ; saved data Y-coordinate
MOVE.W D4,SavedRows ; rows of saved data
; Display the cursor on the screen.
LSR.W #3,D0 ; convert X-coord to bytes
ADD.W D0,A1 ; and add to screen address
MOVEQ #MaxX/8,D5 ; bytes per row on screen
MULU D5,D1 ; * Y-coord
ADD.L D1,A1 ; added to screen address
MOVE.L A1,SavedAddr ; saved data screen address
BRA.S @7 ; test for rows=0
@6 MOVE.W (A2)+,D0 ; cursor data
ROL.L D2,D0 ; shift to proper bit position
AND.L D3,D0 ; eliminate unwanted bits
MOVE.W (A3)+,D1 ; cursor mask
ROL.L D2,D1 ; shift to proper bit position
AND.L D3,D1 ; eliminate unwanted bits
NOT.L D1 ; invert cursor mask
MOVE.L (A1),(A0)+ ; from screen to saved data
AND.L D1,(A1) ; screen and (not mask)
EOR.L D0,(A1) ; xor cursor data
ADD.W D5,A1 ; screen address of next row
@7 DBF D4,@6 ; loop 'SavedRows' times
MOVEM.L (SP)+,D0-D5/A0-A3 ; restore registers
RTS ; return
.ENDC ;{USERINT}
.IF AAPL = 1
.PAGE
;-------------------------------------------------------------------------
; Testing complete - reset default NMI vector and display ROM #'s
;-------------------------------------------------------------------------
NMISET
LEA NMI,A6 ;restore NMI ptr
MOVE.L A6,NMIVCT
; Reset to first video page (for compatibility w/ old software)
RSTOR MOVE.L MINMEM,D0 ;get starting memory address
LSR.L #8,D0 ;convert to 32K multiple
LSR.L #7,D0
MOVE D0,VIDLTCH ;and set video page latch
CLR.L SCRNBASE ;and set base screen address
; Display ROM version #'s and OK msg if no errors
TST.L STATUS ;any errors?
BNE.S @1 ;skip if yes
LEA INITMSG,A3 ;else display OK msg
BSR DSPMSGR
@1 BSR DSPROMS ;display ROM versions
; And restore ROM Monitor environment
MOVE.L #STKBASE,SP ;RESTORE STACK POINTER
LEA BERR,A3 ;and bus error vector
MOVE.L A3,BUSVCTR
; MOVEQ #FIRSTROW,D5 ;AND CURSOR PTRS
; MOVEQ #FIRSTCOL,D6
.PAGE
;-------------------------------------------------------------------------
; APPLE MONITOR CODE - ENABLES COMMUNICATION VIA APŠLE ][
@4 TST.W D4 ; rows of saved data >= 0 ?
BGE.S @5 ; branch if >= 0
MOVE.W #0,D4 ; minimum rows of saved data
@5 MOVE.W D0,SavedX ; saved data X-coordinate
MOVE.W D1,SavedY ; saved data Y-coordinate
MOVE.W D4,SavedRows ; rows of saved data
; Display the cursor on the screen.
LSR.W #3,D0 ; convert X-coord to bytes
ADD.W D0,A1 ; and add to screen address
MOVEQ #MaxX/8,D5 ; bytes per row on screen
MULU D5,D1 ; * Y-coord
ADD.L D1,A1 ; added to screen address
MOVE.L A1,SavedAddr ; saved data screen address
BRA.S @7 ; test for rows=0
@6 MOVE.W (A2)+,D0 ; cursor data
ROL.L D2,D0 ; shift to proper bit position
AND.L D3,D0 ; eliminate unwanted bits
MOVE.W (A3)+,D1 ; cursor mask
ROL.L D2,D1 ; shift to proper bit position
AND.L D3,D1 ; eliminate unwanted bits
NOT.L D1 ; invert cursor mask
MOVE.L (A1),(A0)+ ; from screen to saved data
AND.L D1,(A1) ; screen and (not mask)
EOR.L D0,(A1) ; xor cursor data
ADD.W D5,A1 ; screen address of next row
@7 DBF D4,@6 ; loop 'SavedRows' times
MOVE.B #1,CrsrVisible ; cursor visible
MOVEM.L (SP)+,D0-D5/A0-A3 ; restore registers
@8 MOVE.B #0,CrsrBusy ; cursor change complete
RTS ; return
;------------------------------------------------------------------------------
;
; Routine: CursorInit
; Arguments: none
; Function: Definately redisplay the cursor, independent of previous calls
; to CursorHide, CursorShield and CursorObscure. Also sets up
; the initial defaults used by the ROM cursor.
;
CursorInit MOVE.L D0,-(SP) ; save registers
MOVE.W #0,CrsrHotX ; cursor hotspot X-coordinate
MOVE.W #0,CrsrHotY ; cursor hotspot Y-coordinate
MOVE.W #16,CrsrHeight ; cursor hieght, 0-32
MOVE.W #0,CrsrX ; initial cursor X-coordinate
MOVE.W #0,CrsrY ; initial cursor Y-coordinate
MOVE.B #0,CrsrObscured ; 0=not obscured, else=obscured
MOVE.B #0,CrsrHidden ; <= 0 implies hidden
MOVE.B #0,CrsrVisible ; 0 = not visible, else=visible
MOVE.B #1,CrsrTracking ; enable cursor tracking
BSR CursorDisplay ; display the cursor
MOVE.L (SP)+,D0 ; restore registers
RTS ; return
.ENDC ;{USERINT}
.IF AAPL = 1
.PAGE
;-------------------------------------------------------------------------
; Testing complete - reset default NMI vector and display ROM #'s
;-------------------------------------------------------------------------
NMISET
MOVE.B (A0)+,D0 ; ELSE EXAMINE MEMORY
BSR4 CHKSUM ;ADD TO CHECKSUM
BSR2 PUT ; AND SEND TO PIA
BRA.S EXMLOOP ; LOOP TILL COUNT EXHAUSTED
CMDDONE BSR4 ECHOSUM ;RETURN CHECKSUM
BRA GETCMD ;AND GO WAIT FOR NEXT CMD
DEPOSIT BSR4 CHKHDR ;GO GET AND CHECK ADDRESS, COUNT FIELDS
CLR.L D7 ;CLEAR FOR DATA CHECKSUM USE
DEMLOOP SUBQ #1,D1 ; DEC COUNT
BCS CMDDONE ; IF DONE, SEND REPLY
BSR2 GET ; ELSE GET BYTE FROM PIA
MOVE.B D0,(A0) ; AND DEPOSIT INTO MEMORY
CMPA.L #IOSPACE,A0 ;CHECK IF IN IO SPACE
BCC.S @2 ;SKIP READ IF YES
MOVE.B (A0)+,D0 ;ELSE READ BACK
@2 BSR4 CHKSUM ;UPDATE CHECKSUM
BRA.S DEMLOOP ; LOOP TILL COUNT EXHAUSTED
;
; READ - read a location (over and over)
;
READ BSR4 GETADDR ; fetch address to A0
BSR4 GETKNT ; and count to D1
@1 MOVE.B (A0),D0 ; read once
SUBQ #1,D1
BNE @1 ; and loop til done
BRA REPLY ; reply is fetched byte
;
; WRITE - write fixed location (many times)
;
WRITE BSR4 GETADDR ; fetch address
BSR4 GETKNT ; and count
BSR2 GET ; and data byte
@1 MOVE.B D0,(A0) ; do the write
SUBQ #1,D1 ; and loop until done
BNE.S @1
BRA REPLY
;
; RDMULTI - Read sweep of locations
;
RDMULTI BSR4 GETADDR ; get params
BSR4 GETKNT
@1 TST (A0)+
SUBQ #1,D1
BNE @1
BRA REPLY
;
; WRMULTI - Write sweep of locations
;
WRMULTI BSR4 GETADDR
BSR4 GETKNT
@1 MOVE A0,(A0)+
SUBQ #1,D1
BNE @1
BRA REPLY
;
; Routine to do check command, address and count fields
;
CHKHDR MOVE.L A4,A3 ;SAVE RETURN ADDRESS
BSR4 GETADDR ;GET 4 BYTE ADDRESS IN A0
BSR4 GETKNT ;GET 2 BYTE COUNT IN D1
CLR.L D0
MOVE.L A0,D2 ;GET ADDRESS DATA
MOVEQ #8,D3 ;SET SHIFT COUNT
MOVEQ #4,D4 ;SET LOOP COUNT
@1 ROL.L D3,D2 ;GET ADDRESS BYTE
MOVE.B D2,D0
BSR4 CHKSUM ;GO ADD TO CHECKSUM
SUBQ #1,D4
BNE.S @1 ;LOOP UNTIL DONE
CLR.L D2
MOVE D1,D2 ;GET COUNT DATA
ROR D3,D2 ;GET HIGH BYTE
MOVE.B D2,D0
BSR4 CHKSUM ;ADD TO CHECKSUM
ROL D3,D2 ;GET LOW BYTE
MOVE.B D2,D0
BSR4 CHKSUM ;ADD TO CHECKSUM
BSR4 ECHOSUM ;ECHO RESULT TO APPLE
BSR2 GET ;GET APPLE'S REPLY
TST.B D0 ;OK?
BNE GETCMD ;ABORT IF NO
MOVE.L A3,A4 ;ELSE GET RTRN ADDRESS
RTS4
;
; Routine to calculate checksum
; Assumes D0 = byte to add to checksum
; D7 = checksum word
;
CHKSUM ANDI #$00FF,D0 ;ENSURE VALID DATA
ADD D0,D7 ;ADD TO CHECKSUM
ROL #1,D7 ;ROTATE FOR NEXT USE
RTS4
;
; Routine to send checksum word in D7 to APPLE
;
ECHOSUM MOVE D7,D0 ;GET IT
BSR2 PUT ;OUTPUT LOW BYTE
LSR #8,D0
BSR2 PUT ;OUTPUT HIGH BYTE
RTS4
.ENDC
.ENDC ;{ROM4K}