Lisa_Boot_ROM_RM248
.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 #,D0 ;width in pixels of menu entry
ADD D0,D6 ;compute and save
MOVE D6,6(A0,D2.W) ; lower Y coordinate
ADD #,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 #-1,D0 ; set count for header read
BSR.S READIT ; go do it
MOVEQ #-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