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