        .PAGE        .LIST;-------------------------------------------------------------------------;  All is OK - check for boot device and then do bootstrap;-------------------------------------------------------------------------DOBOOT  BSR     CURSORINIT      ;init cursor/mouseBOOTCHK        CLR.L   D0	        ;clear for use        BTST    #ALTBOOT,D7     ;check if alternate boot command rcvd        BEQ.S   @1	        ;skip if no        MOVE.B  BOOTDVCE,D0     ;get alternate boot code       .IF     BURNIN = 1        CMP.B   #PC,D0	        ;power-cycle mode?        BNE.S   DVCECHK	        ;if no, go determine device        BSR     SAV2PM	        ;if yes, save in parameter memory       .ENDC        BRA.S   DVCECHK	        ;and go determine device@1        .IF USERINT = 1        BTST    #BTMENU,D7      ;boot menu wanted?        BNE     BOOTMENU        ;skip if yes        .ENDC        BSR     CHKPM	        ;next step is to check parameter memory        .IF  AAPL = 1        BCS     NMISET	        ;skip if not to default boot        .ELSE        BCC.S   @2	        ;skip if valid;  set default boot        TST.B   SYSTYPE	        ;else check if Lisa 1			        CHG030        BEQ.S   @5	        ;skip if yes				        CHG030        MOVEQ   #1,D2	        ;else set wait flag			        CHG030        BSR     CHKPROFILE      ;and go check if hard disk attached	        CHG030        BEQ.S   @5	        ;skip if yes to do boot from hard disk	        CHG030        MOVEQ   #TWIG2,D0       ;else set for boot from floppy		        CHG030        BRA.S   @3	        ;					        CHG030@5      MOVEQ   #PROFILE,D0     ;else if not valid do default boot from Profile        BRA.S   @3        .ENDC@2      MOVE.B  DVCCODE,D0      ;else read device code        LSR.B   #4,D0	        ;rotate to low nibble        BRA.S   DVCECHK        .IF  NEWTWIG = 0        BSR     EXPAND	        ;convert id to keycode        .ENDC@3        .IF  ROM16K = 1;  Do special check for Applenet and I/O test cards        MOVE    #TSTCRD,D1      ;search first for a bootable test card        MOVE    #TSTQUAL,D4        BSR     SEARCH	        ;go do search        BNE.S   DVCECHK	        ;skip if not found        MOVE    D2,D3	        ;else save its id        MOVE    #APPLENET,D1    ;next search for an Applenet card        MOVE    #APPLQUAL,D4        BSR     SEARCH        BEQ.S   @4	        ;skip if found to boot from it (DMT need)        MOVE    D3,D2	        ;else do boot from I/O test card (DIAG need)        BPL.S   DVCECHK	        ; unless card boot bit not set		        CHG012@4        MULU    #3,D2	        ;convert to boot id        MOVE    D2,D0	        ;and set boot id for appropriate slot        .ENDC;  Alternate boot desired - check whichDVCECHK MOVE.B  D0,BOOTDVCE     ;save for later reference        .IF TWIGGY = 1        TST.B   D0	        ;boot from upper drive?		        CHG009        BNE.S   @1	        ;no - go to next check        TST.B   SYSTYPE	        ;check system type		        CHG009        BEQ.S   @11	        ;skip if Lisa 1.0		        CHG009@10     BRA     PROBOOT	        ;else do Pepsi boot		        CHG009@11     MOVE.B  #DRV1,D0        ;else set drive #		        CHG009        BRA.S   @2	        ;and go do boot@1      CMP.B   #TWIG2,D0       ;boot from lower drive?		        CHG009        BNE.S   @3	        ;skip if no        MOVE.B  #DRV2,D0        ;else set drive #@2      BRA     TWGBOOT	        ;and go boot        .ENDC@3        .IF PROFLE = 1        CMP.B   #PROFILE,D0     ;boot from Profile?        BEQ.S   @10	        ;yes - go do it			        CHG009        .ENDC        CMP.B   #IO1PORT2,D0    ;boot from slot 1, ports 1-2?        BGT.S   @4	        ;skip if not        MOVE.L  #SLOT1L,A1      ;set slot address        BRA.S   @9	        ;and go do boot@4      CMP.B   #IO2PORT2,D0    ;boot from slot 2, ports 1-2?        BGT.S   @5	        ;skip if not        MOVE.L  #SLOT2L,A1      ;set slot address        BRA.S   @9	        ;and go do boot@5      CMP.B   #IO3PORT2,D0    ;boot from slot 3, ports 1-2?        BGT.S   @6	        ;skip if not        MOVE.L  #SLOT3L,A1      ;set slot address@9      BRA     IOSBOOT	        ;and go do boot@6        .IF     BURNIN = 1        CMP.B   #PC,D0	        ;power-cycle?        BEQ     CHKPASS	        ;go do cycling        .ENDC        .IF  ROM4K = 0@7      CMP.B   #MON,D0	        ;abort boot?        BNE.S   LSTCHK	        ;skip if no match        .IF  USERINT = 1        BCLR    #NORSTRT,STATFLGS ;allow restart option but        BSET    #NOCONT,STATFLGS  ; no CONTINUE button for direct to monitor jump        BSR     CLRMENU		  ;clear menu bar and        BSR     MAKEPCALRT	  ; open alert box for monitor or power cycling        .ENDC        .IF  BURNIN = 1;  Check if completing power-cycling operation        .IF  DEBUG = 0        LEA     PMERR,A3        ;set vector for parameter mem error        MOVE.L  A3,BUSVCTR        .ENDC        BSR     CHKPM	        ;check validity of parameter memory        BCS.S   PMEXIT	        ;skip if not        MOVE.B  DVCCODE,D0      ;get boot code        LSR.B   #4,D0	        ;shift to lower nibble        .IF     NEWTWIG = 0        BSR     EXPAND	        ;convert to keycode        .ENDC        CMPI.B  #PC,D0	        ;exiting from power-cycling?        BNE.S   PMEXIT	        ;skip if no        CLR.B   DVCCODE	        ;else reset boot and        BCLR    #6,MEMCODE      ; memory test indicators        LEA     LOOPMSG,A3      ;display loop count        BSR     DSPMSG        MOVE.L  #LCNTHI,A0      ;set ptr to loop count        MOVEP   (A0),D0	        ;get it        MOVEQ   #4,D1	        ;set # of digits to display        BSR     OUTCHR	        ;and do display        MOVEQ   #PCCOL,D6       ;reset col for proper left margin        BSR     DSPCLK	        ;display final clock value        BSR     TWGDSP	        ;and display Twiggy error count;  Normal exitPMEXIT        .IF  DEBUG = 0        BSR     SETBUSVCT       ;restore normal bus error vector        RM000        .ENDC		        ;{debug}        .ENDC		        ;{BURNIN}        BRA     MONITOR	        ;and go to monitor        .IF  BURNIN = 1;  Bus error handler for parameter memory errorPMERR   LEA     PMMSG,A3        ;setup error message        LEA     IOBRD,A2        ;and icon        CLR.L   D0	        ;no error code        BRA     INITMON	        ;exit to monitor        .ENDC		        ;{BURNIN}        .ENDC		        ;{ROM4K}LSTCHK        .IF  AAPL = 1        CMP.B   #APPLE,D0       ;Apple boot?        BEQ     NMISET	        ;exit if yes        .ENDC        .IF  USERINT = 0        LEA     BADBOOT,A3      ;else display error msg        BSR     DSPMSGR        BRA     MONITOR	        ;go to monitor        .ELSE        BSR     SQUAWK	        ;else sound error tone        BRA     BOOTMENU        ;and go to boot menu        .ENDC        .PAGE;-------------------------------------------------------------------------;  Subroutine to check parameter memory validity.  Calls generalized;  verify checksum routine.;-------------------------------------------------------------------------CHKPM   MOVEM.L D0-D1/A0,-(SP)  ;save regs        MOVEA.L #PMSTRT,A0      ;set starting ptr        MOVE    #PMWRDS-1,D0    ;and # of words to check        MOVE    D0,D1	        ;set for shared memory        BSR.S   VFYCHKSM        ;and go do checksum@1      MOVEM.L (SP)+,D0-D1/A0  ;restore regs        RTS        .IF BURNIN = 1;-------------------------------------------------------------------------;  Subroutine to save boot device code to parameter memory.;-------------------------------------------------------------------------SAV2PM  MOVEM.L D0-D1/A0,-(SP)  ;save regs        .IF     NEWTWIG = 0        BSR     XLATE	        ;convert keycode to boot id        MOVE.B  D2,D0        .ENDC        LSL.B   #4,D0	        ;rotate device code to upper nibble        MOVE.B  DVCCODE,D1      ;read current setting        ANDI.B  #$0F,D1	        ;clear device indicator        OR.B    D1,D0	        ;save other data        MOVE.B  D0,DVCCODE      ;and write new device code;  also set for full memory test        BSET    #6,MEMCODE      ;ensure memory test indicator set;  then compute new checksum        MOVEA.L #PMSTRT,A0      ;compute new checksum        MOVEQ   #PMWRDS-2,D0    ;leaving out checksum word        BSR.S   WRTSUM@2      MOVEM.L (SP)+,D0-D1/A0  ;restore regs        RTS;----------------------------------------------------------------------;  Subroutine to write new checksum to parameter memory area;----------------------------------------------------------------------WRTSUM  MOVE    D0,D1	        ;set for shared memory        BSR.S   VFYCHKSM        NOT     D3	        ;compute 2's complement        ADDQ    #1,D3        MOVEP   D3,(A0)	        ;write as new checksum        RTS        .ENDC;-------------------------------------------------------------------------;  Subroutine to verify 16 bit checksum validity for memory contents.;;  Inputs Required:  A0 = starting address for verify;		     D0 = # of words-1 to read;		     D1 = 0 for regular memory (uses MOVE.W);		        = nonzero for shared memory (uses MOVEP);;  Outputs:	     Carry bit set if computed checksum not 0.;		     D2 = expected checksum  (last word read);		     D3 = computed checksum;-------------------------------------------------------------------------VFYCHKSM        CLR.L   D2	        ;clear regs for use        CLR.L   D3CKLOOP  TST     D1	        ;shared memory?        BEQ.S   @1	        ;skip if no        MOVEP   (A0),D2	        ;else read alternate bytes        ADDQ.L  #4,A0	        ;bump address        BRA.S   @2	        ;skip to do checksum@1      MOVE    (A0)+,D2        ;read words@2      ADD     D2,D3	        ;add to computed checksum        ROL     #1,D3	        ;rotate for better effectiveness        DBF     D0,CKLOOP       ;loop until done        TST     D3	        ;expected result = 0        BEQ.S   CKXIT        ORI.B   #$01,CCR        ;else set error indicatorCKXIT   RTS        .IF     NEWTWIG = 0;-------------------------------------------------------------------------;  Subroutine to expand boot id read from parameter memory to keycode;-------------------------------------------------------------------------EXPAND  LEA     KEYTBL,A2       ;set ptrs to keycode table        LEA     TBLEND,A3        CLR.L   D2	        ;use for search id@1      CMP.B   D2,D0	        ;check for match        BEQ.S   @2	        ;skip if yes        ADDQ    #1,D2	        ;incr search id        ADDQ.L  #1,A2	        ;bump table ptr        CMPA.L  A2,A3	        ;at end?        BNE.S   @1	        ;loop if not        MOVE.B  #APPLE,D0       ;else set for default boot        BRA.S   @3	        ;and go to exit@2      MOVE.B  (A2),D0	        ;get keycode@3      RTS        .ENDC        .IF  USERINT = 1;-------------------------------------------------------------------------;  Subroutine to expand boot id read from parameter memory to keycode;  Returns with keycode in D0.;-------------------------------------------------------------------------EXPAND  MOVEM.L D2/A2-A3,-(SP)  ;save regs        LEA     KEYTBL,A2       ;set ptrs to keycode table        LEA     TBLEND,A3        CLR.L   D2	        ;use for search id@1      CMP.B   D2,D0	        ;check for match        BEQ.S   @2	        ;skip if yes        ADDQ    #1,D2	        ;incr search id        ADDQ.L  #1,A2	        ;bump table ptr        CMPA.L  A2,A3	        ;at end?        BNE.S   @1	        ;loop if not        MOVEQ   #PROFILE,D0     ;else set for default boot        BRA.S   @3	        ;and go to exit@2      MOVE.B  (A2),D0	        ;get keycode@3      MOVEM.L (SP)+,D2/A2-A3  ;restore regs        RTS;-------------------------------------------------------------------------;  Routine to search I/O slots for specific card;  Expects  D1 = card id to search for;	    D4 = qualifier for search (mask);  Returns  CC = 0 if card found and;	    D2 = slot #;-------------------------------------------------------------------------SEARCH  MOVEM.L D0/D3,-(SP)     ;save regs        MOVEQ   #0,D2	        ;setup as slot counter        MOVEQ   #2,D3	        ;set # of slots - 1 to check        LEA     IO1ID,A0        ;get location of saved slot id's@1      ADDQ    #1,D2	        ;bump slot #        MOVE    (A0)+,D0        ;read slot id        AND     D4,D0	        ;mask it        CMP     D1,D0	        ;match?        BEQ.S   @2	        ;skip if yes        DBF     D3,@1        TST     D2	        ;set nonzero status if no match@2      MOVEM.L (SP)+,D0/D3     ;restore regs        RTS		        ;exit        .PAGE;-------------------------------------------------------------------------;  Routines to display boot icon menu;-------------------------------------------------------------------------BOOTMENU        ANDI.B  #$0F,STATFLGS   ;initialize flags        CLR     RectCnt	        ;clear active rectangle counter        MOVEQ   #1,D6	        ;set min # of boot alternates	        CHG009                                ; i.e., at least have lower drive                                ;  to boot from        TST.B   SYSTYPE	        ;check system type		        CHG009        BNE.S   @10	        ;Skip if Lisa 2			        CHG009        ADDQ    #1,D6	        ;else incr count for upper floppy drive CHG009@10     MOVEQ   #1,D2	        ;set flag to do wait if needed	        RM011        BSR     CHKPROFILE      ;go check for attached Profile        BNE.S   @1	        ;skip if not there        ADDQ    #1,D6	        ;else bump boot count@1      CLR.L   D4	        ;set flag for no status check        BSR     RDSLOTS	        ;go scan the I/O slots        LEA     IO1ID,A0        ;check results        MOVE    (A0)+,D0        ;read first ID        BPL.S   @2	        ;skip if not bootable or not there        MOVE.L  #SLOT1L,A2      ;set slot address        BSR     RDSLT	        ;go check if any icons        BCS.S   @2	        ;skip if any error        ANDI    #$03,D3	        ;else clear don't care bits (max count = 2)        ADD     D3,D6	        ;and add to icon count@2      MOVE    (A0)+,D0        ;check slot 2        BPL.S   @3	        ;skip if not bootable        MOVE.L  #SLOT2L,A2      ;set slot address        BSR     RDSLT	        ;go check if any icons        BCS.S   @3	        ;skip if any error        ANDI    #$03,D3	        ;else clear don't care bits (max count = 2)        ADD     D3,D6	        ;and add to icon count@3      MOVE    (A0)+,D0        ;check final slot        BPL.S   @4        MOVE.L  #SLOT3L,A2      ;set slot address        BSR     RDSLT	        ;go check if any icons        BCS.S   @4	        ;skip if any error        ANDI    #$03,D3	        ;else clear don't care bits (max count = 2)        ADD     D3,D6	        ;and add to icon count;  set starting icon display address according to boot count@4      CMP.B   #10,D6	        ;max of 10 icons in menu        BLE.S   @5	        ;skip if OK        MOVEQ   #10,D6	        ;else set max count;  now display blank boot icon menu@5      MOVEQ   #BMENUWIDTH,D0  ;set menu parameters        MOVE.L  D6,D1	        ;get count of entries        MULU    #BMENULEN,D1    ;length depends on number of entries        LEA     STRTMSG,A3      ;set menu heading        BSR     DSPMENUBOX      ;and go display the menu        MOVE    #MENUSTRT,MenuBase ;setup base menu address        MOVE    #MENU1MSG,IconAddr ;and display pt for first entry;  next fill in the menu entries with icons and alternate keycodes;  D0 set with system typeICONCHK        MOVE.B  SYSTYPE,D0      ;read system type	        CHG009/CHG029        BEQ.S   @1	        ;skip if Lisa 1.0	        CHG009        CMP.B   #3,D0	        ;else check if internal disk    CHG009/CHG029        BNE.S   @2	        ;skip if not - no upper icon    CHG009/CHG029        CLR.L   D2	        ;else set for no wait	        CHG009        BSR     CHKPROFILE      ; and check if integral disk    CHG009                                ; installed		        CHG009        BNE.S   @2	        ;skip if not		        CHG009        LEA     UPPER,A2        ;set icon ptr for integral disk CHG009        BRA.S   @3	        ;and go display		        CHG009@1      LEA     DRIVEN,A2       ;set icon ptr for drive	        CHG009        MOVEQ   #1,D1	        ;set drive id #		        CHG009@3      MOVEQ   #TWIG1,D2       ;set id code		        CHG009        MOVEQ   #-1,D3	        ;set compressed icon indicator        BSR     DSPMNTRY        ;display the entry@2      LEA     DRIVEN,A2       ;set icon ptr for drive	        CHG009        MOVEQ   #2,D1	        ; and drive id #	        CHG009        MOVEQ   #TWIG2,D2       ;set id code        MOVEQ   #-1,D3	        ;set compressed indicator        BSR     DSPMNTRY        ;display the entry        CLR.L   D2	        ;set flag for no wait	        RM011        CMP.B   #3,D0	        ;skip check if internal disk    CHG009/CHG029        BEQ.S   SCNSLTS	        ;			        CHG009/CHG029        BSR     CHKPROFILE      ;else check if external disk attached        BNE.S   SCNSLTS	        ;skip if not        LEA     PROICON,A2      ;else set icon ptr for Profile        MOVEQ   #PROFILE,D2     ;set id code        MOVEQ   #-1,D3	        ;set compressed indicator        BSR     DSPMNTRY        ;display the entry;  check for bootable devices in slots (what a pain!)SCNSLTS CLR.L   D0	        ;clear for use        LEA     IO1ID,A0        ;set ptr for slot id        MOVE    (A0)+,D0        ;get id        BPL.S   CHKS2	        ;skip if not bootable or not there        MOVE.L  #SLOT1L,A2      ;else set slot address        MOVEQ   #1,D1	        ;set slot # for generic display if no ROM icon        MOVEQ   #IO1PORT1,D2    ;set base boot id for slot        BSR     CHKSLOT	        ;go check slot and display iconsCHKS2   MOVE    (A0)+,D0        ;read next id        BPL.S   CHKS3	        ;skip if not bootable or not there        MOVE.L  #SLOT2L,A2      ;else set slot address        MOVEQ   #2,D1	        ;set slot # for generic display        MOVEQ   #IO2PORT1,D2    ;set base boot id for slot        BSR     CHKSLOT	        ;go check slot and display iconsCHKS3   MOVE    (A0)+,D0        ;read slot 3 id        BPL.S   WT4BOOT	        ;skip if not bootable or not there        MOVE.L  #SLOT3L,A2      ;else set slot address        MOVEQ   #3,D1	        ;set slot # for generic display        MOVE    #IO3PORT1,D2    ;set base boot id for slot        BSR     CHKSLOT	        ;go check slot 3 and display icons;---------------------------------------------------------------------------;  Menu displayed - now wait for operator selection;---------------------------------------------------------------------------WT4BOOT        BSR     CursorDisplay	 ;display cursor on screen        BSET    #CHKCMD,STATFLGS ;set flag for CMD key check        BSR     GETINPUT        ;go wait for user input        BCS     GETERR	        ;skip if error        BSR     XLATE	        ;translate and save boot id        BSR     CursorHide      ;remove cursor from screen        BSR     CLRDESK	        ;clear desktop        BRA     BOOTCHK	        ;and go start boot        .PAGE;---------------------------------------------------------------------------;  Routine to check for Profile attached to built-in parallel port.;  Checks for Profile connected (OCD) and tries an initial handshake to;  ensure the device is a Profile.;;  Inputs: D2 = nonzero if full wait for Profile ready should be done;  Outputs: Zero condition code bit cleared if error;---------------------------------------------------------------------------CHKPROFILE        MOVEM.L A0/D0/D2/D4/D6,-(SP)    ;save regs			        RM011        BSR     PROINIT		        ;init for Profile access        BNE.S   @9		        ;skip if not attached        BSR     WFNBSY3		        ;wait for not busy		        RM000        TST.B   D0		        ;check return code        BEQ.S   @0		        ;skip if OK        TST.B   D2		        ;do full wait?			        RM011        BEQ.S   @7		        ;skip if not			        RM011        CLR.L   D0		        ;else reset error code for retry        BSR     WAITALRT	        ;output wait alert        BSR     WFNBSY2		        ;try wait for normal profile boot time  CHG019        MOVEM.L A0/D0,-(SP)	        ;save regs        BSR     CLRDESK		        ;clear desktop        MOVEM.L (SP)+,A0/D0	        ;restore regs        TST.B   D0        BNE.S   @8		        ;exit if still not ready@0      ANDI.B  #$EF,ORB2(A0)	        ;set command = true        BSR     WFBSY		        ;then get initial Profile response      RM016        BNE.S   @1		        ;skip if error        CMPI.B  #1,PORTA2(A0)	        ;check for expected '01' response        BEQ.S   @1		        ;skip if OK        MOVEQ   #BADRSP,D0	        ;else set error code@1      MOVEQ   #0,D3		        ;send '0' response to reset Profile        BSR     SENDRSP        BSR     WFNBSY		        ;wait until command taken@8      CLR.B   DDRA2(A0)	        ;set port A bits to input        ORI.B   #$18,ORB2(A0)	        ;and set dir=in, cmd=false@7      TST     D0		        ;set return code@9      MOVEM.L (SP)+,A0/D0/D2/D4/D6    ;restore			        RM011        RTS			        ; and exit;---------------------------------------------------------------------------;  Subroutine to invoke display of boot menu entry;  Inputs:;       D2 = boot id;       A2 = ptr to icon;  Outputs:;       Location MenuBase updated with address for next menu "box";  Side Effects:;       None;---------------------------------------------------------------------------DSPMNTRY        MOVEM.L D0/A1,-(SP)     ;save boot id and addr ptr        MOVE    D2,D0	        ;get boot id        BSR     EXPAND	        ;go convert boot id to keycode        MOVE    MenuBase,A1     ;get address for display of entry        BSR.S   ICONMENU        ;go display in menu        MOVEM.L (SP)+,D0/A1     ;restore boot id and addr ptr        RTS		        ;and exit;----------------------------------------------------------------------------;  Subroutine to display icon menu on screen.  Creates "active rectangle;  table" as entries are made.;  Inputs:;       D0 = alternate keycode;       D3 = compressed icon indicator;       A1 = address for start of next menu "box";       A2 = ptr to icon;  Outputs:;       A1 = ptr for display of next menu entry;  Side Effects:;       None;----------------------------------------------------------------------------ICONMENU        MOVEM.L D0-D4/A0/A2/A5,-(SP);  first save icon coordinates in active rectangle table        LEA     RectTable,A0    ;get ptr to active rect table        MOVE    (A0),D2	        ;get current count of rect's        MULU    #5,D2	        ;five entries per rect        ADD     D2,D2	        ;double for word index        ADDQ    #1,(A0)+        ;incr for new rect        MOVE    D0,0(A0,D2.W)   ;save keycode id for new rect        BSR     KeyToAscii      ;convert keycode to Ascii        MOVE    D0,D4	        ;save for later display;  compute X,Y pixel coordinates from starting address        BSR     GETROWCOL       ;get pixel row, byte col        MULU    #8,D6	        ;convert to pixel col        MOVE    D6,2(A0,D2.W)   ;save upper left X        MOVE    D5,4(A0,D2.W)   ; and Y coordinates        MOVE    #<MENUWIDTH*8>,D0 ;width in pixels of menu entry        ADD     D0,D6		  ;compute and save        MOVE    D6,6(A0,D2.W)	  ; lower Y coordinate        ADD     #<ICONHIGH+2>,D5  ;compute and save        MOVE    D5,8(A0,D2.W)	  ; lower X coordinate;  now do icon display        SUBA.L  A6,A6	        ;clear for use        MOVE    IconAddr,A6     ;get address for icon display        MOVE.L  A6,A1	        ;save for later use        ADD.L   SCRNBASE,A6     ;convert to screen address        TST.B   D3	        ;check for compressed icon        BPL.S   @1	        ;skip if not        BSR     DSPICON	        ;go do display        LEA     DRIVEN,A0       ;displaying drive?		        CHG009        CMPA.L  A0,A2	        ;				        CHG009        BNE.S   @2	        ;skip if not			        CHG009        MOVE.L  A1,A5	        ;else set icon display address	        CHG009        BSR     DSPNUM	        ; and display with id #		        CHG009        BRA.S   @2	        ;skip to continue		        CHG009@1      BSR     DSPRGICON       ;display an uncompressed icon	        CHG008;  now display the alternate keycode@2      ADD     #ALTKYADDR,A1   ;set starting display pt        BSR     GETROWCOL       ;convert to row, col        CLR     D0	        ;first display the apple        BSR     DSPVAL        MOVE    D4,D0	        ;get Ascii char        BSR     DSPVAL	        ;and display it;  finally compute the next menu entry and icon display address@3      MOVE    MenuBase,A1     ;get base address for the entry        ADD     #BMenuSpc,A1    ;space to next col        MOVE    A1,MenuBase     ;and save for next entry        MOVE    IconAddr,A1     ;else get this icon's address        ADD     #BMenuspc,A1    ;and bump to next spot in column        MOVE    A1,IconAddr     ;and do update        BRA.S   @4@4      MOVEM.L (SP)+,D0-D4/A0/A2/A5        RTS;---------------------------------------------------------------------------;  Routine to check slots for icons and do display or do generic display.;  Inputs:;       D0 = card id;       D1 = slot #;       D2 = first boot id for slot;       A1 = address for icon display;       A2 = slot address;  Outputs:;       Returns with carry bit set if error.;  Side Effects:;       None;---------------------------------------------------------------------------CHKSLOT MOVEM.L D0-D4/A0-A2,-(SP) ;save regs        BTST    #ICBIT,D0       ;icon available?        BNE.S   CHKICONS        ;skip if yes;  no icons available - display slot # and display generic slot card icon        LEA     XCARD,A2        ;point to generic icon        MOVEQ   #-1,D3	        ;set compressed flag        MOVE    IconAddr,A1     ;get display address for later use        BSR     DSPMNTRY        ;go display entry        LEA     XCARD,A2        ;set icon ptr        MOVE.L  A1,A5	        ;get icon address        BSR     DSPNUM	        ;display slot #        BRA.S   CHKSXIT	        ;and exit;  Slot has icon - read ROM and get ptr to desired iconCHKICONS        BSR.S   RDSLT	        ;go read slot        BCS.S   CHKSXIT	        ;exit if error        MOVE.L  #ADR128K-4,A1   ;set base address of I/O slot ROM code        MOVE.L  D3,D4	        ;save icon count        ANDI    #$03,D4	        ;isolate count (max = 2)        MOVE.L  A2,A0	        ;get code ptr        MOVE    (A0)+,D1        ;get icon offset        MOVE.L  A1,A2	        ;get base address        ADD     D1,A2	        ;add offset to set up icon ptr        BSR     DSPMNTRY        ;display as menu entry        SUBQ    #1,D4	        ;more than one icon?        BEQ.S   CHKSXIT	        ;skip if not        MOVE    (A0)+,D1        ;else get ptr to second icon        ADDQ    #1,D2	        ;bump boot id ptr for slot        MOVE.L  A1,A2	        ;restore base address        ADD     D1,A2	        ;set up icon address        BSR     DSPMNTRY        ;display as menu entryCHKSXIT MOVEM.L (SP)+,D0-D4/A0-A2 ;restore regs and exit        RTS;---------------------------------------------------------------------;  Routine to read I/O slot ROM's and get icon count if any.;;  Expects D0 = boot id;	   A2 = slot address;;  Returns D3 = icon count;	   A2 = address of ptr to first icon if more than one;---------------------------------------------------------------------RDSLT   MOVEM.L D0/D2,-(SP)     ;save boot id's        BTST    #ICBIT,D0       ;any icons stored in ROM?        BEQ.S   @2	        ;skip if none        CLR.L   D4	        ;set flag for no status check        BSR     RDIOSLT	        ;and go read ROM on slot        BCS.S   @1	        ;skip if error        CLR.L   D3	        ;clear for use        MOVE    ICONPTR,D3      ;get icon ptr        BSET    #0,D3	        ;must be odd address        MOVE.L  #ADR128K-4,A2   ;set base address        ADD.L   D3,A2	        ;set actual address        MOVE.B  (A2)+,D3        ;read icon count        BRA.S   @1@2      MOVEQ   #1,D3	        ;set default icon count@1      MOVEM.L (SP)+,D0/D2     ;restore boot id's        RTS        .ENDC		        ;{USERINT}        .PAGE;-------------------------------------------------------------------------;  Do default boot from Twiggy specified drive.;  Assumes regs:;       D0 = drive #;  Following assumptions are made for power-up status:;    1) No interrupt from disk unless diskette inserted or button pushed;-------------------------------------------------------------------------TWGBOOT LEA     DSKVCT,A3       ; first set up bus error vector        MOVE.L  A3,BUSVCTR        .IF  USERINT = 0        LEA     BOOTMSG,A3      ; output boot msg        BSR     DSPMSGR        .ELSE        MOVE.B  D0,DRIVE        ;save drive id        BSR     WAITALRT        ;display wait icon        .ENDC        MOVE.L  #DISKMEM,A0     ; set ptr to controller memory        MOVE.L  #TWGHDR,A1      ; set ptr to load header        MOVE.L  #TWGHDR+12,A2   ; and ptr to load data        CLR.L   D1	        ; set drive/side/sector/track ptr        ANDI.L  #$00FF,D0       ; mask off junk        TST     D0	        ;enable only drive selected        BNE.S   @1        MOVE.B  #$08,CMD(A0)    ;enable drive #1        BRA.S   @2@1      MOVE.B  #$80,CMD(A0)    ;enable drive #2@2      ROR.L   #8,D0	        ; get actual drive desired        OR.L    D0,D1	        ; and save for shared mem format        MOVE.B  #ENBLINT,(A0)   ;go do enable        BSR     CMDCHK	        ;wait until cmd taken        BCS     DSKTIMERR       ;skip if timeout error        MOVE.L  #VIA1BASE,A3    ;else enable        BCLR    #FDIR,DDRB1(A3) ; FDIR;	 BTST	 #FDIR,(A3)	 ;FDIR present?;	 BEQ.S	 DOREAD		 ;skip if no to do readCLRINT  BSR     CLRFDIR	        ;clear interrupts        BCS     DSKTIMERR       ;exit if timeout error        .PAGE;-----------------------------------------------------------------------------;  Read boot data - retry on sector 0 if needed.;-----------------------------------------------------------------------------DOREAD        CLR     D0	        ; set speed value        BSR     TWGRD	        ; go read sector 0		        RM000        BCC.S   @1	        ; skip if OK        CMP.B   #TIMOUT,D0      ; timeout error?        BEQ     DSKCHK	        ; exit if yes        BRA.S   RDRETRY	        ; else go do retry@1      MOVE    FILEID(A1),D0   ; else get file ID        CMP     #BOOTPAT,D0     ; is it a boot file?        BEQ.S   RDSCTR1	        ; skip if yes;  Do retry by reading track 1 to try to get head properly aligned, then;  retry reading track 0RDRETRY MOVE.B  #1,D1	        ; set for track 1        CLR     D0	        ; set speed value        BSR     TWGRD	        ; go do read			        RM000        BCS.S   DSKCHK	        ; exit if second error        CLR.B   D1	        ; else retry track 0        CLR     D0	        ; set speed value        BSR     TWGRD	        ; go do read			        RM000        BCS.S   DSKCHK	        ; exit if error;  Now check again for a valid boot track        MOVE    FILEID(A1),D0   ; get file ID        CMP     #BOOTPAT,D0     ; is it a boot file?        BEQ.S   RDSCTR1	        ; skip if yes        MOVEQ   #BADTHDR,D0     ; set error code        BRA.S   DSKCHK	        ; and exitRDSCTR1        .IF  NEWTWIG = 0        ORI     #$100,D1        ; set for sector 1        MOVE.L  #TWGHDR+268,A1  ; set new header ptr        MOVE.L  #TWGHDR+280,A2  ; and new data ptr        BSR.S   TWGREAD	        ; and read next sector        BCS.S   DSKCHK        .ENDC        CLR.L   BOOTDATA        ;set for no error        LEA     DSKERR2,A3      ;set up vectors in case of bad diskette        LEA     DSKERR3,A4        BSR     VCTRINIT        MOVE.L  #TWGDATA,A2     ;set data ptr (software view);  Do keyboard/mouse reset before continuing boot processSTRTBOOT        MOVEM.L A0/D0,-(SP)     ;save regs        BSR     RSTKBD	        ;send reset signal        BSR     CLRRST	        ;then clear it        CLR.B   KBDQ	        ;clear first byte of keyboard queue        MOVEM.L (SP)+,A0/D0     ;restore regs        JMP     (A2)	        ;and away we go ...        .PAGE;-------------------------------------------------------------------------;  Error occurred - output error message and go to monitor;-------------------------------------------------------------------------DSKTIMERR        MOVEQ   #TIMOUT,D0      ;set timeout error codeDSKCHK  MOVE.B  D0,BOOTDATA     ;save the error status        CMPI.B  #TIMOUT,D0      ;timeout?        BEQ.S   DSKERR	        ;skip if yes        BSR     CLRFDIR	        ;ensure intrpt cleared        BCS.S   DSKOUT	        ;exit if error        .IF  USERINT = 0        CMPI.B  #NODISK,D0      ; no disk in?        BNE.S   DSKBAD	        ; skip if no        LEA     DSKMSG,A3       ; get msg ptr        BSR     DSPMSGR	        ; output it        BSR     CHKFIN	        ; go wait for FDIR        BCS.S   DSKERR	        ; and exit if timeout        BSR     CLRFDIR	        ;assume disk in place, clear int        BCS.S   DSKERR	        ;skip if error        BSR     CLAMPIT	        ;issue clamp cmd        BCS.S   DSKERR	        ;exit if error        CLR.B   D1	        ;reset for track 0        BRA.S   CLRINT	        ;and go try read again        .ENDCDSKBAD  MOVE.B  CHKCNT(A0),BOOTDATA+2  ; and data checksum count        .IF  NEWTWIG = 1        MOVE.B  CHKCNT2(A0),BOOTDATA+1 ; and address checksum count        MOVE.B  RTRYCNT(A0),BOOTDATA+3 ; and retry count        .ENDCDSKOUT  BSR     EJCTDSK	        ;then eject the diskDSKDIS  BSR     DSABLDSK        ;disable both drivesDSKERR  BSR     SETBUSVCT       ; restore default bus error vector      RM000        .IF  USERINT = 0        LEA     BOOTERR,A3      ; and output message        BSR     DSPMSGR        .ELSE        BSR     CHKDRIVE        ;go determine drive        MOVE.B  BOOTDATA,D0     ;get error code        CMP.B   #NODISK,D0      ;no disk error?        BNE.S   @1	        ;skip if not                                ;2 statements deleted		        CHG009        LEA     INSERTD,A2      ;set icon for insert rqst	        CHG009        BSR     DSPALRTICON     ;display basic icon		        CHG009        MOVE    #ERRSTRT,A5     ;set display pt for id #	        CHG009        BSR     DSPNUM	        ; and display it		        CHG009        BRA     BFAIL2	        ;then go signal user@1      CMP.B   #RDWRERR,D0     ;read error?        BEQ.S   @2	        ;skip if yes        CMP.B   #BADTHDR,D0     ;bad file id?        BEQ.S   @2        CMP.B   #EBOOT,D0       ;boot error?        BNE.S   @3	        ;skip if not@2      BSR     DSPNUMICON      ;display diskette icon with id #        BRA.S   TBOOTERR        ;and exit@3      LEA     IOBRD,A2        ;error must be on I/O board        BSR     DSPERRICON      ;display icon        .ENDCTBOOTERR        .IF  USERINT = 0        BRA     DSPDVC	        ; and exit to display        .ELSE        BRA     BOOTFAIL        ;and go signal boot failure        .ENDC;--------------------------------------------------------------------------;  Handler for Twiggy boot errors;--------------------------------------------------------------------------DSKERR2 BSRS4   SAVEXCP	        ;go save exception infoDSKERR3 BSRS4   BTERR	        ;regroup        BRA.S   DSKOUT	        ;and display errorSAVEXCP        MOVE    (SP)+,EXCFC     ;save function code        MOVE.L  (SP)+,EXCADR    ;and address        MOVE    (SP)+,EXCIR     ;and instruction reg        RTS4BTERR   MOVE    (SP)+,EXCSR     ;save status reg        MOVE.L  (SP)+,EXCPC     ;and pc        BSR     SAVEREGS        ;save regs        MOVEA   #STKBASE,SP     ;reset stack pointer        BSR     SETVCTRS        ;reinit vectors        MOVEQ   #EBOOT,D0       ;set boot error        MOVE.B  D0,BOOTDATA     ;and save        RTS4;---------------------------------------------------------------------------;  Subroutine to disable interrupts from both Twiggy drives;  Inputs:;       None;  Outputs:;       Carry bit set if timeout error (in CMDCHK).;  Side Effects:;       A0 trashed (other regs trashed in CMDCHK);---------------------------------------------------------------------------DSABLDSK        MOVE.L  #DISKMEM,A0     ;set ptr to shared memory        MOVE.B  #$88,CMD(A0)    ;disable ints from both drives        MOVE.B  #DSABLINT,(A0)        BSR     CMDCHK	        ;wait for command to be taken        RTS		        ;then return;--------------------------------------------------------------------------;  Subroutine to determine drive # in error and get icon ptr;  Inputs:;       Location DRIVE = drive id # (0 or $80);  Outputs:;       A2 = ptr to diskette icon;       D1 = id #;  Side Effects:;       None;--------------------------------------------------------------------------CHKDRIVE        LEA     DISKETTE,A2     ;set ptr for diskette icon        MOVE.B  DRIVE,D1        ;get drive id        TST.B   D1	        ; drive #1?        BNE.S   @1	        ; skip if no        .IF  USERINT = 0        MOVEQ   #TWG1,D0        ; else set up ASCII code        .ELSE        MOVEQ   #1,D1	        ; else set up id code        .ENDC        BRA.S   @2@1        .IF  USERINT = 0        MOVEQ   #TWG2,D0        ; else must be drive #2        .ELSE        MOVEQ   #2,D1	        ; else set up id code        .ENDC@2        RTS		        ;exit        .IF     EXTERNAL = 1        .LIST        .ENDC        .PAGE;-----------------------------------------------------------------------------;  Read a Twiggy sector routine.  Uses hardware view of the world, with;  12 bytes for header and 256 bytes (512 for new format) of data per sector.;  Also assumes registers:;    D0 = speed (for new Twiggy code)   A0 = disk shared memory address;    D1 = drive/side/sector/track       A1 = address to load header(12 bytes);    D2 = timeout for read	        A2 = address to load data(256 or 512 bytes);    D3 = scratch		        A3 = VIA address for FDIR;  If error, returns with carry bit set and error code in D0.;------------------------------------------------------------------------------TWGRD        MOVE.L  #FDIRTIME,D2    ; set default timeout value	        RM000TWGREAD        .IF TWIGGY = 1        MOVEM.L D3/A1-A4,-(SP)  ; save regs        DISABLE		        ; disable interrupts        BSR     CHKFDIR	        ;ensure no ints pending        MOVEP.L D1,DRV(A0)      ; set disk ptrs        .IF     NEWTWIG = 1        MOVE.B  D0,SPEED(A0)    ;set speed value        .ENDC        MOVE.B  #READS,CMD(A0)  ; set for read operation        MOVE.B  #EXRW,(A0)      ; and go do it        BSR     CHKFIN	        ; wait        BCS.S   TWGOUT	        ; exit if timeout        MOVE.B  STAT(A0),D0     ; get disk return code        MOVE.B  #$CC,CMD(A0)    ;clear RWTS interrupt bits        MOVE.B  #CLRSTAT,(A0)        BSR.S   CMDCHK	        ;wait until cmd taken        BCS.S   TWGOUT	        ;exit if error        TST.B   D0	        ;check status code        BNE.S   TWGERR	        ; and exit if error;  Read successful - transfer header and then data to main memory        .IF  NEWTWIG = 0        MOVE.B  #HDRLEN,D0      ; set header length (hardware view)        MOVE.L  #HDRSTRT,A4     ; set ptr to Twiggy bufferXFRHDR  MOVE.B  (A4),(A1)+      ; transfer bytes        ADDQ.L  #2,A4	        ; bump ptr        SUBQ.B  #1,D0	        ; and continue until done        BNE.S   XFRHDR        MOVE    #SECLEN,D0      ; next set sector length        MOVE.L  #DSKBFR,A4      ; and set ptr to disk bfrXFRDATA MOVE.B  (A4),(A2)+      ; do data transfer        ADDQ.L  #2,A4	        ; bump disk ptr        SUBQ    #1,D0	        ; and continue until done        BNE.S   XFRDATA        BRA.S   TWGOK	        ; and go to exit        .ELSE        LEA     DSKBUFF(A0),A4  ;set address for Twiggy bufferXFRHDR  MOVEP.L (A4),D3	        ;load header bytes        MOVE.L  D3,(A1)+        MOVEP.L 8(A4),D3        MOVE.L  D3,(A1)+        MOVEP.L 16(A4),D3        MOVE.L  D3,(A1)+        LEA     DSKDATA(A0),A4  ;set address for data        MOVE.W  #31,D0	        ;need to load 512 bytesXFRDATA MOVEP.L (A4),D3	        ;load data bytes        MOVE.L  D3,(A2)+        MOVEP.L 8(A4),D3        MOVE.L  D3,(A2)+        MOVEP.L 16(A4),D3        MOVE.L  D3,(A2)+        MOVEP.L 24(A4),D3        MOVE.L  D3,(A2)+        ADD.W   #32,A4        DBF     D0,XFRDATA      ;loop until done        BRA.S   TWGOK	        ;and go to exit        .ENDC;  Error exit - set carry bit as error indicatorTWGOUT  MOVEQ   #TIMOUT,D0      ; set timeout errorTWGERR  ENABLE		        ; restore interrupt mask        ORI.B   #$01,CCR        BRA.S   TWGRXIT	        ; and exitTWGOK   ENABLE		        ; restore interrupt mask        CLR.L   D0	        ; set OK return code	        CHG025TWGRXIT MOVEM.L (SP)+,D3/A1-A4  ; restore regs        RTS		        ; and return to caller        .PAGE;-------------------------------------------------------------------------;  Subroutine to check for disk command taken. Also does check for DSKDIAG;  in case Twiggy controller becomes busy servicing second disk drive before;  command is seen.  Loop takes about 12.4 us if DSKDIAG OK, else DSKDIAG;  loop takes about 9.6 us.;;  Destroys register A0;-------------------------------------------------------------------------CMDCHK  MOVEM.L D3/A3,-(SP)     ;save regs        MOVE.L  #CMDTIME,D3     ;set timeout for about 15 secs        MOVE.L  #DISKMEM,A0     ;set ptr to shared memory        MOVE.L  #VIA2BASE,A3    ;also set up to monitor DSKDIAG        ANDI.B  #$BF,DDRB2(A3)@1      TST.B   (A0)	        ;cmd taken when byte 0'ed        BEQ.S   @2@3      BTST    #DSKDIAG,IRB2(A3) ;check if controller not ready        BNE.S   @4	        ;skip if OK        SUBQ.L  #1,D3	        ;else loop until timeout or ready        BNE.S   @3        BRA.S   @5	        ;take error exit@4      SUBQ.L  #1,D3        BNE.S   @1	        ;loop until yes or timeout@5      ORI.B   #$01,CCR        ;set error@2      MOVEM.L (SP)+,D3/A3     ;restore regs        RTS;----------------------------------------------------------------------------;  Subroutine to check for disk interrupt (FDIR asserted) - loop takes 8.8us;  Destroys register D3 and A3;----------------------------------------------------------------------------CHKFIN        .IF  NEWTWIG = 0        MOVE.L  #FDIRTIME,D3    ;set fixed timeout of 2 mins        .ENDC        .IF  NEWTWIG = 1        MOVE.L  D2,D3	        ;set user-supplied timeout        .ENDC        MOVE.L  #VIA1BASE,A3    ;set ptr for interface@1      BTST    #4,(A3)	        ;FDIR?        BNE.S   @2	        ;exit if yes        SUBQ.L  #1,D3        BNE.S   @1	        ;else loop        ORI.B   #$01,CCR        ;set error@2      RTS        .PAGE;-------------------------------------------------------------------------;  Subroutine to eject disk;  Assumes A0 = ptr to disk shared memory;-------------------------------------------------------------------------EJCTDSK        .IF     NEWTWIG = 1        BSR.S   CLRFDIR		 ;ensure interrupts cleared        BCS.S   @1		 ;exit if error        MOVE.L  #EJCTTIME,D2	 ;set eject timeout        .ENDC        MOVE.B  #UNCLAMP,CMD(A0) ;set up cmd        MOVE.B  #EXRW,(A0)	 ;go do it        BSR.S   CHKFIN		 ;wait for FDIR        BCS.S   @1		 ;skip if error        BSR.S   CLRFDIR		 ;clear intrpt and return@1      RTS;-------------------------------------------------------------------------;  Subroutine to clear interrupt.  Waits for FDIR to go low before return.;  Assumes A0 = ptr to disk shared memory.;-------------------------------------------------------------------------CLRFDIR MOVE.B  #$FF,CMD(A0)    ;clear FDIR        MOVE.B  #CLRSTAT,(A0)        BSR.S   CMDCHK	        ;wait until cmd taken        MOVE.L  #VIA1BASE,A3    ;then wait for FDIR to go low        MOVEQ   #25,D3	        ;set timeout for about 200 us@1      BTST    #FDIR,(A3)      ;FDIR?        BEQ.S   @2	        ;skip if none        SUBQ    #1,D3	        ;else loop until gone or timeout        BNE.S   @1        ORI.B   #01,CCR	        ;set error indicator@2      RTS;-------------------------------------------------------------------------;  Subroutine to ensure FDIR gone after clear status cmd;-------------------------------------------------------------------------CHKFDIR MOVE.L  #VIA1BASE,A3    ;set ptr for FDIR status        BTST    #FDIR,(A3)      ;FDIR present?        BEQ.S   @1	        ;skip if not        BSR.S   CLRFDIR	        ;else do clear@1      RTS		        ;and exit        .IF  USERINT = 0        .IF  NEWTWIG = 1;-------------------------------------------------------------------------;  Subroutine to issue clamp cmd;-------------------------------------------------------------------------CLAMPIT MOVE.B  #CLAMP,CMD(A0)  ;set cmd        MOVE.B  #EXRW,(A0)      ;do it        BSR     CHKFIN	        ;wait until done        RTS        .ENDC		        ;{NEWTWIG}        .ENDC		        ;{USERINT}        .IF  USERINT = 1;-------------------------------------------------------------------------;  Subroutine to enable display of wait icon.  Main entry point creates;  alert box also, secondary enrty point (DSPWTICON) invokes icon display;  only.;  Inputs:;       None;  Outputs:;       None;  Side Effects:;       A2,A3 trashed;-------------------------------------------------------------------------WAITALRTDSPWTICON        LEA     WAITICON,A2     ;and display wait icon        BSR     DSPALRTICON        RTS        .ENDC		        ;{USERINT}        .ENDC		        ;{TWIGGY};-----------------------------------------------------------------------------;  Routine to reinit vectors before release of control to boot loader.;  Sets all vectors other than reset and interrupts to jump to the;  failing boot device handler.;;  Inputs:;       A3 = address of boot error handler for bus/address errors;       A4 = address of boot error handler for other exceptions;  Outputs:;       None;  Side Effects:;       A0/D1 trashed;-----------------------------------------------------------------------------VCTRINIT        MOVEA   #BUSVCTR,A0     ;get ptr to vector locations	        RM000        MOVE.L  A3,(A0)+        ;set up for bus error        MOVE.L  A3,(A0)+        ;and address error        MOVEQ   #20,D1	        ;# of remaining low vectors to init@1      MOVE.L  A4,(A0)+        ;setup handler for errors up        SUBQ    #1,D1	        ; to spurious intrpt vector        BNE.S   @1        MOVEA   #TRPVCT0,A0     ;next do all trap vectors	        RM000        MOVEQ   #32,D1	        ;set count@2      MOVE.L  A4,(A0)+        ;and do init        SUBQ    #1,D1        BNE.S   @2        RTS        .IF     EXTERNAL = 1        .NOLIST        .ENDC        .PAGE        .IF PROFLE = 1	        ;ASSEMBLE ONLY IF PROFILE CODE NEEDED;-----------------------------------------------------------------------------;  Routine to boot from Profile hard disk attached to parallel port;  Sets up input parameters and then calls READ routine.  If no error;  on return (carry not set), a jump to the loaded boot code is done.;-----------------------------------------------------------------------------PROBOOT        .IF  USERINT = 0        LEA     BOOTMSG,A3	        ; output boot msg        BSR     DSPMSGR        .ELSE        BSR     WAITALRT	        ; display wait icon        .ENDC        MOVE.L  #HDRBUFR,A1	        ; set up ptr to save header        MOVE.L  #HDRBUFR+20,A2	        ; ptr for data        CLR.L   D1		        ; set sector #        MOVE.L  #STRTIME,D2	        ; set timeout count (3 mins)        MOVEQ   #RCNT,D3	        ; set retry count        MOVEQ   #TCNT,D4	        ; set threshold count        BSR     PROREAD		        ; go get data        BCS.S   HDSKERR		        ; exit if error;  Now verify header and if OK, jump to startup program        MOVE    FILEID(A1),D0	        ; get file id        CMP     #BOOTPAT,D0	        ; is it a boot block?        BEQ.S   PBOOT		        ; continue if OK        MOVEQ   #BADHDR,D0	        ; else set error code        BRA.S   HDSKERR		        ; and exitPBOOT   LEA     HDERR2,A3	        ;set up vectors in case of errors        LEA     HDERR3,A4        BSR     VCTRINIT        MOVE.L  #HDRBUFR+20,A2	        ; set ptr for data        BRA     STRTBOOT	        ; and go start execution;  Error detected - output message and abort bootHDSKERR        .IF  USERINT = 0        LEA     BOOTERR,A3	        ; get msg ptr        BSR     DSPMSGR		        ; display error        MOVEQ   #PRO,D0		        ; set device code        BRA     DSPDVC		        ;  and go display        .ELSE        CMP.B   #3,SYSTYPE	        ;check system type	        CHG009/CHG029        BEQ.S   @2		        ;skip if internal disk	        CHG009/CHG029        LEA     PROICON,A2	        ;else setup Profile icon        BRA.S   @3		        ;skip to do display	        CHG009@2      LEA     UPPER,A2	        ;set for integral hard disk     CHG009@3      CMP.B   #NODSK,D0	        ;Profile not attached error?        BNE.S   @1		        ;skip if not;  If default boot and no Profile attached, go to boot menu        BTST    #ALTBOOT,D7	        ;is this a default boot?        BNE.S   @1		        ;skip if not        BSR     CLRDESK		        ;clear desktop        BRA     LSTCHK		        ;and do beep and display the boot menu@1      BSR     DSPERRICON	        ;display with bad mark        .ENDC			        ;{PROFILE};  Sound error tones and display error codeBOOTFAIL        BSR     DSPCODE		        ;display error codeBFAIL2        BSR     HIPTCH		        ;startup failure causes hi,hi,hi tones        BSR     HIPTCH        BSR     HIPTCH        BSR     CLRMENU		        ;clear menu bar        ANDI.B  #$FC,STATFLGS	        ;allow CONTINUE option from boot error        BSET    #NORSTRT,STATFLGS       ; but not restart option        BRA     MONITOR		        ;and go to monitorHDERR2  BSR4    SAVEXCP		        ;save exception infoHDERR3  BSR4    BTERR		        ;regroup from error        BRA.S   HDSKERR		        ;and go display it        .IF     EXTERNAL = 1        .LIST        .ENDC        .PAGE;-----------------------------------------------------------------------------;  First initialize and then ensure disk is attached by checking OCD line.;  Assumes ACR and IER registers of VIA set up by caller.  For boot, these;  are cleared by power-up reset.;  Register usage:;    D0 = scratch use	        A0 = VIA address for parallel port interface;    D1 = block to read	        A1 = address to save header;    D2 = timeout count	        A2 = address to save data;    D3 = retry count	        A3 = scratch;    D4 = threshold count       A4 = unused;  Returns:;    D0 = error code (0 = OK);    D1 = error bytes (4);    D2 - D7 and A1 - A6 are preserved;-----------------------------------------------------------------------------PROREAD MOVEM.L D2-D7/A1-A6,-(SP)       ; save regs        DISABLE			        ; ensure interrupts off        BSR.S   PROINIT		        ; init for Profile access and check                                        ;  if attached        BEQ.S   CHKBSY		        ; go on if OK        MOVEQ   #NODSK,D0	        ; else set error code and        BRA.S   PROERR		        ; skip if error - no disk attached;  Now check if Profile ready - wait time presently set for about 100 seconds;  to allow enough time for normal Profile startup time of about 80 secondsCHKBSY  BTST    #BSY,IRB2(A0)	        ; check if Profile ready (not busy)        BNE.S   TRYRD		        ; skip if yes        SUBQ.L  #1,D2		        ; else loop until timeout        BNE.S   CHKBSY        MOVEQ   #DSKBSY,D0	        ; set disk busy error code        BRA.S   PROERR		        ; and go to error exit;  Now start read and check status to see if OKTRYRD   BSR     STRTRD		        ; go begin read process        BCC.S   @1		        ; skip if OK		        CHG016        BSR     WFNBSY		        ; else check for ready	        CHG016        BSR     STRTRD		        ; and do retry		        CHG016        BCC.S   @1		        ; continue if OK	        CHG016        BSR     DOCRES		        ; else issue reset signal       CHG016        BSR     WFNBSY		        ; wait until ready	        CHG016        BSR     STRTRD		        ; and try one more time	        CHG016        BCS.S   PROERR		        ; finally exit if error@1      TST.W   STAT3		        ; check if reset error	        CHG016        BPL.S   @2		        ; skip if not        BSR     STRTRD		        ; else go try read again        BCS.S   PROERR		        ; and abort if error@2      TST.L   STATBFR		        ; check complete status        BEQ.S   RDDATA		        ; skip if OK        MOVE.L  STATBFR,D1	        ; else get status        MOVE.L  D1,D0		        ; save for use        ANDI.L  #STATMSK,D0	        ; mask don't care bits        BEQ.S   RDDATA		        ; and continue if OK        MOVEQ   #STATNZ,D0	        ; else set error code        BRA.S   PROERR		        ; and go to error exit;  All OK - go read block and transfer to memory; do as multiple moves for;  max transfer rate.RDDATA  MOVEQ   #<HDRSIZE/4>-1,D0       ; set count for header read        BSR.S   READIT		        ; go do it        MOVEQ   #<BLKSIZE/4>-1,D0       ; set count for data read        MOVEA.L A2,A1		        ; set new read location        BSR.S   READIT        BRA.S   PROXIT		        ; and go to exit;  Error exit - set carry bit as indicator flagPROERR  ENABLE			        ;restore interrupt mask        ORI.B   #$01,CCR        BRA.S   PROXIT2;  Normal exit - restore regs and exitPROXIT  ENABLE			        ;restore interrupt mask        CLR.L   D0		        ;set OK return code	        CHG025PROXIT2 MOVEM.L (SP)+,D2-D7/A1-A6        RTS;----------------------------------------------------------------------------;  Subroutine to init parallel port for Profile access.;  Inputs:;       None;  Outputs:;       D0 cleared for error use;       A0 = VIA base address for parallel port;       CCR zero bit set if cable connected;  Side Effects:;       None;----------------------------------------------------------------------------PROINIT        CLR.L   D0		        ; clear for result use        MOVE.L  #VIA1BASE,A3	        ; get kybd VIA base address		        CHG036        ORI.B   #$A0,ORB1(A3)	        ; initialize profile-reset and parity-reset     CHG036        ORI.B   #$A0,DDRB1(A3)	        ;  and set lines as outputs		        CHG036        MOVE.L  #VIA2BASE,A0	        ; get paraport VIA base address        ANDI.B  #$7B,PCR2(A0)	        ; set ctrl CA2 pulse mode/positive edge        ORI.B   #$6B,PCR2(A0)        MOVE.B  #$00,DDRA2(A0)	        ; set port A bits to input        ORI.B   #$18,ORB2(A0)	        ; then set direction=in, cmd=false,	        CHG036        ANDI.B  #$FB,ORB2(A0)	        ;  enable=true				        CHG036        ANDI.B  #$FC,DDRB2(A0)	        ; set port B bits 0,1=in,        ORI.B   #$1C,DDRB2(A0)	        ;  2,3,4=out        BTST    #OCD,IRB2(A0)	        ; check OCD line        RTS			        ; and exit;----------------------------------------------------------------------------;  Subroutine to read bytes from Profile.  Assumes:;    D0 = byte count - 1;    A0 = VIA address for parallel interface;    A1 = memory load address;----------------------------------------------------------------------------READIT  MOVE.B  IRA2(A0),(A1)+	        ; read the bytes        MOVE.B  IRA2(A0),(A1)+        MOVE.B  IRA2(A0),(A1)+        MOVE.B  IRA2(A0),(A1)+        DBF     D0,READIT        RTS        .PAGE;---------------------------------------------------------------------------;  Subroutine to begin the read process.  First calls a routine that;  gets in sync with Profile and sends read command.  Then a wait for;  an appropriate response from Profile is executed.;  Assumes regs:;    D0 = scratch use	        A0 = VIA address;    D1 = block to read	        A1 = unused;    D2 = used for Profile cmd  A2 = unused;    D3 = retry count	        A3 = scratch use;    D4 = threshold count       A4 = unused;  If error, carry bit set and error code in D0.;---------------------------------------------------------------------------STRTRD  MOVEA   #CMDBUFR,A3	        ; first set up command		        RM000        MOVE.L  D1,(A3)		        ; set read command (0) and block #        MOVE.B  D3,RETRY(A3)	        ; set retry count        MOVE.B  D4,THRESH(A3)	        ; set threshhold for sparing        BSR.S   STAT01		        ; get 01 byte and send read command        BCS.S   STRTXIT		        ; exit if error;  OK so far - go check if Profile ready to send data        MOVEQ   #2,D2		        ; get 02 byte			        RM000        BSR.S   FINDD2        BCS.S   STRTXIT		        ; exit if timeout error;  Get status bytesGETSTAT MOVEA   #STATBFR,A3	        ; set buffer ptr		        RM000        MOVE.B  IRA2(A0),(A3)+	        ; read and save the status        MOVE.B  IRA2(A0),(A3)+        MOVE.B  IRA2(A0),(A3)+        MOVE.B  IRA2(A0),(A3)+STRTXIT RTS			        ; return to caller        .PAGE;--------------------------------------------------------------------------;  Subroutine to get in sync with Profile.;  Input regs:;    A0 = VIA address;    A3 = ptr to command buffer;  If error, returns with carry bit set and error code in D0;--------------------------------------------------------------------------STAT01  MOVEM.L D2/D4,-(SP)	        ; save regs        MOVE.L  #1,D2		        ; try to find state 01        BSR.S   FINDD2        BCC.S   COPY6		        ; skip if OK        CMP.B   #TMOUT,D0	        ; else check if timeout error        BEQ.S   STATERR		        ; and exit if yes        BSR     WFNBSY3		        ; ensure Profile ready		        RM000        TST.B   D0		        ; check for timeout error        BNE.S   STATERR		        ; and exit if yes@2      BSR.S   FINDD2		        ; try to find state 01 again        BCS.S   STATXIT		        ; exit if error againCOPY6   ANDI.B  #$F7,ORB2(A0)	        ; set dir=out        MOVE.B  #$FF,DDRA2(A0)	        ; set port A bits to output        MOVE.W  #PCMDSZ,D0	        ; set command sizeCOPY6LP MOVE.B  (A3)+,ORA2(A0)	        ; send the command bytes        DBF     D0,COPY6LP        ORI.B   #$08,ORB2(A0)	        ; reset dir=in        MOVE.B  #$00,DDRA2(A0)	        ;  and set port A bits to input        BRA.S   STATXIT		        ; then exitSTATERR ORI.B   #$01,CCR	        ; set error indicatorSTATXIT MOVEM.L (SP)+,D2/D4	        ; restore regs        RTS        .PAGE;------------------------------------------------------------------------------;  Subroutine to handshake with Profile and wait for command completion.;  Polls busy bit until it goes low (not busy).;  Assumes regs:;    A0 = VIA address;    D2 = Expected response to previously issued command;  If error, carry bit set and error code in D0.;------------------------------------------------------------------------------FINDD2  MOVEM.L D1-D4,-(SP)	        ; save regs        ANDI.B  #$EF,ORB2(A0)	        ; set cmd=true        MOVE.B  #$00,DDRA2(A0)	        ; set port A bits to input        CLR.L   D0		        ; used for return code        BSR.S   WFBSY		        ; wait for busy        BNE.S   FINDERR		        ; exit if errorGETRSP  MOVE.B  PORTA2(A0),D1	        ; get response in D1 w/o handshake        CLR.B   D3		        ; used for reply to Profile        CMP.B   D2,D1		        ; did pippin return state requested ?        BEQ.S   RSPOK		        ; skip if yes        MOVEQ   #BADRSP,D0	        ; else set error code        BRA.S   SNDR1		        ; and go send replyRSPOK   MOVEQ   #$55,D3		        ; set up OK reply		        RM000SNDR1   BSR.S   SENDRSP		        ; send response        TST.B   D0		        ; check return code        BNE.S   FINDERR		        ; skip if error        BSR.S   WFNBSY		        ; now go wait for not busyFINDERR MOVE.B  #$00,DDRA2(A0)	        ; reset port A bits to input        ORI.B   #$18,ORB2(A0)	        ; and dir = in, cmd=false        TST.B   D0		        ; check return code        BEQ.S   FNDXIT		        ; skip if OK        ORI.B   #$01,CCR	        ; else set error indicatorFNDXIT  MOVEM.L (SP)+,D1-D4	        ; restore regs(but don't affect CCR bits)        RTS;------------------------------------------------------------------------------;  Subroutine to wait for Profile busy signal.  Polls busy bit until it;  goes high (busy).;  Assumes regs:;    A0 = VIA address;    D4 = timeout value if WFBSY1 entry point used;  If error, error code in D0.;------------------------------------------------------------------------------WFBSY   MOVE    #RSPTIME,D4	        ; set response timeout = 100 msecWFBSY1  BTST    #BSY,IRB2(A0)	        ; wait for busy        BEQ.S   @9		        ; skip if OK        SUBQ    #1,D4		        ; else loop until timeout        BNE.S   WFBSY1        MOVEQ   #TMOUT,D0	        ; set timeout error@9      RTS;------------------------------------------------------------------------------;  Subroutine to send response command to Profile.;  Assumes regs:;    A0 = VIA address;------------------------------------------------------------------------------SENDRSP ANDI.B  #$E7,ORB2(A0)	        ; set dir=out, cmd=true        MOVE.B  #$FF,DDRA2(A0)	        ; set port A bits to output        MOVE.B  D3,PORTA2(A0)	        ; send reply(00 or 55) w/o handshake        ORI.B   #$10,ORB2(A0)	        ; set cmd=false        RTS;------------------------------------------------------------------------------;  Subroutine to wait for Profile not busy signal.  Polls busy bit until it;  goes low (not busy).;  Assumes regs:;    A0 = VIA address;    D4 = timeout value if WFNBSY1 entry point used;  If error, D0 has error code.;------------------------------------------------------------------------------WFNBSY  MOVE.L  #RDTIME,D4	        ; set timeout for about 16 secs	        CHG037        BRA.S   WFNBSY1		        ;				        CHG019WFNBSY2 MOVE.L  #STRTIME,D4	        ; set initial Profile self-test time    CHG019        BRA.S   WFNBSY1		        ;				        CHG019WFNBSY3 MOVE.L  #BSYTIME,D4	        ; set timeout for about 10 ms	        RM000WFNBSY1 BTST    #BSY,IRB2(A0)	        ; wait for not busy        BNE.S   @9		        ; exit if OK        SUBQ.L  #1,D4		        ; else loop until timeout        BNE.S   WFNBSY1        MOVEQ   #TMOUT,D0	        ; set timeout error@9      RTS;-----------------------------------------------------------------------------;  Subroutine to send reset to Profile controller to enable handshake retry     CHG016;-----------------------------------------------------------------------------DOCRES  MOVE.L  #VIA1BASE,A3	        ;use keyboard 6522		        CHG026        ANDI.B  #$7F,ORB1(A3)	        ;set reset signal		        CHG016/CHG026/CHG036        BSR     DELAY_1		        ;delay for controller to get signal     CHG016        ORI.B   #$80,ORB1(A3)	        ;remove reset signal		        CHG016/CHG026/CHG036        BSR     DELAY_1		        ;delay for controller to respond        CHG038        RTS			        ;and exit        .ENDC			        ;{PROFLE}        .IF     EXTERNAL = 1        .NOLIST        .ENDC        .PAGE;-------------------------------------------------------------------------;  Routine to boot from I/O slot.;  Verifies that slot has bootable card installed and then reads in ROM;  data.  If status routine exists it is executed, else jump to boot;  routine done if checksum OK.;;  Inputs:;       D0 = boot device id ($4-$C);       A0 = scratch use;       A1 = slot address;  Outputs: (relayed to loaded boot program);       D0 = boot device id;       A1 = slot address;-------------------------------------------------------------------------IOSBOOT MOVE.B  D0,D4	        ;save boot device id                                ; also acts as flag for status check        MOVE.L  BUSVCTR,A5      ;save bus error vector        MOVE.L  SP,A6	        ;save current stack pointer        LEA     NOCRD,A3        ;setup new bus error vector        MOVE.L  A3,BUSVCTR        MOVEP   (A1),D1	        ;read card id        .IF  USERINT = 0        LEA     BOOTMSG,A3      ;output boot msg        BSR     DSPMSGR        .ENDC        TST     D1	        ;check if card installed        BPL.S   INVID	        ;exit if not bootable        CMP     #$FFFF,D1       ;check if special case        BEQ.S   INVID        .IF  USERINT = 1        BSR     WAITALRT        ;display wait icon        .ENDC        MOVE.L  A1,A2	        ;get slot address        BSR.S   RDIOSLT	        ;go check the board        BCS.S   BADBRD	        ;exit if errorSTATOK        MOVE.B  BOOTDVCE,D0     ;setup boot device id        MOVE.L  #BTENTRY,A2     ;and starting program address        BRA     STRTBOOT        ;and go do boot ...;  Error routines for I/O slot booting. Error code saved and error message output.NOCRD   MOVEQ   #NOC,D0	        ;set error code        MOVE.L  A5,BUSVCTR      ;restore bus error vector        MOVE.L  A6,SP	        ;and stack ptr        BRA.S   SENDMSG	        ;then go display msgINVID   MOVEQ   #INV,D0	        ;set error code        BRA.S   SENDMSG	        ;go do displayBADBRD  MOVE.B  BOOTDVCE,D4     ;restore boot device id for checkingSENDMSG        MOVE.B  D0,BOOTDATA     ;save error code        .IF  USERINT = 0        LEA     BOOTERR,A3      ;set ptr to msg        BSR     DSPMSGR	        ;and display        MOVE.B  D4,D0	        ;set up boot device id for display        BRA     DSPDVC	        ; and go do it        .ELSE;  determine which slot # being used        LEA     XCARD,A2        ;set general I/O slot card ptr        CMP.B   #IO1PORT2,D4    ;in slot 1 range?        BGT.S   @1        MOVEQ   #1,D1	        ;yes - set slot #1        BRA.S   @3@1      CMP.B   #IO2PORT2,D4    ;slot 2 range?        BGT.S   @2        MOVEQ   #2,D1	        ;set slot 2 id        BRA.S   @3@2      MOVEQ   #3,D1	        ;else must be slot 3@3      BSR     DSPNUMICON      ;display error icon and slot #        BRA     BOOTFAIL        ;and signal boot failure        .ENDC        .PAGE        .IF  NEWTWIG = 1;----------------------------------------------------------------------------;  Routine to read ROM on an I/O slot.;  Inputs:;       A2 = I/O slot base address;       D4 = nonzero if status check also to be done, else 0 for no check;       D1 = card id if status check needed;  Outputs:;       Carry bit set if error, error code saved in D0, error code from;       status check saved in BOOTDATA+1;  Side Effects:;       D0, A2 trashed;----------------------------------------------------------------------------RDIOSLT MOVEM.L D1-D3/A0-A1,-(SP) ;save regs        MOVE.L  #ADR128K-4,A0   ;set load pt (also load id/word count)        MOVE.L  A2,A1	        ;save slot address for later use        CLR.L   D0	        ;clear for use        MOVEP   4(A2),D0        ;read word count        ADDQ    #2,D0	        ;incr for id/count fields        CMPI    #$0FFF,D0       ;check for max count        BHI.S   INVSUM	        ;exit if error        CLR.L   D2	        ;clear for use        CLR.L   D3LOADPGM MOVEP   (A2),D2	        ;read word        MOVE    D2,(A0)	        ;save in memory        MOVE    (A0)+,D2        ;reread it from memory        ADD     D2,D3	        ;add to checksum        ROL     #1,D3	        ;rotate for better effectiveness        ADDQ.L  #4,A2	        ;bump address ptr        SUBQ    #1,D0        BNE.S   LOADPGM	        ;loop until done        MOVEP   (A2),D2	        ;read expected checksum (2 bytes)        ADD     D2,D3	        ;add to calculated checksum        TST     D3	        ;check for 0 result (also clears carry bit)        BNE.S   INVSUM	        ;skip if error;  Do status check if desired and available        TST     D4	        ;do status check?        BEQ.S   RDIOXIT	        ;skip if not        BTST    #STBIT,D1       ;status routine available?        BEQ.S   RDIOXIT	        ;skip if not        MOVEM.L D4-D7/A2-A6,-(SP) ;save regs not already saved        JSR     STENTRY		  ;go execute status routine        MOVEM.L (SP)+,D4-D7/A2-A6 ;restore regs        TST     D0	        ;check status        BEQ.S   RDIOXIT	        ;skip if no error        MOVE.B  D0,BOOTDATA+1   ;save card error code        MOVEQ   #BADST,D0       ;set general error code        BRA.S   SAVERRINVSUM  MOVEQ   #BADSM,D0       ;set invalid checksumSAVERR  MOVE.B  D0,BOOTDATA     ;save error code        ORI.B   #$01,CCR        ;set error indicatorRDIOXIT MOVEM.L (SP)+,D1-D3/A0-A1 ;restore regs        RTS        .ENDC        .IF     BURNIN = 1        .PAGE;-------------------------------------------------------------------------;  Special code to enable burnin cycling by the ROM.  Does initialization;  on first pass, and then causes cycling for the specified cycle count,;  which defaults to approximately 60 minutes.  At;  that point a branch to a system shutdown routine is performed.;-------------------------------------------------------------------------;  Do first pass initializationCHKPASS CMP.B   #$01,INITFLG    ;first pass done?        BEQ.S   CHKTIM	        ;skip if yesCHKPAS2 MOVEA.L #INITFLG,A0     ;set ptr for other data areas        MOVEA.L #ENDPM,A1       ;and ending ptrCLRPM   CLR.B   (A0)	        ;do clear        ADDQ.L  #2,A0	        ;bump ptr        CMPA.L  A0,A1	        ;loop until done        BNE.S   CLRPM        MOVEQ   #1,D0        MOVE.B  D0,INITFLG      ;set init flag        MOVE.B  #60,CYCLVAL     ;set cycling for 60 minutes        CLR.L   CLKDATA	        ;and init clock data area        CLR     CLKDATA+4;  Set clock to initial value so run can be ended at cycle count.  Sends;  value of day=01, all other values=0 (e.g., time = 00:00:00).        MOVEQ   #$2C,D0	        ;set up clock set cmd        BSR     COPSCMD	        ;and send to COPS        BCS.S   @9	        ;exit if error			        RM000        MOVE.L  #SET1,D1        ;set up value for clock        MOVEQ   #8,D2	        ;set "char" count        BSR     TODSET	        ;and go do it        BCS.S   @9	        ;				        RM000        MOVE.L  #SET2,D1        ;set up next value for clock        MOVEQ   #8,D2	        ;set "char" count        BSR     TODSET	        ;and go do it        BCS.S   @9	        ;				        RM000        MOVEQ   #$25,D0	        ;finally set up clock enable cmd        BSR     COPSCMD	        ;and send it@9      BCS     SETERR1	        ;exit if error;  Check to see if cycle count to be changed and if time data needs to be savedCHKTIM        .IF  USERINT = 1        BSR     MAKEPCALRT      ;setup powercycle alert box        .ENDC        BTST    #MSBUTN,STATFLGS ;mouse button detected?        BEQ.S   @3	        ;skip if no			        RM000        MOVE.B  CYCLVAL,D0      ;read current setting		        RM000        CMP.B   #60,D0	        ;long cycle set?		        RM000        BNE.S   @1        MOVEQ   #3,D0	        ;set for 3 minute cycle		        RM000        BRA.S   @2@1      MOVEQ   #60,D0	        ;set for 60 minute cycle	        RM000@2      MOVE.B  D0,CYCLVAL      ;save in PM			        RM000@3      CMP.B   #$01,TIMFLG     ;time data saved?		        RM000        BEQ.S   TWGCHK	        ;skip if yes        MOVE.L  HOUR,D0	        ;get minutes        ROL.L   #4,D0        SWAP    D0        MOVE.B  D0,MINSAV       ;save minutes        CLR.B   MINCNT	        ;and clear minute count        CLR.B   CYCLCNT	        ; and cycle count        MOVE.B  #$01,TIMFLG     ;and set flag;  Check if time for Twiggy test (do every two minutes)TWGCHK  CMP.B   #2,MINCNT       ;check minute counter        BNE     WRTMSG        CLR.B   MINCNT	        ;clear counter        LEA     TWGMSG,A3       ;get msg ptr        BSR     DSPMSGR	        ;and display it        MOVEQ   #PCCOL,D6       ;reset left margin        LEA     DSKVCT,A3       ;set up bus error vector        MOVE.L  A3,BUSVCTR        MOVE.L  #DISKMEM,A0     ;set ptr to shared memory        MOVE.L  #VIA1BASE,A3        TST.B   SYSTYPE	        ;check system type		        CHG009        BEQ.S   @1	        ;skip if Lisa 1.0		        CHG009        MOVEQ   #80,D4	        ;else set track count for SONY drive    CHG009        BRA.S   @2	        ;and go test single drive	        CHG009@1      CLR.L   D1	        ;else set for drive 1, track 0 to start        MOVEQ   #45,D4	        ;set count (# of tracks);  Now do the drive test, one drive at a time        BSR     CLRFDIR	        ;first clear interrupts        BCS.S   TSTERR	        ;exit if error        BSR     TWGTST	        ;go do test        BCS.S   TSTERR        MOVEQ   #45,D4	        ;reset track count		        CHG009@2      CLR.L   D1	        ;set for drive 2		        CHG009        MOVE.B  #$08,D1        ROR.L   #4,D1        BSR     TWGTST	        ;and do test again        BCC.S   DISINT	        ;and continue if OKTSTERR  LEA     TWGFAIL,A3      ;display error msg        BSR     DSPMSGR        MOVEQ   #PCCOL,D6       ;reset left margin        CMP.B   #TIMOUT,D0      ;timeout error?        BEQ     CMDERR	        ;exit testing if yes        ADDQ.B  #1,DSKCNTL      ;else bump low error count        BCC.S   DISINT	        ;skip if no overflow        ADDQ.B  #1,DSKCNTH      ;else bump high counter also;  Disable interrupt so disks can be ejectedDISINT  BSR     TWGDSP	        ;display Twiggy error count        MOVE.B  #$88,CMD(A0)    ;set ptr for both drives        MOVE.B  #DSABLINT,(A0)  ;send disable cmd        BSR     CMDCHK	        ;wait until done;  Output initial messageWRTMSG  LEA     BRNMSG,A3       ;get msg ptr        BSR     DSPMSG	        ;and display it        MOVE.B  CYCLVAL,D0      ;get cycling value        BSR     DSPDEC	        ;display as decimal        MOVEQ   #PCCOL,D6       ;set col for window limits;  Increment loop count and display it on screenCNTINC  ADDQ.B  #1,LCNTLO       ;inc low byte        BCC.S   DSPTIM	        ;skip if no carry        ADDQ.B  #1,LCNTHI       ;else inc high byte alsoDSPTIM  BSR     DSPCLK	        ;go display time;  Now check time to see if update needed        MOVE.L  HOUR,D0	        ;get minute value        ROL.L   #4,D0        SWAP    D0        CMP.B   MINSAV,D0       ;has value changed?        BEQ.S   NOCHG	        ;skip if not        ADDQ.B  #1,MINCNT       ;else bump minute count        ADDQ.B  #1,CYCLCNT      ;and cycle count        MOVE.B  D0,MINSAV       ;save new minute value;  Delay so screen can be readNOCHG   BSR     DELAY5	        ;delay for 5 secs;  Check to see if run should be ended        MOVE.B  CYCLCNT,D0      ;get cycle count        MOVE.B  CYCLVAL,D1      ;get desired cycle value        CMP.B   D1,D0	        ;cycle if same or greater        BGE.S   SHUTDOWN;  If not, cause double bus fault to restart diagnostics;  First make parameter memory valid        MOVE.B  #PC,D0	        ;set power-cycle boot code        BSR     SAV2PM	        ;and go set param mem        BSR     PROINIT	        ;check for attached hard disk   CHG019        BNE.S   @1	        ;skip if none		        CHG019        BSR     WFNBSY2	        ;else wait until disk ready     CHG019@1      BRA     DORESET	        ;then go cause a system reset;  Do soft power-off for specified cycle periodSHUTDOWN        CLR.B   TIMFLG	        ;reset time save indicator        MOVE.L  CLKDATA+2,D0    ;and save clock data        MOVE.L  #CLKSAVE,A1        MOVEP.L D0,(A1);  Disable Twiggy controller to avoid any RAM problemsDSCONT        MOVE.L  #DISKMEM,A0     ;set ptr to shared memory        MOVE.B  #DIE,(A0)       ;and send "die" cmd        BSR     CMDCHK	        ;wait until done        BCS.S   CMDERR	        ;exit if error        MOVEQ   #$2D,D0	        ;enable alarm setting        BSR     COPSCMD        BCS.S   SETERR2        CLR.L   D1        MOVE.B  CYCLVAL,D1      ;get desired shutdown time        MOVEQ   #60,D0	        ;multiply by 60 for seconds        MULU    D0,D1        MOVEQ   #12,D0	        ;rotate to send as alarm value        ROL.L   D0,D1        MOVE.L  #ALRMSAV,A1        MOVEP.L D1,(A1)	        ;save alarm value        MOVEQ   #5,D2	        ;5 digits for alarm value        BSR.S   TODSET        BCS.S   SETERR2;  Make parameter memory valid        MOVE.B  #PC,D0	        ;set power-cycle boot code        BSR     SAV2PM	        ;and go set param mem;  And finally send power-off cmd        MOVEQ   #$23,D0	        ;set up enable/power off cmd        BSR     COPSCMD	        ;send it        BCS.S   SETERR2SELF    NOP        BRA.S   SELF	        ;goodbye ...SETERR1 MOVEQ   #SERR1,D0       ;set error code        BRA.S   DSPERR	        ;and go displaySETERR2 MOVEQ   #SERR2,D0       ;set error codeDSPERR        .IF  USERINT = 0        LEA     IOMSG,A3        ;display error        BSR     DSPMSGR        .ELSE        LEA     IOBRD,A2        ;set icon ptr        BSR     DSPERRICON      ;display it        .ENDC        BSR     DSPCODE        BRA     MONITOR	        ;and exit to monitor;  Error routine if disk cmd not takenCMDERR  BSET    #DISK,D7        ;set error bit        BRA     TSTCHK	        ;and exit        .PAGE;-------------------------------------------------------------------------;  Subroutine to send clock data.  Assumes registers:;       D0 = scratch use;       D1 = clock data;       D2 = digit count;-------------------------------------------------------------------------TODSET  ROL.L   #4,D1	        ;get digit        MOVE.B  D1,D0	        ;set up for COPS as 1X        ANDI.B  #$0F,D0	        ; where X = digit for clock        ORI.B   #$10,D0        BSR     COPSCMD	        ;and send it        BCS.S   SETXIT	        ;exit if error        SUBQ    #1,D2	        ;decr count        BNE.S   TODSET	        ;and loop until doneSETXIT  RTS        .PAGE;--------------------------------------------------------------------------;  Subroutine to do Twiggy testing;  Expects;       D0 = scratch use	        A0 = shared memory address;       D1 = drive parameters	        A1 = unused;       D2 = FDIR timeout value	        A2 = unused;       D3 = unused		        A3 = VIA address for FDIR access;       D4 = loop count for reads;--------------------------------------------------------------------------TWGTST  MOVE.B  #$88,CMD(A0)    ;enable interrupts from both drives        MOVE.B  #ENBLINT,(A0)   ;do it        BSR     CMDCHK	        ;wait until done        BCS.S   TERR	        ;exit if error        BCLR    #FDIR,DDRB1(A3) ;enable FDIR bit        MOVE.L  #FDIRTIME,D2    ;set timeout value for FDIRTWGLOOP MOVEP.L D1,DRV(A0)      ; set disk ptrs        MOVE.B  #READS,CMD(A0)  ; set for read operation        MOVE.B  #EXRW,(A0)      ; and go do it        BSR     CHKFIN	        ; wait        BCS.S   TOOLONG	        ; exit if timeout        MOVE.B  STAT(A0),D0     ; get disk return code        BSR     CLRFDIR	        ; clear interrupt indicator        BCS.S   TOOLONG        TST.B   D0	        ;any error?        BNE.S   TERR	        ; and exit if error        ADDQ    #1,D1	        ;incr track ptr        SUBQ    #1,D4	        ;decrement count        BNE.S   TWGLOOP	        ;loop until done        RTSTOOLONG MOVEQ   #TIMOUT,D0      ;set error codeTERR    ORI.B   #$01,CCR        ;set indicator        RTS		        ;and exit;------------------------------------------------------------------------;  Subroutine to display clock reading as D HH MM SS;------------------------------------------------------------------------DSPCLK  LEA     TIMMSG,A3       ;get msg ptr        BSR     DSPMSG	        ;and display it        ADDQ    #1,D6	        ;add extra space        BSR     READCLK	        ;go read clock        MOVE.L  CLKDATA+2,D0    ;get time (minus Ey/dd digits)        MOVE.L  #CLKSAVE,A1     ;and save it        MOVEP.L D0,(A1)        ROL.L   #4,D0	        ;get day value        MOVEQ   #1,D1	        ;set # of digits to display        BSR     OUTCH	        ;and display it        ADDQ    #1,D6	        ;bump col ptr        ROL.L   #8,D0	        ;get hour        MOVEQ   #2,D1	        ;and display        BSR     OUTCH        ADDQ    #1,D6        ROL.L   #8,D0	        ;display minute        MOVEQ   #2,D1        BSR     OUTCH        ADDQ    #1,D6        ROL.L   #8,D0	        ;display seconds        MOVEQ   #2,D1        BSR     OUTCHR        .IF  USERINT = 1        MOVEQ   #PCCOL,D6       ;set col for window        .ENDC        RTS        .PAGE;-------------------------------------------------------------------------;  Subroutine to display Twiggy error count;-------------------------------------------------------------------------TWGDSP  MOVEM.L D0-D1/A3,-(SP)  ;save regs        LEA     TWGRSLT,A3      ;output msg        BSR     DSPMSG        MOVE.L  #DSKCNTH,A3     ;set ptr to error count        MOVEP   (A3),D0	        ;get count        MOVEQ   #4,D1	        ;# of digits to display        BSR     OUTCHR        .IF  USERINT = 1        MOVEQ   #PCCOL,D6       ;set col for window        .ENDC        MOVEM.L (SP)+,D0-D1/A3  ;restore and exit        RTS        .ENDC        .PAGE        .IF  USERINT = 0;-------------------------------------------------------------------------;  Boot failed - see if device code should be displayed;  Assumes D0 = ASCII code to be displayed;-------------------------------------------------------------------------DSPDVC        LEA     DVCMSG,A3	        ;set msg ptr        BSR     DSPMSG		        ;and display        BSR     DSPVAL		        ;then display device code        ADDQ    #1,D5		        ;bump cursor ptrs to next row        MOVEQ   #1,D6        BRA.S   MONITOR		        ;exit to monitor        .ENDC