        .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    #<RBYTES*10>,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    #<RBYTES*10>,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  #<DBOXHIGH*ROWBYTES>,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}