-not a Macintosh disk-FëbGY�a4�GY�a;0a:¶a4ÀBH±@%€,ÖÈ›Y¤Ý1Òן¸rÁŸ¸wk  ‡ Ø MW Source 10Pp� ° Ðð0Pp�°Ðð "0$P&p(�*°,Ð.ð0204P8�:°<Ð>ð@B0DPFH�JLÐNðPR0TPVpX�Z°\Ð^`b0dPfph�j°lÐnðpr0tPpx�z°|Ð~ð€‚0„P†pˆ�аŒÐŽð� ’ 0” P– p˜š °œ О ð  ¢ 0¤ P¦ p � °¬ Ю€FNDRERIK@ ôŸ¸rÇŸ¸wkDeskTop€TEXTMACAUaXŸgŸg| scrap.text€TEXTMACA`dLhŸfÝkŸfÝùsegloader.text€TEXTMACAÀ6¯Ÿfö8Ÿf÷setprefix.text€TEXTMACA 7=@ŸfÞŸfÞ_ sony.text€TEXTMACA0G RŸfÞãŸfß start.text€TEXTMACA0`KM€PŸfß>Ÿfßèstartdiag.text€TEXTMACA0À_Zö\Ÿfà Ÿfà–starthooks.text€TEXTMACA0 v‹ÈŒŸfà Ÿfá_startinit.text€TEXTMACA` ™9­<ŸfáiŸfáÄstartmain.text€TEXTMACA`` ¨/ŸfáÏŸfâ stub.text€TEXTMACA`À ªzŸfâ6ŸfâS vblcore.text€SC01SCOM` °¯ŽôXÍŸfÑ?WorkshopDTR/Lisa ¢¢RUªUªUˆ"ˆ"ˆ"ˆ"D `€€ `DÿàDÀ```||C†B†C†|~<~``ààÀàððÿÿÿþüüüÿÿÿÿðððàD?? Finder 1.0n|˜€ÿþ+à=@%<Ÿ¸rÁŸ¸w]ÿýò>ú¢ÿøÿé 4Ö %< MW Source 1 � �ÿÿ4MACAICN#mwRTO9:WFREF/2Vˆ (% w#™g¶€@ "D„‰A$�€H @@ $€"ID€?�$@‚BH€A ‘0"!ÈN�0!€€`@ç  @€€Ààð?øüÿþÿÿÿÿ€ÿÿÀÿÿàÿÿð?ÿÿøÿÿüÿÿÿþÿÿÿ?ÿÿþÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ?þüøðàÀ€ÿþ€@ ;Þøîøû÷ˆîï=ïˆ÷½ˆÞ÷ˆ÷Þ=Ûˆ÷wˆhÿÿøÿþÿÿÿÿ€ÿÿÀÿÿàÿÿðÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿø(ÿü€ø@ çðàüþÿà<Àøü?àþÿÿðÿüÿþÿÿÿÿ€ÿÿÀÿÿàÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿð€@ "D„‰A$�€H @@ $€"ID€?�$@‚BH€A ‘0"!ÈN�0!€€`@ç  @€€Ààð?øüÿþÿÿÿÿ€ÿÿÀÿÿàÿÿð?ÿÿøÿÿüÿÿÿþÿÿÿ?ÿÿþÿÿüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ?þüøðàÀ€APPLWORDTEXTPRES,SCOMICN#'ÕMWëFREFdç? Žw#™Nÿÿð @@8@(/ôþ@ @ Àþø ;Üp1Œ1Œ1Œ3Ì3Ì3Ì1Œ1Œ1Œ;Üø<<ÿÿü@PP*ª”P@?ÿÿøÿÿðÿÿø?ÿÿüÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿàÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿðÿÿø?ÿÿüÿÿüÿÿüÿÿüÿÿüÿÿüÿÿü?ÿÿøÿþÿ†@ qÊ ûê ûëø ûè ñè àè àè ñè ûè ûè ûíÈ qÍH ÈÿàÝÈUHÝÈÝÈUHÝÈÝÈUHÝÈÿÿøÿþÿÿÿÿ€ÿÿÀÿÿàÿÿðÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿþÿ†@ qÊ ûê ûëø ûè ñè àè àè ñè ûè ûè ûï qψ ÈÿñÈáÈãȈÿÿøÿþÿÿÿÿ€ÿÿÀÿÿàÿÿðÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøAPPLSC01SC00 ¢¢R$ÄòFSTR :FOBJFBNDLRMACAjICN#vFREFÊSCOMÿÿ$ø% Nÿÿ$;%,g¶ÿÿ$•Xÿÿ$Ílëÿÿ$}ÜMWÿÿ$y%('Õÿÿ$u%4:Wÿÿ$ PO9ÿÿ$ßLRTÿÿ$Û\mwÿÿ$×`Žÿÿ$—$Ô? ÿÿ$Œàdçÿÿ$�$Ø% ÿÿ$0t (ÿÿ$%xVˆÿÿ$h/2ÿÿ$dÿÿ$kä MW Source 1; FILE Scrap.text ; MACWORKS Copy ;--------------------------------------------------------------- ; ; Mac Scrap Manager ; ; This is a set of simple routines to help the applications ; manipulate the scrap for inter-application cutting and pasting. ; ; The scrap is simply a collection of typed data objects(Hi Bruce). ; in a handle that is maintained through application launches. ; There are two "Universal types," TEXT, for vanilla text, and PICT, ; for QuickDraw pictures. However, the application is free to ; add private types like SYLK. ; ; The general rules of thumb are: applications MUST be able to ; read both universal types and write at least one. This should ; insure that all applications can minimally exchange information ; through at least one level. If applications choose to write more ; than one type, the order is important; one should write the types ; in order of importance to that application. eg. a word processor ; should write out its private format first, then text, then a picture ; if desired. This implicitly states which type has the highest ; information content coming from that particular application. When ; reading the scrap one should scan for the types in the same order ; in an attempt to recover the highest information content. ; ; There are user-defined "fields" in both the TEXT and PICT types so ; the applications are encouraged to place custom data there in an ; effort to reduce the size of the scrap. As in the example above, a ; word processor might hide its formatting information in the TEXT ; comments so that only two types are written into the scrap. ; ; The script for using the scrap is: The application starts up. It ; inquires as early as possible about the scrap to determine if there ; will be enough room for the application and scrap to coexist in the ; heap. If not, it calls an unload procedure to save the scrap to disk. ; If that fails, or is deemed impossible, an alert should be raised to ; inform the user and ask for guidance. The user might just want to ; abort the application at this point. ; ; Then the application must remember that the universal scrap is ; pregnant with data when a paste command is executed. At that point ; it should dissect the scrap to find the most logical type and ; paste that into its data. An alternative is to automatically ; convert the scrap to the applications internal format so that the ; paste code can be dumb and not have to serve two masters. It is ; important to realize that the scrap data cannot be dumped until a ; cut/copy-like command is executed. While the applications runs ; there is, of course, no need to maintain or otherwise diddle with ; the universal scrap. ; ; When the application terminates, it should make every attempt to ; dump its scrap into the universal one. Obviously, if the application ; has a disk based scrap, it may be impossible to copy into memory. ; Or even with a memory based scrap, there might not be enough room ; for a "second" copy in the heap. In either case an alert should ; be raised telling the user of the applications dilemma. The user ; might at this point stay in the application and prune the scrap. ; ; When the user activates or deactivates an ornament, a similar course ; should be followed by the application. The activate and deactivate ; events contain some additional bits in the modifiers field which will ; indicate whether the transition is between a system or application ; window. If this case is true and the event is a deactivate, the ; application should call the same code as the termination sequence ; above. Of course, activate events should then parallel the startup ; scenario. ; ; ; The routines are: ; ; ScrapStuff = RECORD ; scrapSize: LONGINT; ; scrapHandle: Handle; ; scrapCount: INTEGER; ; scrapState: INTEGER; ; scrapName: StringPtr; ; END; ; pScrapStuff: ^ ScrapStuff; ; FUNCTION InfoScrap: pScrapStuff; ; returns a pointer to the scrap info ; ; FUNCTION UnloadScrap: LONGINT; ; Unloads the scrap from memory ; ; FUNCTION LoadScrap: LONGINT; ; Loads the scrap from scrap file into memory ; ; FUNCTION GetScrap( hDest: Handle; what: ResType; ; VAR offset: LONGINT ): LONGINT; ; hDest = the destination handle in which to copy the object. ; If handle is NIL, then doesn't get it. ; what = the type of object to copy ; offset returned as offset in scrap of this object ; result is -1 if it couldn't be found or a negative system ; error; set >= 0 (to size) if OK ; ; FUNCTION ZeroScrap: LONGINT; ; Cuts back the scrap to empty. ; ; FUNCTION PutScrap( length: LONGINT; what: ResType; source: Ptr ): LONGINT; ; what = the type of object to copy ; source = pointer from which to copy the object ; length = length of object at source ; ; ; Modification history: ; ; 21-Aug-83 SC Crunched eight bytes out ; 29-Aug-83 SC Changed scrap info interface ; 05-Sep-83 SC Andy found a bug... ; 07-Sep-83 SC Added scrapCount ; ;--------------------------------------------------------------- .NOLIST .INCLUDE Tlasm-SYSEQU.TEXT .INCLUDE Tlasm-SYSMACS.TEXT .INCLUDE Tlasm-SYSERR.TEXT .INCLUDE Tlasm-ToolMACS.TEXT .INCLUDE Tlasm-ToolEQU.TEXT .LIST ; 3 States of scrap (In scrapState): negative uninitialized, positive on disk, ; zero in memory ; Defs for a scrap entry scrType .EQU 0 scrLength .EQU scrType+4 scrData .EQU scrLength+4 ; Std frame off A6 scrapIO .EQU -IOFQElSize ; io cmd dLength .EQU scrapIO-4 ; disk object length dType .EQU dLength-4 ; disk object type stdLink .EQU dType ; std frame size .PROC ScrapMgr,0 .DEF InfoScrap .DEF LoadScrap .DEF UnloadScrap .DEF GetScrap .DEF ZeroScrap .DEF PutScrap ;-----------------------------------Scrap----------------------------------- ; ; FUNCTION InfoScrap: pScrapStuff; ; ;-----------------------------------Scrap----------------------------------- ; InfoScrap MOVE.L (SP)+,A0 ; RTS LEA scrapVars,A1 MOVE.L A1,(SP) JMP (A0) ;-----------------------------------Scrap----------------------------------- ; ; StdEntry ; ; This routine sets up the standard frame and builds the ; io command block for an open. Then it tries to create and then open ; the file ; ; ; Exit: ; A0 - io command block ; A3 - io command block ; D0 - IO error ; D4 - scrapInfo ; D5 - scrapHandle ; D6 - scrapState ; CC's - set according to Open or create result (e.g. IO error) ; ;-----------------------------------Scrap----------------------------------- ; StdEntry MOVE.L (SP)+,A1 ; save local return address LINK A6,#stdLink ; set up frame MOVEM.L D2-D7/A2-A4,-(SP) ; save the regs MOVE.L A1,-(SP) ; push back on return MOVEM.L scrapVars,D4/D5/D6/A2 ; preload scrapInfo,handle,state and name LEA scrapHandle,A4 ; convenient pointer LEA scrapIO(A6),A0 ; set up io command block MOVE.L A0,A3 ; Save I/O ptr in A3 MOVE.L A2,IOFileName(A0) ; set file name ptr CLR.W IODrvNum(A0) ; use default drive CLR.W IOFileType(A0) ; clear type, permissions CLR.L IOOwnBuf(A0) ; use system buffer TST D6 ; scrapState = disk BNE.S goHome0 ; skip open if not on disk ; Now try to open; if that fails, create and open the file StdOpen _Open ; try an open first BEQ.S goHome ; and escape if good CMP #OpWrErr,D0 ; if open already, pretend it's ok BEQ.S goHome0 CMP #FNFErr,D0 ; create if not there BNE.S goHome _Create ; io cmd set up BNE.S goHome BRA StdOpen ; go open now ;-----------------------------------Scrap----------------------------------- ; ; FUNCTION UnloadScrap: LONGINT; ; FUNCTION LoadScrap: LONGINT; ; ; Reminder: ; D4 = scrapLength from StdEntry ; D5 = scrapHandle ; D6 = scrapState ; A4^ scrapHandle ; ;-----------------------------------Scrap----------------------------------- ; UnloadScrap BSR StdEntry ; go set up local world BNE.S err0Exit ; escape if IO error TST D6 ; escape if on disk or un-inited BLE.S ok0Exit ; scrapState is <=0' BSR StdOpen ; go open it MOVE.L D4,D0 ; pass the length BSR.S SetupRW ; set up IO cmd _Write ; write it out BNE.S err0Exit MOVE.L D5,A0 ; get rid of the handle _DisposHandle ; ignore errors from dispose CLR.L (A4)+ ; indicate on disk(scrapHandle) CLR.L (A4)+ ; indicate on disk(scrapState) ok0Exit MOVEQ #0,D0 ; no error err0Exit EXT.L D0 MOVE.L D0,8(A6) ; return result code (link+0 param) MOVEQ #0,D0 ; see you later StdExit MOVEM.L (SP)+,D2-D7/A2-A4 ; see you later StdUNLK UNLK A6 stdRTS MOVE.L (SP)+,A0 ADD D0,SP JMP (A0) goHome0 MOVEQ #0,D0 ; jam no error goHome RTS ; return LoadScrap BSR StdEntry ; go set up the world BNE err0Exit TST D6 ; check scrap state BNE.S ok0Exit ; escape if in memory MOVE.L D4,D0 ; get scrap length _NewHandle BNE err0Exit MOVE.L A0,(A4)+ ; save the new handle(scrapHandle) ADDQ.L #1,(A4)+ ; 0 disk => 1 memory(scrapState) BSR.S SetupRW2 ; set up IO cmd for read ;jwp MOVE.L D4,IOByteCount(A0) ; set up the real byte count ;jwp _Read ; read it in BRA err0Exit ;-----------------------------------Scrap----------------------------------- ; ; Set up Read/Write for IO in command block off A6 ; Absolute pos mode at beginning ; ; Entry: ; A0 - (SetupRW2) handle for scrap ; A3 - io cmd block ; D0 - length to read or write ; D5 - scrap handle from stdEntry ; Exit: ; A0 - iocommand block ; ;-----------------------------------Scrap----------------------------------- SetupRW MOVE.L D5,A0 ; set up buffer address SetupRW2 MOVE.L (A0),IOBuffer(A3) ; to scrap handle MOVE.L D0,IOByteCount(A3) ; set up the buffer count MOVE #1,IOPosMode(A3) ; absolute position CLR.L IOPosOffset(A3) ; position to beginning MOVE.L A3,A0 ; set up for I/O RTS ; return for read or write ;-----------------------------------Scrap----------------------------------- ; ; FUNCTION ZeroScrap: LONGINT; ; ; Reminder: ; D4 = scrapLength from StdEntry ; D5 = scrapHandle ; D6 = scrapState ; ;-----------------------------------Scrap----------------------------------- ; ZeroScrap BSR StdEntry ; D0 set to 0 by above BNE err0Exit MOVE.L D0,scrapInfo ; zero out info ADDQ #8,4(A4) ; increment validation word TST D6 BEQ.S zeroDisk ; see if on disk BGT.S zeroMem ; see if in memory ; allocate a new scrap _NewHandle ; create the handle if the location BRA.S zsExit ; was negative zeroMem MOVE.L D5,A0 ; get the existing handle _SetHandleSize zsExit MOVE.L A0,(A4)+ ; save the handle(scrapHandle) MOVE (A4)+,(A4) ; positive => 1 memory(scrapState) BRA err0Exit zeroDisk CLR.L IOLEOF(A0) ; set to zero _SetEOF BRA err0Exit ;-----------------------------------Scrap----------------------------------- ; ; FUNCTION GetScrap( hDest: Handle; what: ResType; ; VAR offset: LONGINT ): LONGINT; ; ; Reminder: ; D4 = scrapLength from StdEntry ; D5 = scrapHandle ; D6 = scrapState ; ;-----------------------------------Scrap----------------------------------- ; gsOffset .EQU 8 ; VAR offset gsType .EQU gsOffset+4 ; type gsHDest .EQU gsType+4 ; destination handle gsResult .EQU gsHDest+4 ; result longint ; Utility to "get" bytes from the scrap on disk or in memeory ; ; Entry: ; D3 contains byte offset in scrap ; D0 contains amount to read ; A1 points to receiving buffer DoGet TST D6 ; see if on disk BEQ.S getDisk ; Get the data from the scrap handle in memeory MOVE.L D5,A2 ; get scrapHandle MOVE.L (A2),A0 ; set up source for move ADD.L D3,A0 ; add in offset _BlockMove BRA goHome0 ; return zero ; Get the data from the file getDisk BSR SetupRW ; fill out I/O command blk MOVE.L D3,IOPosOffset(A0) ; absolute read @ D3 MOVE.L A1,IOBuffer(A0) ; point to dest buffer _Read RTS GetScrap BSR StdEntry ; Open things up BNE.S err12Exit ; escape if file error ; Make sure scrap exists MOVEQ #noScrapErr,D0 ; scrap don't exist(nor does grammar) TST D6 ; check scrap state BMI.S err12Exit ; escape if not zeroed ; Start looking through the scrap ; ; D0 is used for read lengths ; D3 is the offset @ which to read ; A1 points to dest buffer MOVEQ #0,D3 ; start offset readNext CMP.L D4,D3 ; see if done with list BGE.S notFound MOVEQ #scrData,D0 ; read object header(8) LEA dType(A6),A1 ; buffer to place stuff BSR.S DoGet ; go get it BNE.S err12Exit okRead ADDQ.L #scrData,D3 ; point to next entry(more below) MOVE.L (A1)+,D7 ; get type from file CMP.L gsType(A6),D7 ; and compare BEQ.S foundIt ADD.L (A1)+,D3 ; by adding 8 plus length ADDQ.L #1,D3 ; round up to even BCLR D0,D3 ; assume D0 = 0 BRA readNext ; We now have D3 offset to correct entry, A1 points to object's length ; If the dest handle is nil, escape after passing back offset and D0 ; contains the length notFound MOVEQ #noTypeErr,D0 ; couldn't find type BRA.S err12LExit ; We now have D3 offset to correct entry, A1 points to object's length ; If the dest handle is nil, escape after passing back offset and D0 ; contains the length foundIt MOVE.L gsOffset(A6),A2 ; set up var address MOVE.L D3,(A2) ; return the offset to caller MOVE.L (A1),D0 ; Get object's length for return in D0 MOVE.L D0,20(A6) ; and return length for now MOVE.L gsHDest(A6),D1 ; set up destination BEQ.S go12Exit ; return length if no handle MOVE.L D1,A0 ; set it's size _SetHandleSize BNE.S err12Exit ; Do the actual fetch of the object MOVE.L (A1),D0 ; and read it's length MOVE.L (A0),A1 ; and read into dereferenced handle BSR.S DoGet BEQ.S go12Exit ; if no error(the length is stuffed above) err12Exit ; see you later EXT.L D0 ; turn OS error into a long err12LExit MOVE.L D0,20(A6) ; and return error code go12Exit ; link(8) + params(12) MOVEQ #12,D0 BRA StdExit ;-----------------------------------Scrap----------------------------------- ; ; FUNCTION PutScrap( length: LONGINT; what: ResType; pSource: Ptr ): LONGINT; ; ; Doesn't check for existing object of that type because caller ; will have always zeroed scrap prior to this. ; ; Reminder: ; D4 = scrapLength from StdEntry ; D5 = scrapHandle ; D6 = scrapState ; ;-----------------------------------Scrap----------------------------------- ; psSource .EQU 8 ; source ptr psType .EQU psSource+4 ; type psLength .EQU psType+4 ; source length psResult .EQU psLength+4 ; result PutScrap BSR StdEntry ; set up frame BSR SetupRW ; and ready for a write MOVEQ #noScrapErr,D0 ; assume the worst TST D6 ; see if on disk BMI.S err12Exit MOVEQ #scrData,D0 ; length of type LEA psType(A6),A0 ; save type and length BSR.S DoPut ; ignore error, catch it below MOVE.L psSource(A6),A0 ; get source ptr MOVE.L psLength(A6),D0 ; save the length's worth MOVEQ #-2,D1 ; evenizer mask ADDQ.L #1,D0 ; round up to even AND.L D1,D0 BSR.S DoPut ; errors handled on exit MOVE.L D4,-(A4) ; and save new scrap length(ScrapInfo) BRA.S err12Exit ; see you later D0 set from above DoPut MOVE.L D4,IOPosOffset(A3) ; set file position to old size ADD.L D0,D4 ; add this length to get new size TST D6 ; see if on disk BEQ.S putDisk MOVE.L D5,A1 ; get scrap handle _PtrAndHand ; add on to handle RTS putDisk MOVE.L A0,IOBuffer(A3) ; stuff ptr to data MOVE.L D0,IOByteCount(A3) ; 8 bytes of I/O MOVE.L A3,A0 ; restore I/O command _Write RTS .END }x;File SegLoader.Text ; MACWORKS copy ;--------------------------------------------------- ; ; Segment Loader for MacIntosh Operating System ; ; written by Andy Hertzfeld 09-May-83 ; ; ; Here is the new resource-based segment loader. It ; is capable of loading multiple Lisa-style code segments ; using a jump table scheme similar to the Lisa "physical ; executable" format. ; ; The loader is also the part of the system that cuts back ; the application heap and builds an "A5 world" for the ; application. ; ; The loader will preserve the handle in low memory called ; "theScrap" across world swaps. ; ; Modification History: ; ; 29-May-83 AJH Changed jumptable from 10 bytes/entry to 8 bytes/entry ; 01-Jun-83 AJH preserved theScrap; added page two options ; 02-Jun-83 AJH fixed bug in ExitToShell to push page 2 word ; 04-Jun-83 AJH made Launch clear D7 & 20(A5) for stupid Lisa Pascal ; 08-Jun-83 AJH increased size of appName; made it use AppParmHandle ; 11-Jun-83 AJH cleaned up BadOpen error exit stuff ; 16-Jun-83 AJH made it InitApplZone early so it only opens once ; 16-Jun-83 AJH made it compact before locking code segments ; 17-Jun-83 AJH fixed bug (no InitApplZone) introduced yesterday ; 06-Aug-83 BLH Added initialization of DragHook, DeskHook, CloseOrnHook, ; restProc, saveProc, saveSP, taskLock, fScaleDisable, ; resErrHook right after InitApplZone. These all used to ; be in InitWindows (except fScaleDisable). ; 08-Aug-83 AJH removed compact before locking (now rMgr does it!) ; 09-Aug-83 SC Fixed bug in scrap stuff(D0 lost through NewHandle) ; 10-Aug-83 AJH moved LoadTrap to LoadSeg; loader calls SetApplLimit ; 11-Aug-83 AJH made it preserve scrap by moving it to stack ; 12-Aug-83 AJH moved globals to SysEqu; use deepShit alert in SysErr ; made ExitToShell use a low memory pBlock ; save parameters in lomem earlier ; 13-Aug-83 SC Dropped flushevents ; 16-Aug-83 AJH Compute screen sound address relative to memTop (instead of ; ScreenBase) ; 18-Aug-83 SC Changed theScrap to scrapHandle and changed BEQ to BLE ; 19-Aug-83 LAK Now inits StkLowPt. ; 06-Sep-83 AJH BadOpen now deep shits ; 10-Sep-83 AJH Fixed bug -- it wasn't releasing segment 0! ; 25-Sep-84 KWK If no Current Application, still does Goodbye kiss loop ; ;-------------------------------------------------------- ; .INCLUDE TlAsm-SYSEQU.TEXT .INCLUDE TlAsm-SYSMACS.TEXT .INCLUDE TlAsm-GRAFEQU.TEXT .INCLUDE TlAsm-GRAFTYPES.TEXT .INCLUDE TlAsm-TOOLEQU.TEXT .INCLUDE TlAsm-ResEqu.Text .INCLUDE TlAsm-QuickMacs.TEXT .INCLUDE TlAsm-ToolMacs.TEXT .INCLUDE TlAsm-SysErr.TEXT .PROC Loader,0 .DEF Launch,Chain,ExitToShell .DEF InstallRDrivers .DEF LoadSeg,UnloadSeg .DEF GetAppParms .REF MakeStkPB ; segment header definitions SegJTOffset .EQU 0 ; offset of 1st jumpTable entry SegJTEntries .EQU 2 ; number of jumpTable entries SegHdrSize .EQU 4 ; the header is four bytes long ; misc definitions SegLoadTrap .EQU $A9F0 ; LoadSeg trap ID ;------------------------------------------------------------------------------ ; ; PROCEDURE LoadSeg(segID: INTEGER); ; ; LoadSeg is used to load a segment and patch all the jump table entries for ; that segment. It is usually called from the jump table entry and almost ; never called directly by the application. It then transfers control ; to the newly loaded code. ; ; All registers are preserved until the newly loaded code is launched. ; If the segment can't be found, a deep shit alert is posted. ; ;------------------------------------------------------------------------------ LoadSeg MOVEM.L D0-D2/A0-A1,-(SP) ;all registers must be preserved MOVE.W 24(SP),D0 ;get the segment ID BSR.S LoadCode ;ask resources to load the segment BEQ.S SegError ;if not, give up BSET #7,(A0) ;lock it down MOVE.L (A0),-(SP) ;handle -> pointer CLR.B (SP) ;clear the high byte MOVE.L (SP)+,A0 ;get the pointer MOVE.L A5,A1 ;copy world base address ADD.W CurJTOffset,A1 ;offset by the current offset ADD.W SegJTOffset(A0),A1 ;compute address of 1st entry CMP.W #$4EF9,4(A1) ;is it already loaded? BEQ.S GoLaunch ;if so, don't bother to load ; we must patch the jump table to point to the newly loaded segment. At this ; point A1 points to the first jump table entry. MOVE.W SegJTEntries(A0),D0 ;get the number of entries BEQ.S GoLaunch ;if none, just go launch it MOVE.W 24(SP),D1 ;get the segment ID MOVEQ #0,D2 ;clear out high part of D2 PatchJTLoop MOVE.W (A1)+,D2 ;pick up the offset MOVE.W D1,-2(A1) ;remember the segment ID in entry MOVE.W #$4EF9,(A1)+ ;patch in the "JMP.L" opcode PEA SegHdrSize(A0,D2.L) ;compute the entry point address MOVE.L (SP)+,(A1)+ ;move in the entry point address SUBQ #1,D0 ;more entries to do? BNE.S PatchJTLoop ;loop till done ; now we can transfer control to the newly loaded code at the proper entry point GoLaunch MOVE.L 20(SP),A1 ;get the return address from the trap SUBQ.L #6,A1 ;back up to the JMP.L opcode MOVE.L A1,22(SP) ;patch the return address MOVEM.L (SP)+,D0-D2/A0-A1 ;restore the registers ADDQ #2,SP ;strip parameter TST.B LoadTrap ;debugging on? BEQ.S @1 ;go launch if its not .WORD $A9FF ;invoke debugger @1 RTS ;launch the code! ; here is the error handler for when we couldnt load a segment we need. Its ; a deep shit alert. SegError MOVEQ #DSLoadErr,D0 ;get deep shit ID _SysError ;invoke deep shit - dont come back .WORD $A9FF ;trap to debugger, just in case ; LoadCode is a code saving utility that loads the segment with the resource ID ; specified in D0. It returns the segment handle in A0 LoadCode SUBQ #4,SP ;make room for function result MOVE.L #CodeRType,-(SP) ;push "CODE" MOVE.W D0,-(SP) ;push the segment ID _GetResource ;load it MOVE.L (SP)+,A0 ;get result in A0 MOVE.L A0,D0 ;better set Z-flag based on result RTS ;return to caller ;------------------------------------------------------------------------------ ; ; PROCEDURE UnloadSeg(routineAddr: Ptr); ; ; UnLoadSeg is used to unload a segment when the application feels its no ; longer needed for a while. It patches all of the segment's jump table ; entries back to the "load me" state. The parameter is the address of any ; routine within the segment. ; ;------------------------------------------------------------------------------ UnloadSeg MOVE.L 4(SP),A0 ;get the address of the routine CMP.W #$4EF9,(A0) ;is it already unloaded? BNE.S DoneUnload ;if so, we're done ; the first thing we must do is figure out the handle of the segment MOVE.W -2(A0),D0 ;get the segment ID BSR.S LoadCode ;get the segment handle BCLR #7,(A0) ;unlock it MOVE.L (A0),A0 ;handle -> pointer MOVE.L A5,A1 ;copy world base address ADD.W CurJTOffset,A1 ;offset by current offset ADD.W SegJTOffset(A0),A1 ;compute address of 1st entry MOVE.W SegJTEntries(A0),D0 ;get the number of entries BEQ.S DoneUnload ;if zero, we're all done ; loop through each jump table entry, patching it back to the "load me" state UnpatchLoop MOVE.W (A1),D1 ;remember the segment ID MOVE.L 4(A1),D2 ;get the current address SUB.L A0,D2 ;subtract the segment base address SUBQ.L #SegHdrSize,D2 ;subtract the header size MOVE.W D2,(A1)+ ;move in the offset MOVE.W #$3F3C,(A1)+ ;move in the "push immediate" opcode MOVE.W D1,(A1)+ ;move in the segment ID MOVE.W #SegLoadTrap,(A1)+ ;move in the "SegLoad" trap SUBQ #1,D0 ;more to do? BNE.S UnpatchLoop ;loop until done ; we're all done with unloading the segment so strip the parameter and ; return to the caller DoneUnload MOVE.L (SP)+,(SP) ;strip the parameter RTS ;return to caller ;------------------------------------------------------------------------------ ; ; PROCEDUREs Launch, Chain, ExitToShell: ; ; Here is the main part of the segment loader that actually launches ; an application. It opens the resource file specified by the input name, ; loads segment 0 to get the jumptable and global size information, optionally ; cuts back the application heap and kicks off the application by invoking ; its first jump table entry. ; ; ; Warning -- LAUNCH obliterates the application heap so if an error occurs ; (like the file isn't executable) the code that called us is no longer ; "in the zone". Callers of LAUNCH should be very careful...(they probably ; should use a deep shit alert to put up a message and then re-launch themselves) ; ;------------------------------------------------------------------------------ ; This part of the code is here so it can be accessible by short branches. ; Compute the address of sound page 2 and go modify the stackBase if ; neccessary. SoundPage2 MOVE.L MemTop,D0 ;get address of top of RAM SUB.L #$00005F00,D0 ;compute address of sound page 2 BRA SetNewStack ;modify stackBase if necessary ; First we have some an alternate entry point "Chain" which is just like ; launch except it doesn't cut back the heap. Chain CLR.W LaunchFlag ;flag not to cut back heap BRA.S LaunchCom ;fall into common code ; Here is the main entry point for launch Launch ST LaunchFlag ;flag that we should cut back the heap LaunchCom MOVE.W 4(A0),CurPageOption ;remember page 2 options word MOVE.L (A0)+,A0 ;save name ptr LEA CurApName,A1 ;get address to stuff the name MOVEQ #32,D0 ;move 32 bytes worth _BlockMove ;move it in ; first close any previously open application, if any MOVE CurApRefNum,D0 ;get refnum of current application BLE.S SkipClose ;if none, skip the close MOVE.W D0,-(SP) ;push the refNum _CloseResFile ;close it CLR.W CurApRefNum ;flag that no application is open ; kwk -- moved skipclose above loop for goodbye kiss checking, thus always checks, ; even if no current application (normal state if not in Finder). ;jwp ; at this point, the loader is about to dismantle the applications heap zone. ; loop through the unit table, making a farewell call to any driver that wants ; one (before we obliterate the application zone) SkipClose MOVEM.L D0-D1/A0-A1,-(SP) ;save registers SUB #IOQElSize,SP ;allocate pBlock MOVE #-1,CSCode(SP) ;set up control code MOVE.L UTableBase,A1 ;point to unit table MOVE.W UnitNtryCnt,D1 ;get # of entries in unit table GoodByeLoop MOVE.L (A1)+,D0 ;get the DCE handle BEQ.S NextGoodBye ;if NIL, none installed MOVE.L D0,A0 MOVE.L (A0),A0 ;get DCE ptr BTST #DNeedGoodbye,DCtlFlags(A0) ;need a goodbye kiss? BEQ.S NextGoodBye ;if not,skip ; we found one that wants a goodBye call so issue the control call MOVE.W DCtlRefNum(A0),IORefNum(SP) ;set up the refNum MOVE.L SP,A0 ;point to the DCE _Control ;kiss it goodbye... NextGoodBye SUBQ #1,D1 ;more to do? BNE.S GoodByeLoop ;if so, loop ADD #IOQElSize,SP ;deallocate pBlock MOVEM.L (SP)+,D0-D1/A0-A1 ;restore registers ;jwp ; now initialize the application heapZone, if we're launching MOVE.L BufPtr,SP ;start stack under screen/debugger CLR.L StkLowPt ;keep VBL task out TST.W LaunchFlag ;is it a launch? BEQ.S OpenApp ;if not, skip ; before obliterating the heap, save the scrap on the stack MOVE.L scrapHandle,D0 ;get the scrap handle BLE.S GoInitAZone ;if none, skip MOVE.L D0,A0 ;get the handle _GetHandleSize ;get its size ;jwp - make sure that the scrap handle is never an odd size ADDQ.L #1,D0 ;round up to nearest even number BCLR #0,D0 ;jwp SUB.L D0,SP ;allocate space for it MOVE.L SP,A1 ;set up destination for move MOVE.L (A0),A0 ;set up source for move MOVE.L D0,-(SP) ;remember the size _BlockMove ;move it! ; re-init the application heap zone, destroying the world... GoInitAZone _InitApplZone ;cut back the heap CLR.W CurApRefNum ;InitApplZone closes resource files ;allocate a new handle for the scrap to be copied into, if necessary. TST.L scrapHandle ;did we have a scrap? BLE.S SkipScrap ;if none, skip ; we had a scrap so better allocate a new handle for it and rescue its contents ; from the stack MOVE.L (SP)+,D1 ;get the size of the scrap MOVE.L D1,D0 ;set up size for NewHandle _NewHandle ;allocate a handle for it MOVE.L A0,scrapHandle ;remember the handle MOVE.L D1,D0 ;get size for blockMove MOVE.L (A0),A1 ;get destination pointer MOVE.L SP,A0 ;get source pointer _BlockMove ;move it in! ADD.L D1,SP ;deallocate scrap save buffer SkipScrap _RDrvrInstall ;fix up ram based drivers ; now that the heaps in good shape, open the new application file after reiniting ; some important hooks and globals OpenApp CLR.L DragHook ;No drag hook yet CLR.L DeskHook ;No desk hook for hit-testing desk. LEA CloseOrnHook, A0 ; Point to closeOrnHook CLR.L (A0)+ ;clear closeOrnHook CLR.L (A0)+ ;clear RestProc CLR.L (A0)+ ;clear saveProc CLR.W TaskLock ;clear taskLock, fScaleDisable. CLR.L ResErrProc ;and resource error proc. ; open the application resFile (which will pre-load some resources) SUBQ #2,SP ;make room for function result PEA CurApName ;push file name ptr _OpenResFile ;open it MOVE.W (SP)+,CurApRefNum ;remember it in low memory BLE BadOpen ;branch if open wasn't successful ; now load in segment 0, which has the A5 world information as well as the ; jump table MOVEQ #0,D0 ;get ID for segment 0 BSR LoadCode ;load it in =>seg handle in A0 BEQ BadOpen ;if we failed, report error MOVE.L A0,SaveSegHandle ;remember code 0 handle in loMem ; set up A5 and A7 for this application MOVE.L (A0),A0 ;point to seg 0 info ; adjust the stack base according to the page 2 options word TST.W CurPageOptions ;are any page 2 options requested? BEQ.S SetA5 ;if not, go build A5 world BPL.S SoundPage2 ;if so, go handle sound page 2 MOVE.L MemTop,D0 ;start at memTop SUB.L #$0000D900,D0 ;compute video page 2 address SetNewStack CMP.L SP,D0 ;should we move down the stack BGE.S SetA5 ;if not, skip MOVE.L D0,SP ;move it down SetA5 SUB.L (A0)+,SP ;allocate "above A5" space MOVE.L SP,A5 ;set up A5 SUB.L (A0)+,SP ;allocate "below A5" space MOVE.L A5,CurrentA5 ;remember A5 for this application MOVE.L SP,CurStackBase ;remember stack for this one, too MOVE.L SP,StkLowPt ;for heap-stack crashes ; move in the jump table to where it belongs MOVE.L (A0)+,D0 ;get the jump table size MOVE.L (A0)+,A1 ;get the load offset MOVE.W A1,CurJTOffset ;remember the offset ADD.L A5,A1 ;add in the base address LEA 2(A1),A3 ;remember the launch address _BlockMove ;move it in ; now that things are set up, we can release segment 0 MOVE.L SaveSegHandle,-(SP) ;push the segment 0 handle _ReleaseResource ;de-allocate it ; set up the parameters to the application LEA 8(A5),A0 ;point to parameter area CLR.L (A0)+ ;standard input CLR.L (A0)+ ;standard output MOVE.L AppParmHandle,(A0)+ ;parameter pointer CLR.W (A0)+ ;physExec flag for stupid Lisa Pascal ; set the default application heap zone limit based on the current stack MOVE.L SP,A0 ;get the stack SUB.L DefltStack,A0 ;subtract buffer zone _SetApplLimit ;set the new limit ; OK, we can actually kick off the application now. MOVEQ #0,D7 ;clear D7 for stupid Pascal JSR (A3) ;launch the application ; If we reached this point, the application must have successfully terminated. ; Close its resource file and chain back to the finder. ExitToShell MOVE.W CurApRefNum,-(SP) ;push the app's refnum _CloseResFile CLR.W CurApRefNum ;jwp SUB.L A0,A0 ; clear out A0 _SetGrowZone ; disable application's growZone handler SUBQ #4,SP ; load the scrap into memory _LodeScrap ADDQ #4,SP ; trashes pascal regs JSR MakeStkPB MOVE.W BootDrive,IOVRefNum(A0) ; prefix to 'boot' drive _SetVol ADD #IOVQElSize,SP ; clean up stack ;jwp LEA LoaderPBlock,A0 ;point to lomem param block MOVE.L A0,A1 ;copy to A1 PEA FinderName ;get finder name pointer MOVE.L (SP)+,(A1)+ ;put finder name ptr in pBlock CLR.L (A1)+ ;no page 2 usage BRA Launch ;launch it! ; here is the error handler for when we can't open the file. We've already ; obliterated the world (possibly) so just deep shit BadOpen MOVEQ #DSBadLaunch,D0 _SysError ;post the error .WORD $A9FF ;invoke debugger ;------------------------------------------------------------------------------ ; ; PROCEDURE GetAppParms(VAR apName: Str255; ; VAR apRefNum: INTEGER; ; VAR apParam: Ptr) ; ; GetAppParms is a utility routine that returns some information about the ; currently executing application. It returns its name (the first 24 ; characters, anyway), its resource refNum and a pointer to the parameter ; block passed by the finder. ; ;------------------------------------------------------------------------------ GetAppParms MOVE.L (SP)+,A0 ;pull off the return address MOVE.L (SP)+,A1 ;get pointer to apParam MOVE.L 16(A5),(A1) ;return a pointer to finder pBlock MOVE.L (SP)+,A1 ;get pointer to apRefNum MOVE.W CurApRefNum,(A1) ;pass back the refNum MOVE.L (SP)+,A1 ;point to place to stuff name string MOVE.L A0,-(SP) ;replace return address LEA CurApName,A0 ;point to name in low memory MOVEQ #32,D0 ;move 32 bytes _BlockMove ;move it! RTS ;return to caller (params already stripped) ;------------------------------------------------------------------------------ ; ; InstallRDrivers fixes up the unit table after the application heap ; is obliterated between applications. ; ;------------------------------------------------------------------------------ InstallRDrivers MOVEM.L D0-D4/A0-A3,-(SP) ; loop through the unit table, checking for drivers in the application heap MOVE.L UTableBase,A3 ; get pointer to unit table MOVE.W UnitNtryCnt,D3 ; get # of entries in unit table MOVEQ #-1,D4 ; the first unit is refNum -1 IRDLoop MOVE.L (A3)+,D0 ; get the DCE handle BEQ.S NextIRD ; if NIL, skip MOVE.L D0,A1 ; get handle in A-reg MOVE.L (A1),A1 ; get DCE ptr BTST #DRamBased,DCtlFlags+1(A1) ;is it ROM-based? BEQ.S NextIRD ; if so, skip MOVE.L DCtlDriver(A1),D0 ; get driver handle BEQ.S NextIRD ; if none, skip CMP.L ApplZone,D0 ; which zone is it in? BLT.S DoSysZDriver ; special case ones in the system zone ; we got a driver in the application heap, so re-init its DCE MOVEQ #DCtlEntrySize-1,D0 ; get size in bytes MOVE.L A1,A0 ; point to DCE start @1 CLR.B (A0)+ ; clear a byte DBRA D0,@1 ; loop till cleared ; flag it as RAM-based and set up the refNum BSET #DRamBased,DCtlFlags+1(A1) MOVE.W D4,DCtlRefNum(A1) ; set up the refNum (queue inited to 0s) ; inspect the next table entry NextIRD SUBQ #1,D4 ;decrement refNum SUBQ #1,D3 ;more to do? BNE.S IRDLoop ;loop until done MOVEM.L (SP)+,D0-D4/A0-A3 RTS ; all done! ; handle drivers on the system zone by zero their window or storage ; if its in the application zone DoSysZDriver CLR.L DCtlWindow(A1) ; zero its window MOVE.L DCtlStorage(A1),D0 ; get its storage handle CMP.L ApplZone,D0 ; is it in the system zone? BLT.S NextIRD ; if so, its cool CLR.L DCtlStorage(A1) ; clear it cause its invalid BRA.S NextIRD ; go do the next one .END $EXEC{setprefix.text, sets the prefix to be Arg0} F{iler}P{refix}%0{prefix 1} {no change to prefix 2} {no change to prefix 3} {don't set for boot} Q{uit the filer} $ENDEXEC }; FILE Sony.text ; MACWORKS original ;_______________________________________________________________________ ; ; ; Lisa/Mac Sony Disk Driver ; ; written by Jeff Parrish 23-Oct-83 ; ; 19-Jun-84 KWK Fixed DiskPrime/DiskDone to position for read/write ; and update correctly. ; 02-Jul-84 KWK/RDC Really fixed DiskPrime (ChkDrvNum changes A1!) ;_______________________________________________________________________ .NOLIST .INCLUDE Tlasm-SysEqu.Text .INCLUDE Tlasm-SysErr.Text .INCLUDE Tlasm-SysMacs.Text .INCLUDE Tlasm-SonyEqu.Text .LIST .PROC DiskDrvr,0 .REF InitQueue,EnQueue,JmpTblInit .DEF AddDrive ; ; Here is the driver format header ; SonyDrvr .WORD $4F00 ; read, write, control, status, needs lock .WORD 0,0 ; no delay or EMask .WORD 0 ; no menu ; Entry point offset table .WORD DiskOpen-DiskDrvr ; open .WORD DiskPrime-DiskDrvr ; prime .WORD DiskControl-DiskDrvr ; control -- eject is call 1 .WORD DiskStatus-DiskDrvr ; status -- call 1 for info .WORD DiskClose-DiskDrvr ; close -- just RTS (NOT CLOSABLE) .BYTE 5 .ASCII '.Sony' ;------------------------------------------------------------------------- ; ; Routine: DiskOpen ; ; Arguments: A1 (input) -- pointer to DCE ; A0 (input) -- pointer to control call parameter block: ; D0 (output) -- result code ; ;------------------------------------------------------------------------- DiskOpen MOVEQ #,D0 ; get memory for driver variables ADD.L D0,D0 _NewPtr ,SYS,CLEAR MOVE.L A0,SonyVars ; and keep pointer in low memory MOVE.L A0,A2 ; save for later MOVE.L A1,(A0) ; save DCE pointer MOVE.B #$80,DCtlQueue+1(A1); set up driver version byte MOVE.W DCtlRefNum(A1),D2 ; this driver LEA DrvQHdr,A1 ; initialize the drive queue, too JSR InitQueue MOVEQ #Drv1,D0 ; init drive 1 CLR.B WriteProt(A2,D0) ; start out not write protected CLR.B DiskInPlace(A2,D0) ; and no disk inplace MOVE.B #$1,Installed(A2,D0); and drive is installed CLR.B Sides(A2,D0) ; and 1 sided LEA DQEL(A2,D0),A0 ; first drive queue element MOVEQ #1,D0 BSR.S ToAddDrive MOVE.W #800,DQDrvSize(A0) ; block size for sonys - format package ADD.W #DrvLclLth,A0 ; init drive 2 CLR.B WriteProt(A0) ; start out not write protected CLR.B DiskInPlace(A0) ; and no disk inplace MOVE.B #$1,Installed(A0) ; and drive is installed TST.B $624 ; is there really an external drive? BNE.S @1 ST Installed(A0) ; no @1 CLR.B Sides(A0) ; and 1 sided MOVEQ #2,D0 BSR.S ToAddDrive MOVE.W #800,DQDrvSize(A0) ; block size for sonys - format package MOVEQ #0,D0 ; return no error from DiskOpen RTS ;------------------------------------------------------------------------- ; ; Routine: DiskClose ; ; Arguments: A1 (input) -- pointer to DCE ; A0 (input) -- pointer to control call parameter block: ; D0 (output) -- result code ; ;------------------------------------------------------------------------- DiskClose MOVEQ #0,D0 ; no errors RTS ;------------------------------------------------------------------------- ; ; Routine: AddDrive ; ; Arguments: A0 (input) -- pointer to block of mem for queue. ; D0 (input) -- high word = drive # ; low word = driver refnum ; A1 (output) -- pointer to drive queue header. ; ;------------------------------------------------------------------------- ToAddDrive SWAP D0 MOVE.W D2,D0 AddDrive MOVE.L D0,DQDrive(A0) ; drive number and driver refnum LEA DrvQHdr,A1 ; put into the drive queue JMP Enqueue ;------------------------------------------------------------------------- ; ; Routine: DiskDone ; ; Arguments: D0 (input) -- last error ; A1 (output) -- pointer to disk DCE ; ;------------------------------------------------------------------------- DiskDone MOVE.W D0,DskErr ; save last error for file system MOVE.L sonyVars,A1 ; get pointer to locals CLR.B active(A1) ; reset disk active MOVE.L DiskUnitPtr(A1),A1 ; and pointer to disk DCE MOVE.L JIODone,-(SP) RTS ; use IODone vector ;------------------------------------------------------------------------- ; ; Routine: DiskControl ; ; Arguments: A0 (input) -- pointer to control call parameter block: ; CSCode = 1 for KillIO ; 5 for Verify ; 6 for Format ; 7 for Eject ; 8 for setting tag buffer ; A1 (input) -- pointer to disk DCE ; D1 (?????) -- ; D0 (output) -- result code ; ;------------------------------------------------------------------------- DiskControl MOVEM.L D6/A0-A1,-(SP) MOVE.W CSCode(A0),D6 SUBI.W #2,D6 ; change 5,6,7,8 to 3,4,5,6 for sony cntlr CMPI.W #6,D6 ; is it a good command? BGT.S DiskDone ; no CMPI.W #3,D6 ; is it still a good command? BMI.S DiskDone ; no BSR CkDrvNum ; check for valid drive number BNE Done ; exit if bad drive error CMPI.W #6,D6 ; should we set up a new tag buffer? BNE.S @1 MOVE.L CSParam(A0),TagBufPtr(A1) ; set or clear ptr to separate buffer CLR.W D0 ; no errors. BRA.S Done ; always a good exit @1 MOVE.W IOVDrvNum(A0),D4 ; which drive MOVE.L SonyStart,A3 ; get start of disk 1 routines MOVEM.L D1-D6,-(SP) ; save our registers JSR (A3) ; call UnitIO to access the disk MOVEM.L (SP)+,D1-D6 ; replace our registers BEQ.S @2 ; no errors? NEG.W D0 ; make sure all errors are negative CMPI.W #-$15,D0 ; unable to verify a track? BNE.S @2 MOVE.W #DataVerErr,D0 ; bad verify @2 CMPI.W #5,D6 ; was it an eject command? BNE.S Done ; no - then skip the DIP stuff MOVE.L sonyVars,A1 ; get location of twiggy locals MOVE.W #Drv1,D6 ; assume drive 1 CMPI.B #2,D4 ; drive 1 or 2? D0=1,2 for drive 1,2 BMI @3 MOVE.W #Drv2,D6 ; offset to drive 2's locals @3 MOVE.B #0,DiskInPlace(A1,D6); save the disk state Done MOVEM.L (SP)+,D6/A0-A1 BRA DiskDone ;------------------------------------------------------------------------- ; ; Routine: DiskStatus ; Arguments: A0 (input) -- pointer to status call parameter block: ; CSCode = 8 for drive status ; CSParam: ; (0) current track location ; (2) bit7=1=write-protected ; (3) $FC-$FF= just ejected, ; 0=no DIP, 1=DIP, 2=clamped ; (4) 0=don't know, 1=inst., $FF=not inst. ; (5) bit7=0=1 sided ; (6) drive queue element ; (18) $FF for 2-sided format this diskette ; (19) $FF if diskprime called ; (20) soft error count (word) ; ; ; Function: The status call returns current status for the drive requested. ;------------------------------------------------------------------------- DiskStatus MOVEM.L D4/D6/A1/A3,-(SP) MOVEQ #StatusErr,D0 ; assume status error CMP.W #DrvStsCode,CSCode(A0) ; drive status call? BNE.S DiskDone ; exit for other calls BSR.S CkDrvNum BNE.S DiskDone ; ; check if the disk is write protected first - then pass back all info ; ADD.W D1,A1 ; sonyVars+driverOffset CLR.B WriteProt(A1) ; assume the disk is not write-protected MOVE.W IOVDrvNum(A0),D4 ; which drive MOVE.W #6,D6 ; check for write-protected disks MOVE.L SonyStart,A3 ; get start of disk 1 routines MOVEM.L D1-D6/A0-A1,-(SP) ; save our registers JSR (A3) ; call UnitIO to access the disk MOVEM.L (SP)+,D1-D6/A0-A1 ; replace our registers BEQ.S @0 BSET #7,WriteProt(A1) ; the disk was write protected @0 LEA CSParam(A0),A0 ; return all drive vars except speeds MOVEQ #11,D0 ; 11 words @1 MOVE.W (A1)+,(A0)+ ; move it in a word at a time SUBQ.W #1,D0 BGT.S @1 ; leave D0=0 MOVEM.L (SP)+,D4/D6/A1/A3 BRA.S DiskDone ;------------------------------------------------------------------------- ; ; Routine: CkDrvNum ; Arguments: ; A0 (input) -- pointer to the I/O parameter block ; A1 (output) -- pointer to the sonys local vars (DCE) ; D0 (output) -- result code ; D1 (output) -- offset to drive 1, or 2's locals ;------------------------------------------------------------------------- CkDrvNum MOVE.L SonyVars,A1 ; get pointer to locals MOVE.W IOVDrvNum(A0),D0 BEQ.S @1 ; drive number must be 1 or 2 CMP.W #2,D0 BGT.S @1 MOVE.W D0,Drive(A1) ; drive in question BSR GetDrv1 MOVEQ #0,D0 RTS @1 MOVEQ #NSDrvErr,D0 ; bad drive number RTS ;------------------------------------------------------------------------- GetDrv1 MOVE.L SonyVars,A1 ; ptr to driver locals CMP.W #1,Drive(A1) ; drive 1 (internal drive)? BEQ.S @1 ; br if so MOVE.W #Drv2,D1 ; external drive's var offset RTS @1 MOVEQ #Drv1,D1 ; internal drive's var offset RTS ;------------------------------------------------------------------------- ; ; Routine: DiskPrime ; ; Arguments: A0 (input) -- pointer to control call parameter block ; A1 (input) -- pointer to device control entry ; D0 (output) -- result code ; ;------------------------------------------------------------------------- DiskPrime MOVEM.L D2-D7/A2-A4,-(SP) MOVE.L A1,A2 ; save the DCE (kwk) ANDI.W #$F01F,SR ; turn interrupts on BSR.S CkDrvNum ; check for valid drive number BNE Fini ; exit if bad drive error MOVE.W IOTrap(A0),D3 ; save I/O command AND.W #$FF,D3 ; clear out the top byte of the trap SUBQ.B #2,D3 ; 2=read,3=write => 0=read,1=write MOVE.L SonyStart,A3 ; get start of disk 1 routines MOVE.L TagBufPtr(A1),A4 ; ptr to user tag data buffer MOVE.W IOVDrvNum(A0),D4 ; which drive MOVE.W D3,DiskCmd(A1) ; save I/O command in locals MOVE.L IOBuffer(A0),D1 ; get pointer to io buffer MOVE.L IOByteCount(A0),D2 ; get # of bytes requested ;kwk MOVE.L DctlPosition(A2),D3 ; true position to read from ;(kwk) LSR.L #$7,D3 ; divide by 512 to get block position LSR.L #$2,D3 MOVE.W #1,D6 ; assume we are going to read the disk TST.W DiskCmd(A1) ; is it a read? BEQ.S DiskDo MOVE.W #2,D6 ; it is a write ;------------------------------------------------------------------------- ; the registers at this point are: ; ; x D1 pointer to io buffer (long) ; x D2 number of bytes to r/w (long) ; x D3 starting block position (word) ; x D4 drive 1, or 2 (word) ; x D6 read or write specifier (word) ; ; A0 pointer to control call parameter block ; A1 pointer to locals ; ? A2 pointer to DCE (kwk) ; x A3 entry point of Sony disk routines ; x A4 pointer to user tag data buffer ; ; x means that the register is used by UnitIO ;------------------------------------------------------------------------- DiskDo MOVEM.L D1-D7/A0-A2,-(SP) ; save our registers (kwk) JSR (A3) ; call UnitIO to access the disk MOVEM.L (SP)+,D1-D7/A0-A2 ; replace our registers BEQ.S Fini ; no errors? NEG.W D0 ; make sure all errors are negative CMPI.W #-$7,D0 ; no diskette? BNE.S @0 MOVE.W #OffLinErr,D0 ; must have been! BRA.S Fini @0 CMPI.W #-2,D0 ; no such drive installed? BNE.S @1 MOVE.W #NoDriveErr,D0 ; must have been! BRA.S Fini @1 CMPI.W #-$14,D0 ; write protected? BNE.S @2 MOVE.W #WPrErr,D0 ; must have been! BRA.S Fini @2 CMPI.W #-$17,D0 ; unable to read the disk? BNE.S Fini MOVE.W #DataVerErr,D0 ; must have been! Fini ;kwk -- update position & # read correctly TST.W D0 ; check for no errors BNE.S @3 ; don't do any updating ADD.L D2,DctlPosition(A2) ; update absolute position MOVE.L D2,IONumDone(A0) ; set # of bytes read ;(kwk) @3 MOVEM.L (SP)+,D2-D7/A2-A4 BRA DiskDone .END ; FILE START.TEXT ; MACWORKS copy ;___________________________________________________________________________ ; ; System Initialization Routines ; ; written by Larry Kenyon 11-Feb-83 ; ; This file is the top-level file for the Start.Obj code file. This ; code is the first code executed upon system power-up or reset. ; It is used to verify correct functioning of the MAC, initialize the ; OS dispatch table, initialize the basic system, and read in the boot ; blocks off the disk. ; ; ; Modification History: ; ; 11 Feb 83 LAK new today (from old Boot) ; 27 Feb 83 AJH integrated deep shit manager ; 13 Apr 83 AJH no more talk (talk is not cheap) ; 17 Apr 83 AJH added trap for plot compressed icon ; 14 Jul 83 SC Removed D0Info, D1Info1 and made inline in CritErr w/4x6 font ; ; ;___________________________________________________________________________ ;_________________________________; ; ; ; RAM-less subroutine call macros ; ;_________________________________; .MACRO BSR3 LEA @1,A3 BRA %1 @1 .ENDM .MACRO RTS3 JMP (A3) .ENDM .MACRO BSR4 LEA @1,A4 BRA %1 @1 .ENDM .MACRO RTS4 JMP (A4) .ENDM .MACRO BSR5 LEA @1,A5 BRA %1 @1 .ENDM .MACRO RTS5 JMP (A5) .ENDM .MACRO BSR6 LEA @1,A6 BRA %1 @1 .ENDM .MACRO RTS6 JMP (A6) .ENDM ;________________________; ; ; ; Start of Boot ROM Code ; ;________________________; .NOLIST .INCLUDE Tlasm-SYSEQU.TEXT .INCLUDE Tlasm-SYSERR.TEXT .INCLUDE Tlasm-SYSMACS.TEXT .INCLUDE Tlasm-GRAFEQU.TEXT .INCLUDE Tlasm-GRAFTYPES.TEXT .INCLUDE Tlasm-TOOLEQU.TEXT .INCLUDE Tlasm-TOOLMACS.TEXT .INCLUDE Tlasm-QUICKMACS.TEXT ; LisaGraf Definitions .INCLUDE Tlasm-FSEQU.TEXT ; File system Definitions .DEF MacInit,SystemError,SystemBeep,PutIcon .DEF MakeStkPB,DoEject .REF InitKbd,InitUtil,PuntDisk .REF IODone,Fetch,Stash .REF InitMem .REF EMT1010 .REF InitCrTable .REF CrsrVBLTask .REF Lvl2RTS,Lvl2Int .REF ExtAInt,ExtBInt ; primary ext/sts int handlers .REF InitQueue,KeyHandler,VBLHandler,NMIHandler .REF AdjEOF,Gt1stMatch,GtNxtMatch,OKToOpen .LIST .INCLUDE source-STARTMAIN.TEXT ; main start code .INCLUDE source-STARTINIT.TEXT ; actual boot code .INCLUDE source-STARTHOOKS.TEXT ; various file system "hook" proc's .INCLUDE source-STARTDIAG.TEXT ; diagnostic test procedures .INCLUDE source-DeepShit.Text ; deep shit manager .END ; FILE STARTDIAG.TEXT ; MACWORKS copy ;_______________________________________________________________________________ ; ; Modification History: ; ; <15Apr85> RDC Add changes for square dots update ; ;_______________________________________________________________________________ ; ROM DIAGNOSTIC ROUTINES ; ; Basic philosophy here is to do as complete a test as possible, given the time ; and code space requirements; where a useful test is time-consuming, that test ; is performed upon user request only (by pressing the mouse button for several ; seconds after power-on). The 68000 is assumed to be functional (as a complete ; test is not possible given the small code-space and complexity of the chip); ; a simple test could easily be added later if deemed desirable. The other LSI ; chips are tested at least for basic functionality. ; ; Particular care was taken to provide good RAM tests as failing RAM bits are ; more common and not very nice (RAMs are also relatively easy to test because ; of their regularity, tho time-consuming to test exhaustively). ; ; The testing of the disk drives is left to normal read/write routines and the ; use of redundant information in data storage. A boot test could be done, but ; that would require use of a known diskette (a writable one if write capability ; were to be tested) or minimally a diskette inserted in the drive. Testing ; of the external drive would also have to be resolved. I propose that the low ; level disk routines do some minimal testing, when the disk is first used. ; ; NOTES: ; - All routines return via RTS6 (A6 points to return address). ; - D0 lowest byte holds pass/fail result and CCR reflects this ; result (0 for pass). ; - For RAM tests, low word of D1 is an OR mask of bit failures ; - All interrupts should be disabled before these routines are called. ; - OVERLAY must be turned off for RAM tests. ; - Most of the RAM tests have the memory size hardwired into the program ; at 64K words, for speed (DBcc only decrements a word) and to save code. ; - A4,A7 are preserved by all routines. ; ; TESTS IMPLEMENTED: ; - ROM Checksum Test ; - RAM Byte Write Test (very basic) ; - Basic RAM Test (basic) ; - RAM Address Uniqueness Test (basic) ; - RAM Moving Inversion Test (moderately extensive) ; ; LOGIC TESTED: ; - All system RAM ; - All ROM ; ;_______________________________________________________________________________ ; ; ROM CHECKSUM TEST ; ; A0 = pointer into ROM D0 = scratch; error indicator ; A1 = pointer into ROM D1 = accumulated checksum ; D2 = counter ; D3 = checksum stored in ROM ; ; Note: this test is currently disabled - it needs buildrom utility ; support to work . . . ;_______________________________________________________________________________ ROMTest MOVEQ #0,D0 MOVEQ #0,D1 LEA Base,A0 ; point to reset PC (rom cksum) MOVE.L (A0)+,D3 ; stored checksum MOVE.W #ROMWSize-3,D2 ; and ROM size in words (adjusted to ; leave out the first long word) ROMLoop MOVE.W (A0)+,D1 ; add code as pos word-sized number ADD.L D1,D0 ; create a long-word-sized result DBRA D2,ROMLoop EOR.L D3,D0 ; should be zero RTS6 ;_______________________________________________________________________________ ; ; Routine: MemTest ; ; Called via BSR6, with A4 = test number ; ; MEMTEST sequences through four memory subtests: Bus (BUS), Write Byte (WRBYTE) ; External Addressing/Data (UNIQ), and Internal Addressing/Data (MOD3TEST). Each ; subtest has a code in the lower word of A4 that can be used to identify the ; failing subtest. Such information may be useful in determining the exact memory ; system failure. Register D1 contains the failing bit mask. ; ; Subtest codes passed in A4 upon failure. ; ; Note that the Internal Addressing test can return bad bits = FFFF, which would ; indicate an external address failure, possibly caused by a bad RAM chip, an ; address line, or the address multiplexors. ;_______________________________________________________________________________ ;_______________________________________________________________________________ ; ; BUS Subtest walks a 1 through a field of zeros 128 times and reads it back to ; test the read buss drivers. Note that if the first RAM location is bad, this ; subtest will fail, however the bad bit should be valid. ; ; A0 - address pointer D1 - Failing bits mask ; D2 - data pattern A4 - Test number ; D3 - iteration counter ; ;_______________________________________________________________________________ MemTest MOVEQ #0,D1 ; no errors ADDQ #1,A4 ; Subtest code 3 MOVE.L A3,A0 ; get RAM start address MOVEQ #1,D2 ; Walking 1 pattern for Buss test MOVEQ #127,D3 ; iteration count @1 MOVE.W D2,(A0) ; Write memory MOVE.W (A0),D1 ; Read back EOR.W D2,D1 ; Verify read BNE Exit ; Error ROL.W #1,D2 ; Rotate the bit DBRA D3,@1 ; again ;_______________________________________________________________________________ ; ; WRByte subtest exercises the write byte logic at the first RAM location. ; ; A0 - address pointer (still initialized from BUS subtest) ; D1 - Failing bits mask ; D2 - data pattern ; D3 - scratch ; A4 - Test number ; ;_______________________________________________________________________________ WRByte ADDQ #1,A4 ; Subtest code = #4 MOVE.W #$55AA,D2 ; Data pattern to D2 MOVEP D2,(A0) ; 55AA to even byte addresses MOVEP D2,1(A0) ; 55AA to odd byte addresses MOVE.L (A0),D1 ; Read long word back EORI.L #$5555AAAA,D1 ; read long word back to verify BNE Exit ; Abnormal exit ;_______________________________________________________________________________ ; ; Mod3Test tests the internal addressing and data retention ability of the memory ; chips using a worst case address flipping scheme and the infamous "modulo 3's" ; addressing pattern. ; ; A0 - address pointer low A4 - Test number ; A1 - address pointer high ; A2 - test parameter list pointer ; D0 - temporary failed bits register ; D1 - iteration count ; D2 - D6 - data patterns ; ;_______________________________________________________________________________ Mod3Test ADDQ #1,A4 ; Subtest = #5 MOVEQ #0,D0 ; Clear temp error bit reg LEA ParmList,A2 ; Fetch parameter list pointer MOVEM.L (A2),D2-D6 ; test data BSR5 Mod3 ; go first pass through MOVEM.L 4(A2),D2-D6 ; next pass data BSR5 Mod3 ; go second pass MOVEM.L 8(A2),D2-D6 ; next pass data BSR5 Mod3 ; go third pass MOVEQ #0,D1 ; clear any count residue MOVE.W D0,D1 ; align any failed bits SWAP D0 OR.W D0,D1 ; exit done CMP.W #$FFFF,D1 BNE.S Exit ;_______________________________________________________________________________ ; ; Unique subtest tests for external addressing faults and some data faults by ; writing an address into each memory location. ; ; A0 - Address pointer A4 - Test #1, Subtest #4 ; A1 - Address pointer ; D2 - iteration counter/data pattern ; D3 - scratch ;_______________________________________________________________________________ Unique ADDQ #1,A4 ; Subtest = #6 MOVE.L A3,A0 ; Start RAM address MOVE.L A0,A1 MOVEQ #-1,D2 ; Counter @1 MOVE D2,(A0)+ ; Count as address data DBRA D2,@1 ReadLP MOVE.W (A1)+,D3 ; Verify data EOR.W D2,D3 ; If any bad ones OR.W D3,D1 ; or in any bad bits DBRA D2,ReadLP ; until done BNE.S Exit ; Any failures? OR.W D0,D1 ;_______________________________________________________________________________ ; ; Exit via RTS6 with failed bits in D1. Set cc for caller. ;_______________________________________________________________________________ Exit TST D1 ; Set condition code . . . RTS6 ;_______________________________________________________________________________ ; ; Mod3 subroutine called by Mod3Test to do the actual write/read/compare ops. ; ; called via BSR5 ; ; Returns failed bits in D0 ; ;_______________________________________________________________________________ Mod3 MOVEM.L 28(A2),D1/A0-A1 ; Get counts, addresses @1 MOVEM.L D2-D4,(A0) ; Low addresses ADDA #12,A0 ; Adjust low address pointer MOVEM.L D4-D6,-(A1) ; High addresses DBRA D1,@1 ; until meet in the middle MOVEM.L 28(A2),D1/A0-A1 ; Get counts, addresses SWAP D1 ; Get read count @2 MOVEM.L (A0)+,D5-D7 ; Read three long words EOR.L D2,D5 ; Verify data EOR.L D3,D6 EOR.L D4,D7 OR.L D5,D6 ; compile data OR.L D6,D7 OR.L D7,D0 ; save in D0 DBRA D1,@2 ; until done MOVEM.L (A0)+,D5-D6 ; pick up last two long words EOR.L D2,D5 ; Verify data EOR.L D3,D6 OR.L D5,D6 OR.L D6,D0 ; save in D0 RTS5 ; exit via A5 ;_______________________________________________________________________________ ; ; ParmList consists of the data patterns loaded by MOVEM.L in MOD3TEST, enabling ; quick, single instruction loads of test parameters. The loop counts are calcu- ; lated on a 128K byte memory size. ; ;_______________________________________________________________________________ ParmList .LONG $DB6DB6DB .LONG $6DB6DB6D .LONG $B6DB6DB6 .LONG $DB6DB6DB .LONG $6DB6DB6D .LONG $B6DB6DB6 .LONG $DB6DB6DB .WORD 32768/3-1 ; Read loop count .WORD 5462-1 ; Write loop count .LONG OvlyRAM ; Overlay RAM start address .LONG OvlyRAM+$1FFFC+4 ; Overlay RAM end address + 1 ;_______________________________________________________________________ ; ; Routine: PutIcon,PutIcon1 ; ; based on Steve Capps' bitmap compression technique ; ; Arguments: A2 = screen address ; A3 = Ram offset pointer ; A4 = address of icon ; A6 = holds return address ; ; Called by BSR6. ; Used to display a compressed icon on the screen ; ; D0 and D1 must be preserved! ; ;_______________________________________________________________________ PutIcon0 ADD.L A3,A2 ; add in the RAM offset PutIcon MOVEQ #15,D3 ; There are 16 octals in an icon UNCOMP1 MOVE.L A2,A0 ; save screen start address MOVEQ #3,D2 ; reset row bytes counter CLR.L D5 ; clear for use <15Apr85> MOVE.W ScreenRow,D5 ; get bytes per row <15Apr85> UILOOP MOVE #$100,D4 ; prime D0 for 8 bit count count MOVE.B (A4)+,D4 ; load map byte from compressed image MLOOP LSR.W #1,D4 ; shift off map bit BEQ.S DONE ; byte done when = 0 BCC.S IBLACK ; dispatch on the bit CLR.B (A2)+ ; store zero in new BRA.S CHECK ; continue for all 8 bits IBLACK MOVE.B (A4)+,(A2)+ ; store byte in new CHECK DBF D2,MLOOP ; see if on scanline seam (every 4 bytes) ADDA.L D5,A2 ; bump to next scanline <15Apr85> SUBA.L #4,A2 ; minus a little bit <15Apr85> MOVEQ #3,D2 ; reset row bytes counter BRA.S MLOOP ; continue for all 8 bits DONE DBF D3,UILOOP ; do the rest of the octals in ICON ; Now unXOR the icon on the screen MOVE.L A0,A1 ; second pointer MOVEQ #30,D3 ; do 31 scanlines XLOOP ADDA.L D5,A1 ; scanline pointer <15Apr85> MOVE.L (A0),D4 ; get long from previous scanline EOR.L D4,(A1) ; xor into this scanline MOVE.L A1,A0 ; "add" rowBytes to a2 DBF D3,XLOOP RTS6 ; plot the dead Mac icon DeadMac LEA SadFace,A0 ;get address of face overlay CommonMac LEA MacIcon,A4 ;get address of Mac icon MOVE.L A0,D7 ;keep overlay address in D7 MOVE.L ScreenLow,A2 ;get approx centered screen address ADDA.W MidPoint,A2 ; <15Apr85> BSR6 PutIcon0 ;plot the icon MOVE.L ScreenLow,A2 ;get centered screen address plus some CLR.L D5 ;clear for use <15Apr85> MOVE.W ScreenRow,D5 ;get bytes per row <15Apr85> MULU #6,D5 ; <15Apr85> ADD.L D5,A2 ;face is 6 scanlines down <15Apr85> ADDA.W MidPoint,A2 ; <15Apr85> ADDQ.L #1,A2 ; and 1 over <15Apr85> MOVE.L D7,A4 ;get address of face BSR6 PutSym0 ;plot the face DonePutSym RTS5 ;return to caller ; plot the happy Mac icon HappyMac LEA HappyFace,A0 ;point to the happy face BRA.S CommonMac ;use common code ; PutSymbol plots a 16 by 12 overlay pointed to by A4 into the screen address ; pointed to by A2. The screen address may not be word-aligned, so be ; careful. PutSym0 ADD.L A3,A2 ; add in the RAM offset PutSymbol MOVEQ #9,D2 ; plot 10 lines PSLoop CLR.L D5 ; clear for use <15Apr85> MOVE.W ScreenRow,D5 ; get bytes per row <15Apr85> SUBQ #2,D5 ; minus a little bit <15Apr85> @1 MOVE.B (A4)+,(A2)+ ; plot 1 byte MOVE.B (A4)+,(A2)+ ; plot 2nd byte ADD.L D5,A2 ; bump to next scan line (ScreenRow-2 bytes) <15Apr85> DBRA D2,@1 ; loop until done <15Apr85> RTS6 ; return to caller ; compressed icon bitmaps MacIcon .BYTE $00,$57,$FF,$FF,$D5,$FF,$FF,$FF .BYTE $FF,$06,$F8,$3F,$E1,$FF,$FF,$0F .BYTE $60,$E3,$FF,$FF,$8F,$E0,$0F,$66 .BYTE $E0,$0F,$E0,$0F,$66,$E0,$0F,$E0 .BYTE $0F,$66,$E0,$0F,$E0,$0F,$66,$E0 .BYTE $0F,$E0,$0F,$66,$E0,$0F,$E0,$0F .BYTE $06,$E0,$0F,$E3,$FF,$FF,$8F,$60 .BYTE $E1,$FF,$FF,$0F,$E0,$0F,$66,$E0 .BYTE $0F,$E0,$0F,$22,$E3,$3F,$0F,$E3 .BYTE $3F,$0F,$66,$E0,$0F,$E0,$0F,$06 .BYTE $E0,$0F,$FF,$FF,$FF,$FF,$60,$F7 .BYTE $FF,$FF,$DF,$F0,$1F,$06,$F0,$1F .BYTE $F7,$FF,$FF,$DF .IF -1 .ELSE ; here is our theft protection code -- tile the screen with the "stolen" message ; first clear the screen MOVE.L ScreenLow,A5 ;get address to start plotting MOVE.L A5,A0 MOVE.W #ScrnLSize,D2 ; number of longs on the screen - 1 @1 CLR.L (A0)+ DBRA D2,@1 ; clear to white ; now initialize for the loop MOVEQ #10,D0 ;eleven rows MOVEQ #4,D7 Th3 MOVEQ #7,D1 ;8 per row Th4 MOVE.L A5,A2 ;get the base address LEA Theft,A4 ;point to the icon BSR6 PutIcon ;plot it ADDQ #8,A5 ;bump to next horizontal position DBRA D1,Th4 ;finish this row MOVE.W ScreenRow,D2 ;get bytes per row <15Apr85> MULU #31,D2 ; <15Apr85> ADD.W D2,A5 ;bump to next row (31 lines down) <15Apr85> ADD D7,A5 ;add offset NEG D7 ;toggle offset DBRA D0,Th3 ;loop Self BRA.S Self ;wait forever .ENDC DiskIcon .BYTE $00,$7F,$FF,$FF,$F5,$FE,$FF,$FE .BYTE $FF,$33,$70,$0F,$F8,$07,$F7,$03 .BYTE $FF,$BB,$F8,$70,$98,$01,$FF,$FF .BYTE $FF,$FE,$FF,$00,$07,$FF,$FF,$E0 .BYTE $0F,$FF,$FF,$F0,$FF,$FF,$FF,$FF .BYTE $FF,$FF,$FF,$0F,$77,$FF,$FF,$EF ; icon overlays HappyFace ; .WORD $0000,$0888,$0888,$0080 ; .WORD $0080,$0180,$0000,$0420 ; .WORD $03C0,$0000 .WORD $0000,$1110,$1110,$0100 .WORD $0100,$0300,$0000,$0840 .WORD $0780,$0000 SadFace ; .WORD $5028,$2010,$5028,$0000 ; .WORD $0480,$0300,$0000,$0FC0 ; .WORD $1030,$0008 .WORD $2828,$1010,$2828,$0000 .WORD $0480,$0300,$0000,$0FC0 .WORD $1030,$0008 QMark .WORD $0000,$0000,$07E0,$0FF0 .WORD $0C30,$0C30,$0070,$00E0 .WORD $01C0,$0180,$0180,$0000 .WORD $0180,$0180,$0000 XMark .WORD $0000,$0000,$1008,$381C .WORD $1C38,$0E70,$07E0,$03C0 .WORD $03C0,$07E0,$0E70,$1C38 .WORD $381C,$1008,$0000 ; FILE Starthooks.text ; MACWORKS copy ; ; MacWorks modification history ; ; 23-Apr-84 KWK Remember to replace entire DSHook procedure to patch ; several problems, including update bug with mem full ; condition (from Ramsys:msfilefix.text) ; 2-Sep-84 KWK Fix for DrawDSBox proc w/moving port around ; 7-Sep-84 KWK Replaced most of DSHook routine to incorporate May 7 ; software release fix for saving screen bits under ; the diskswitch rectangle. ; 9-Oct-84 KWK Now uses shifted destination rect when restoring screen bits ; <18Apr85> RDC Add change to use port offset from global variable ; ;_______________________________________; ; ; ; MakeStkPB utility . . . ; ;_______________________________________; MakeStkPB MOVE.L (SP)+,A0 MOVEQ #-1,D0 @1 CLR.W -(SP) ; get IO param block off stack DBRA D0,@1 ; (with IOFileName zeroed) MOVE.L A0,-(SP) MOVE.L SP,A0 ADDQ #4,A0 RTS ;_______________________________________; ; ; DrawDSBox utility . . . stack has: ; DS1 return address ; rect ptr ; DS2 return address ;_______________________________________; DrawDSBox PEA DSAlertRect MOVE.L (SP),-(SP) MOVE.L (SP),-(SP) MOVE.L (SP),-(SP) MOVE.L (SP),-(SP) _EraseRect _FrameRect MOVE.L #$00020002,-(SP) _PenSize MOVE.L #$00030003,-(SP) _InsetRect _FrameRect ; draw the border MOVE.L #$FFFDFFFD,-(SP) _InsetRect ;now calc the correct amount to move the port over. should be the topleft of ;the dsalertrect + the lisa offset (kwk) MOVE.L DSAlertRect,D0 ; get ready to calc ADD.L MidDiff,D0 ; adjust for new screen params <18Apr85> MOVE.L D0,-(SP) ; and push on stack _MovePortTo ADDQ #8,SP ; strip one ret addr, rect ptr RTS ; and return to caller of DS DrawDSBox ;_______________________________________; ; ; DoEject utility . . . shared by function ; key 1 and 2 procs . . . disk to eject ; is passed in D1 . . . from in D2: ; calls EjectNotify function as: ; ; Function EjectNotify(drive:int;caller:int):boolean; ; ; if false is returned, the disk is not ejected; ; caller=1 for eject key, caller=2 for DS hook ;_______________________________________; DoEject BSR MakeStkPB ; get a parameter block MOVE.W D1,IODrvNum(A0) MOVE.L EjectNotify,D0 ; notify proc? BLE.S @1 ; br if not MOVEM.L D2/A0-A2,-(SP) CLR.W -(SP) MOVE.W D1,-(SP) ; pass eject drive MOVE.W D2,-(SP) ; 1=fkey eject, 2=ds hook eject MOVE.L D0,A0 ; procedure pointer JSR (A0) ; call it (it should preserve Pascal regs) TST.B (SP)+ ; still want to eject? MOVEM.L (SP)+,D2/A0-A2 BEQ.S @2 ; br if not @1 _Eject ; get rid of it . . . BEQ.S @2 MOVE.W #8,-(SP) _SysBeep ; make a beep @2 ADD #IOVQElSize,SP ; clean up stack and return RTS ;------------------------------------------------------------------------ ; GNEFilter filter proc for GetNextEvent ; ; A1 = MyEvent ptr ; D0 = result ; (SP) = return to caller ; 4(SP) = result to caller ;------------------------------------------------------------------------ GNEFilter LEA AlarmState,A1 BSET #5,(A1) ; should we flash? BNE.S @1 ; br if not MOVEQ #3,D0 AND.B (A1),D0 ; both enables must be 0 (bits 0 and 1) BNE.S @1 TST.B WWExist ; also make sure we are in a normal state BNE.S @1 ; exit if none ; make sure the leftmost menu is the Apple menu MOVE.L MenuList,D0 ; got a menuList? BEQ.S @1 ; if not, skip MOVE.L D0,A0 ; get the handle MOVE.L (A0),A0 ; handle -> pointer TST.W (A0) ; how many menus? BLE.S @1 ; skip if none MOVE.L MenuOH+6(A0),A0 ; get the handle of the 1st menu MOVE.L (A0),A0 ; handle -> pointer CMP.W #$0114,MenuData(A0) ; apple menu? BNE.S @1 ; if not, skip ; we know the Apple menu is up there, so flash it MOVE.L #$00010011,-(SP) ; top,left of shield rect MOVE.L #$0013001E,-(SP) ; bottom right of shield rect MOVE.L JShieldCursor,A0 ; different param's then _ShieldCursor JSR (A0) MOVE.L ScrnBase,A0 ; start of screen MOVE.W ScreenRow,D0 ; 90 for Lisa . . . MOVE.L #$00007FFC,D1 ; xor mask MOVEQ #17,D2 ; 18 rows @0 ADD.W D0,A0 ; bump to next line EOR.L D1,(A0) ; invert DBRA D2,@0 ; loop it 18 times _ShowCursor BCHG #7,(A1) ; flip current state for alarm clock BCLR #6,(A1) ; have we beeped yet? BEQ.S @1 ; br if so MOVE.W #8,-(SP) _SysBeep @1 CkFunKey MOVEQ #0,D1 ; type MOVE.B ScrDmpType,D1 ; dump screen flag? BMI.S @1 ; just go on if not MOVE.W #$00FF,ScrDmpEnb ; disable further keys for now SUBQ #4,SP ; load in appropriate function-key package MOVE.L #'FKEY',-(SP) MOVE.W D1,-(SP) ; types 0-9 _GetResource MOVE.L (SP)+,D0 BNE.S @0 ; br if we got the resource TST.W D1 ; zero? BEQ.S @2 ; exit if so CMP.W #2,D1 ; other than 1 or 2? BGT.S @2 MOVEQ #1,D2 ; 1 means from function key JSR DoEject ; 1 and 2 are eject keys BRA.S @2 ; then exit . . . @0 MOVE.L D0,A0 MOVE.L (A0),D0 ; dereference BEQ.S @2 ; exit if purged BSET #Lock,(A0) MOVE.L A0,-(SP) ; save for unlock MOVE.L (A0),A0 ; dereference JSR (A0) MOVE.L (SP)+,A0 ; recover handle BCLR #Lock,(A0) ; let it go . . . @2 ST ScrDmpEnb ; reenable @1 RTS ;_______________________________________________________________________ ; ; Routine(s): DSHook et al ; (c) 1983 Apple Computer Inc. ; ; Arguments: A0.L (input) -- I/O parameter block ptr (call which failed) ; ReqstVol -- VCB ptr for needed volume ; FSQHead -- ptr to queue of VCBs (all mounted volumes) ; File system is ready for another call. ; All registers are preserved ; ; Function: This routine prompts the user to reinsert the volume needed ; to complete the original call. ; ; Put up dialog asking for off-line volume. ; Eject diskette in original mount drive, if any (check for DIP in drive queue). ; Then: If disk-insert event and MemFullErr then deepshit . . . ; otherwise, relaunch . . . ; ; Possibilities: ; - let feature-1 eject drive 1, feature-2 eject drive 2, etc. ; - let feature-Q cause a quit, or abort . . . ;_______________________________________________________________________ FSQHook CLR.L ReqstVol ; zero requested volume MOVE.W IOVRefNum(A0),D2 ; is a drive number specified? BLE.S @4 ; skip if not . . . CMP.B #$0F,D1 ; MountVol? BEQ.S @4 ; skip if so (drive number is cool here) ; convert the drive number to a volume refnum for volumes with maps swapped out NEG.W D2 ; look for this in the VCBDRefNum field MOVE.L VCBQHdr+QHead,D0 @1 BEQ.S @4 ; skip when no more VCBs MOVE.L D0,A1 TST.W VCBDrvNum(A1) ; is it's map swapped out? BNE.S @2 ; br if not CMP.W VCBDRefNum(A1),D2 ; do we have a mapping? BEQ.S @3 ; br if so @2 MOVE.L QLink(A1),D0 ; otherwise, check next VCB BRA.S @1 @3 MOVE.W VCBVRefNum(A1),IOVRefNum(A0) ; make the switch @4 MOVEQ #0,D0 ; zero for good luck RTS CDHook TST.W D0 BEQ.S mtvolfix TST.L ReqstVol ; requested volume not set? BNE.S @1 MOVE.L A2,ReqstVol ; fix RfnCall screwup @1 CMP.W #ExtFSErr,D0 ; for external file system? BNE.S mtvolfix ; br if not MOVE.L ToExtFS,D2 ; is there an external FS? BLE.S CDRTS ; br if not MOVE.L D2,A1 JMP (A1) ; otherwise, let it handle the call ; (CmdDone return address is on stack) mtvolfix MOVE.L FSQHead,A0 ; A0 -> current request MOVE.B IOTrap+1(A0),D2 ; trap number CMP.B #$0F,D2 ; mountvol call? BNE.S sfifix ; br if not TST D0 ; error? BNE.S @0 ; br if so (mountvol error case) TST.W -(A5) ; is buffer dirty? BMI.S @1 ; br if so CLR.W (A5) ; otherwise, invalidate it (it's the last BRA.S @1 ; file directory block) @0 TST.B NewMount ; new mount? BNE.S @1 ; exit if so (everything is ok) ADD #VCBDrvNum,A2 ; point to drive number field MOVE.W (A2),D3 CLR.W (A2)+ ; it should be zeroed MOVE.W D3,(A2)+ ; and put back into driver refnum field ADDQ #4,A2 ; bump to buffer pointers CLR.L (A2)+ ; both should be cleared CLR.L (A2)+ @1 CDRTS RTS ; that was it . . . sfifix TST.B D2 ; open call? BEQ.S openfix ; br if so CMP.B #$0A,D2 ; openrf? BEQ.S openfix ; br if so TST D0 ; error? BNE.S @1 ; error cases are not patched CMP.B #$0D,D2 ; setfileinfo? BNE.S @1 ; MOVEM.L IOFlCrDat(A0),D1-D2 ; get IOFlCrDat, IOFlMdDat MOVEM.L D1-D2,FlCrDat(A5) ; and store in FlCrDat, FlMdDat @1 RTS ; then exit . . . openfix TST D0 ; no error? BEQ.S @2 ; then branch CMP.W #PermErr,D0 ; permissions error? BNE.S @8 ; no patch for other errors TST.B IOPermssn(A0) ; asking for whatever permissions? BNE.S @8 ; exit if not (asked for write perm) MOVE.L A3,D2 SUB.L FCBSPtr,D2 ; recover refnum MOVE.W D2,IORefNum(A0) MOVE.L -14(A5),D2 ; recover file number TST.B RegRsrc ; regular part open? BNE.S @1 ; br if so MOVE.L -24(A5),D2 @1 ADDQ #4,SP PEA OKToOpen ; do it again RTS ; note res/reg flag bit is in bit 1 of D2, A0 -> pblk, A3 = FCB ptr+28, A2 = VCB ptr @2 BSET #7,5(A2) ; note that a file was once open here MOVE.W IORefNum(A0),D4 ; get refnum we are returning MOVE.W D2,D3 ; save resource/reg indication MOVE.L -28(A3),D2 ; D2 is file number JSR Gt1stMatch ; get an FCB match on D2, A2 (always 1) @5 CMP.W D1,D4 ; this one? BEQ.S @6 ; br if so MOVE.B FCBMdRByte(A1,D1),D5 ; check for same fork (and save) MOVE.B D5,D6 EOR.B D3,D6 ; bit 1 must match LSR.B #2,D6 BCC.S @7 ; br if successful @6 JSR GtNxtMatch BEQ.S @5 ; br if match BRA.S @8 ; return if no FCB matches . . . @7 JSR AdjEOF ; otherwise, make sure we are the same MOVE.B D5,FCBMdRByte(A1,D1); don't let AdjEOF change dirty bit @8 RTS ;_______________________________________; ; ; finally, here is the disk-switch hook ;_______________________________________; ; RoomToSave is the number of free bytes between the stack and the heap that we ; need to save the bits. The bitmap we fake on the stack has rowbytes = 36, for ; a rect with height $5A, thus 3240 bytes. RoomToSave .EQU 3254 ; # of bytes to save bits under box + 14 Slop .EQU 1500 ; (kwk) was 1024, needed more DSHook MOVEM.L A0-A3/A6/D0-D7,-(SP) ; save registers CLR.L DskSwtchHook ; clear this to make sure we don't reenter LEA TrapAgain,A1 ; fill in the trap now MOVE.W IOTrap(A0),(A1) ; Now set up the disk-switch alert rect such that it's shifted for the Lisa ; screen (MWDSalertRect) MOVEM.L A0/A1,-(SP) ; save regs LEA DSalertRect,A0 ; get the original DS alert rect LEA MWDSalertRect,A1 ; get addr of my rect MOVE.L (A0)+,(A1)+ ; shift top left value MOVE.L (A0),(A1) ; shift bot right value PEA MWDSalertRect ; get the rect on the stack MOVE.L MidDiff,-(SP) ; push center of screen offset <18Apr85> _OffsetRect ; and shift the rectangle MOVEM.L (SP)+,A0/A1 ; restore regs ; first try mounting the volume in case it was forced off-line due to mem-full: BSR MakeStkPB ; get a parameter block off the stack . . MOVE.L A0,D7 ; remember it in D7 MOVE.L ReqstVol,A2 ; VCB for requested volume MOVE.W VCBDRefNum(A2),D1 ; Original drive BPL.S TellUser ; br if ejected-offline NEG.W D1 ; negative means non-ejected offline MOVE.W D1,IODrvNum(A0) ; so just remount (reload the buffers) _MountVol BEQ DSExit ; exit if everything is rosy . . . TellUser MOVEQ #0,D4 ; use D4 as QDExist flag, too MOVEQ #0,D5 ; D5 flags if we saved the bits TST.B QDExist ; quickdraw around? BNE.S DrawBoxDS ; br if not MOVE.L (A5),A0 ; get quickDraw globals MOVE.L (A0),D4 ; save "thePort" ;see if there's enough room to save the bits... MOVE.L SP,D0 ; get current stack address SUB.L #,D0 ; sub off size we need MOVE.L ApplZone,A0 ; get the base of the zone CMP.L (A0),D0 ; is there enough room? BLE.S DrawBoxDS ; if not, tough luck ;there's enough toom to save off the bits so allocate the space and initialize ;the bitMap MOVE.L SP,D5 ; remember D5 & flag that we saved bits ADD.L #Slop,D0 ; don't reserve the slop MOVE.L D0,SP ; allocate the space on the stack MOVE.L D0,D6 ; remember bitmap address in D6 MOVE.L SP,A0 ; point to the bitmap PEA 14(A0) ; point to the actual bit buffer MOVE.L (SP)+,(A0)+ ; set up the base address MOVE.W #36,(A0)+ ; set up rowbytes CLR.L (A0)+ ; bounds rect topleft is 0,0 MOVE.L #$005A011D,(A0)+ ; bounds botright ;now D6 points to my bitmap. Make A6 point to a fake port to use for the ;_CopyBits call. SUB #,SP ; allocate space for grafport and fake rgns MOVE.L SP,A6 ; point A6 at port BSR DSAllocFakeRgns ; allocate fake regions MOVE.L SP,-(SP) ; push it _InitPort ; and make a port ; Now save off the bits using Copybits. MOVE.L (A5),A0 ; get grafGlobals pointer MOVE.L A6,(A0) ; set my fake port PEA ScreenBits(A0) ; source bitmap is the screen MOVE.L D6,-(SP) ; dest bitmap is our new one PEA MWDSalertRect ; source rect is the shifted deep shit rect MOVE.L D6,A0 ; point to the bitmap PEA 6(A0) ; dest rect the the stack bitmap's bounds CLR.W -(SP) ; mode is srcCopy CLR.L -(SP) ; no mask region _CopyBits ; copy those bits ; the next thing we do is invoke the DeepShit error handler. By setting the alernate draw proc, we ; force the deepshit code to call DrawDSbox, which draws the small disk-switch box and SHIFTS THE ; PORT such that 0,0 is the upper-left corner of the DSalertRect rectangle. DrawBoxDS BCLR #7,DSDrawProc ; use alternate draw proc . . . MOVEQ #DSReInsert,D0 ; ask for diskette back _SysError EjectCurDisk MOVE.L DrvQHdr+QHead,D0 ; figure out if this drive has a disk-in-place @0 BEQ.S WaitForDsk MOVE.L D0,A1 CMP.W DQDrive(A1),D1 ; find queue element for this drive BEQ.S @1 MOVE.L QLink(A1),D0 BRA @0 @1 MOVE.B -3(A1),D0 ; DiskInPlace CMP.B #1,D0 ; BEQ.S @2 CMP.B #2,D0 BNE.S WaitForDsk ; just wait for disk-insert if no DIP @2 MOVEQ #2,D2 ; a disk-switch eject BSR DoEject WaitForDsk SUB #EvtBlkSize,SP ; get event buffer space off the stack @1 MOVE.W #128,D0 ; only disk-inserted events interest us MOVE.L SP,A0 ; event buffer _GetOSEvent BNE.S @1 ; loop until we get one . . . MOVE.L EvtMessage(SP),D0 ; drive number ADD #EvtBlkSize,SP ; free up event buffer space MOVE.L D7,A0 ; point to the I/O block MOVE.W D0,IODrvNum(A0) ; drive to mount _MountVol Relaunch CMP.W #MemFullErr,D0 ; memory full? BNE.S CheckUpdate ; br if not MOVEQ #DSMemFullErr,D0 ; gookie if so _SysError ; OK, we're basically done with the disk switched stuff. Restore the bits ; on the scren if we were able to save them off. CheckUpdate TST.L D5 ; were the bits saved? BEQ.S PostUpdate ; if not, skip ; we have the bits saved off so put them back on the screen. Remember that the ; port is now shifted from the call to DrawDSrect, so we need to use a shifted ; destination rect. MOVE.L D6,-(SP) ; source bitmap is ours MOVE.L (A5),A0 ; point to QD globals MOVE.L A6,(A0) ; make our port the current one PEA ScreenBits(A0) ; dest bitmap is the screen MOVE.L D6,A0 PEA 6(A0) ; source rect is stack bitmap bounds PEA MWDSalertRect ; dest rect is the shifted deepshit rect CLR.W -(SP) ; mode is srcCopy CLR.L -(SP) ; no mask region _CopyBits ; and do it up ; deallocate the stack space and go restore the port MOVE.L D5,SP ; restore old stack pointer BRA.S RestorePort ; use common exit code ; At this point, we weren't able to save the bits so set a flag to post the update ; the next time GetNextEvent is called PostUpdate CLR.B DSWndUpdate ; flag GNE to remove the alert . . . TST.L D4 BEQ.S DSExit RestorePort MOVE.L D4,-(SP) ; restore the port _SetPort DSExit LEA DSHook,A0 ; reinstall disk switch procedure MOVE.L A0,DskSwtchHook ADD #IOVQElSize,SP ; clean up stack MOVEM.L (SP)+,A0-A3/A6/D0-D7 ; restore registers TrapAgain .Word 0 ; original trap goes here RTS ;This little routine is stolen from the deepshit rom code and used by ;the DShook code DSAllocFakeRgns LEA VisRgn(A6),A1 ;get pointer to visRgn handle LEA PortRec(A6),A0 ;point to fake master pointer MOVE.L A0,(A1)+ ;set up vis ADDQ #4,A0 MOVE.L A0,(A1)+ ;set up clip LEA DSFakeRgn,A1 MOVE.L A1,(A0) SUBQ #4,A0 MOVE.L A1,(A0) RTS DSFakeRgn .WORD 10 .WORD -30000,-30000,30000,30000 ; This rect is the disk-switch alert rectangle (DSalertRect) w/coordinates after the ; _MovePortTo in DrawDSbox has shifted the port over to the top left corner. MWDSalertRect .WORD $0000, $0000, $0000, $0000 ; File: StartInit.Text ; MACWORKS copy ;___________________________________________________________________________ ; ; System Initialization Routines ; ; written by Larry Kenyon 8-Feb-83 ; modified by Jeff Parish 83 -- 84 ; ; This file contains the system initialization routines for Macintosh. ; The entry point is MacInit, which calls various subroutines to ; do the dirty work. ; ; This contains the ROM OS code which initializes the system enough to ; boot the RAM-based system off the first two blocks of the internal disk. ; The memory is set up so: ; ; $4113FF +-------------------+ ; | | ; | Dispatch Table | ; | | ; $411000 +-------------------+ ; | | ; | Driver Globals | ; | | ; $410000 +-------------------+ ; | | ; | ROM | ; | | ; $400000 +-------------------+ ; ; ; $FFFF8 +-------------------+ ; | | ; | Lisa screen | screen boot pattern, ; | | disk request icon if needed ; | | ; $F8000 +-------------------+ ; ; ; $80000 +-------------------+ ; | sound, disk buffer| sound buffer cleared, disk ; $7FD00 +-------------------+ speed set appropriately ; | | ; | | ; | unused | ; | | ; | | ; $10400 +-------------------+ ; | boot blocks | boot blocks read in here ; $10000 +-------------------+ ; | | ; $0FE00 +-------------------+ <- Grafport for QD calls ; | | <- A5 (A5-SP = 400, QD Globals) ; $0FC00 +-------------------+ <- SP ; | | ; | stack | ; | | ; | | ; $01000 +-------------------+ ; | | ; | system globals | ; | | ; $00800 +-------------------+ ; | MacWorks globals | ; | LisaBug globals | ; $00600 +-------------------+ ; | | ; | system globals | ; | | ; $00000 +-------------------+ ; ; ;---------------------------------------------------------------------- ; ; Modification History: ; ; 9 Feb 83 LAK new today (from old Sysinit) ; 16 Feb 83 LAK removed event manager initialization. ; 28 Feb 83 AJH general code krunch ; 13 Apr 83 AJH inited dispatch table to unimplemented core routine ; 17 Apr 83 AJH rewrote boot block sequence ; 21 Apr 83 AJH fixed initing "unimplemented core routine" bug ; 22 Apr 83 AJH plotted Happy Mac after finding boot blocks ; 27 Apr 83 LAK made cursor table init routine sharable ; 27 Apr 83 AJH made InitCrsr set up PinRect vector ; 28 Apr 83 AJH removed pinRect vector (moved PinRect into crsrCore!) ; 28 Apr 83 AJH cleaned up remains of disk icon below happy mac icon ; 01 May 83 AJH made it size memory, work for 512K proto ; 02 Jun 83 SC Added init for jerked cursor ; 16 Jun 83 LAK InitIO now initializes UnitNtryCnt lomem variable. ; 23 Jun 83 LAK InitIO doesn't init Async port A driver if AppleBus configured ; in parameter ram. ; 24 Jun 83 LAK Fixed (hopefully) 23 Jun change with BCS instead of BLE. ; 26 Jun 83 AJH Integrated sound driver ; 14 Jul 83 LAK Incorporated code-saving changes found in code walkthru: ; mainly in memory sizing code and RdBootLoop. ; 15 Jul 83 LAK Further modifications to SCC init code to make cursor work. ; 06 Aug 83 BLH Moved initialization of OneOne, minusOne to here. Moved ; restartProc initialization to segLoader. ; 09 Aug 83 LAK Saved code by having InitIO use InstallDrvr, Status, and ; Open calls; no longer allocates local space for a driver. ; 11 Aug 83 LAK Moved some init stuff here from disk driver. ; 12 Aug 83 AJH Added init for MScaleThresh and Factor ; 13 Aug 83 LAK Use ,CLEAR option for UnitTable allocation to save 8 bytes. ; Changed mouse scale init for newest scheme. ; 15 Aug 83 LAK Added IWM lomem location init; added FSIODneTbl init of ; IO vectors to save one lousy word. ; 17 Aug 83 LAK Added init of JCrsrTask. ; 18 Aug 83 LAK Changed init of cursor scaling parms. ; 19 Aug 83 LAK Added init of StkLowPt. ; 20 Aug 83 SC New disk icon and fixed Qmark overlay. ; 22 Aug 83 LAK don't open the async drivers at boot time ; XX XXX 83 JWP extensively modified for MacWorks to run ; on a Lisa ; 20 Jun 84 RDC Add hard disk driver support for Profile/Widget ; 02 Jul 84 RDC Cleaned up hard disk boot stuff ; 05 Jul 84 KWK Clear TermProc low-mem var (didn't I do this before??) ; 16 Jul 84 KWK Moved BootBeep from StartMain to here, fixed length ; 18 Jul 84 RDC Add fixes for hard disk icon flashing and subsequent boot ; from floppy attempt ; 22 Aug 84 KWK Added Rich's new Hard Disk icon ; 20 Sep 84 KWK Added 'forced' boot from Sony (if option key down) ; 27 Sep 84 KWK Clear MonHeader low-mem var (set to NOT a monitor format) ; 11 Oct 84 KWK ST CrsrCoupled at init time. ; 20 Oct 84 KWK Set MouseMask to -1 at init time ; 29 Oct 84 KWK Fixed 'forced' boot from Sony ; 11 Jan 85 JWP Replace the state of Option and Command key after soft boots. ; <15Apr85> RDC Add changes for new screen size for square dots update ; <24Apr85> RDC Add setting of higher default contrast ;___________________________________________________________________________ .DEF JmpTblInit .REF Restop,FSIODneTbl .REF DiskDrvr,SoundDrvr .REF AsyncAIn,AsyncAOut,AsyncBIn,AsyncBOut HdCode .EQU 1 ; TRUE => including hard disk code (rdc) MacInit ; set up some system globals CLR.L DSAlertTab ; no deep shit alerts yet MOVE.L #$00010001, OneOne ; Set up magic constants MOVEQ #-1, D0 ; Get -1 MOVE.L D0, MinusOne ; and set up MinusOne MOVE.L #$400000,ROMBase ; initialize base address for dispatcher MOVE.B LisaRomID,D0 ; get version level of Lisa ROM <15Apr85> CMP.B #3,D0 ; is it a square dots ROM? <15Apr85> BNE.S @1 ; skip if not <15Apr85> MOVE.L #ScrnRes,ScrVRes ; set up ScrVRes, ScrHRes for square dots <15Apr85> MOVE.W #76,ScreenRow ; number of rowbytes for the MacXL screen <15Apr85> MOVE.W #431,ScrnHeigth ; screen heigth in pixels <15Apr85> MOVE.W #608,ScrnWidth ; screen width in pixels <15Apr85> MOVE.W #NewMidOffset,MidPoint ; approx center of screen <15Apr85> MOVE.L #NewMidDiff,MidDiff ; delta between square dots/mac screen <15Apr85> MOVE.L ScreenLow,A0 ; get screen address <15Apr85> MOVEQ #-1, D0 ; set all F's <15Apr85> MOVE.L D0,$7FF4(A0) ; clear extra screen bytes <15Apr85> BRA.S @2 ; <15Apr85> @1 MOVE.L #$003C005A,ScrVRes ; set up ScrVRes, ScrHRes at 60x90 dots/inch MOVE.W #$5A,ScreenRow ; number of rowbytes for the Lisa screen MOVE.W #364,ScrnHeigth ; screen heigth in pixels <15Apr85> MOVE.W #720,ScrnWidth ; screen width in pixels <15Apr85> MOVE.W #OldMidOffset,MidPoint ; approx center of screen <15Apr85> MOVE.L #OldMidDiff,MidDiff ; delta between lisa/mac screen <15Apr85> @2 MOVE.L ScreenLow,ScrnBase ; set up pointer to screen base MOVE.B #$FE,AlarmState ; set global flash enable CLR.L SPAlarm ; clear system alarm time LEA GNEFilter,A0 MOVE.L A0,JGNEFilter CLR.L IAZNotify ; no InitApplZone notify proc ; initialize the size and location of the Disk Switch alert box (80,120,170,405) MOVE.L #$00500078,DSAlertRect MOVE.L #$00AA0195,DSAlertRect+4 LEA DrawDSBox,A0 ; set up the Disk Switch box draw proc MOVE.L A0,DSDrawProc BSET #7,DSDrawProc ; and set disable flag ; point DskSwtchHook to the RAM-based disk switch hook code for the file system LEA DSHook,A0 ; disk switch procedure MOVE.L A0,DskSwtchHook LEA CDHook,A0 ; cmdDone procedure MOVE.L A0,ExtFSHook LEA FSQHook,A0 ; FSQueue procedure MOVE.L A0,FSQueueHook ; some stuff for the disk driver, too CLR.L PollProc ; no proc to handle SCC poll data MOVE.L #PWMBuffer,PWMBuf2 ; no alternate snd/pwm buffer ; size memory to figure out MemTop (note that memory has been set to all 1s ; at this time . . . MOVE.L TopOfMem,A0 MOVE.L A0,MemTop ; set up MemTop SUB #$300,A0 ; compute sound base address MOVE.L A0,SoundBase ; set up sound base address MOVE.L A0,BufPtr ; start loading code below screen CLR.L StkLowPt ; set stack low at this time ; init some I/O and driver base addresses LEA FSIODneTbl,A0 ; point to the offset table LEA JFetch,A1 ; point to 1st jump table entry MOVEQ #2,D1 ; there are 3 vectors BSR JmpTblInit ; initialize some system booleans so we can initialize the system properly ; ST SysMap ; flag that resources are not inited ; ; (memory set to $FFs now) CLR.L DskVerify ; turn off debug/Verify flags CLR.W SysEvtMask ; don't allow any events to be posted ; until events are initialized CLR.L JKybdTask ; no keyboard task yet LEA VBLQueue,A1 JSR InitQueue ; initialize VBL queue header CLR.L Ticks ; clear system tick count CLR.L MBTicks ; set timestamp for mouse button MOVE.B #$80,MBState ; set current mouse button state to "up" MOVE.B #60,Tocks ; set up the 1-sec counter CLR.L TermProc ; set terminate proc ptr to nil (kwk) CLR.W MonHeader ; SF flag to write out monitor style header to blk 0 during write ; now its time to initialize the interrupt driven keyboard handling routines and ; the vertical retrace manager. InitLvl1 LEA Lvl1DT,A1 ; this is where we will save Rick's stuff TrapTo _VBLRoutine ; get address of current VBL handler MOVE.L A0,(A1) ; save in low memory LEA VBLHandler,A0 ; install our VBL handler TrapTo _SetVBLRoutine ; set address of current VBL handler JSR InitKbd ; initialize keyboard globals TrapTo _KeyRoutine ; get address of Rick's keyboard handler MOVE.L A0,4(A1) ; save in low memory for debugger LEA KeyHandler,A0 ; install our keyboard handler MOVE.L A0,8(A1) ; also save in low memory for debugger TrapTo _SetKeyRoutine ; set address of Mac's keyboard handler MOVE.W #$60,D0 ; <24Apr85> TRAPTO _SetContrast ; set to higher contrast <24Apr85> ; special "high contrast version" .IF xContrast MOVE.W #$A0,D0 TRAPTO _SetContrast ; set to (almost) maximum contrast MOVE.W #$FF,D0 TRAPTO _SetDimContrast ; set to minimum dim value MOVE.L #$3A980,D0 TRAPTO _SetFadeDelay ; 240K milliseconds or 4 minutes .ENDC ; INITCRSR -- Cursor/Mouse initialization routine. ; turn on mouse and VBL interrupts and initialize the cursor globals (all 0's) InitCrsr MOVE.L ScrnBase,D0 ; save the ptr to the screen LEA GrafBegin,A0 ; start of global vars LEA GrafEnd,A1 ; end of global vars ClrGlob CLR (A0)+ CMP.L A1,A0 BLT.S ClrGlob ; clear out cursor globals area MOVE.L D0,ScrnBase ; replace the ptr to the screen ST CrsrCoupled ; the cursor starts out coupled (kwk) MOVE.L MinusOne,MouseMask ; set mouse mask to $FFFFFFFF LEA CrsrPin,A0 CLR.L (A0)+ ; topleft = 0,0 MOVE.W ScrnHeigth,(A0)+ ; set bottom edge <15Apr85> MOVE.W ScrnWidth,(A0)+ ; set right edge <15Apr85> ; initialize the cursor jump table with a loop. The offsets are ; obtained from a table in CrsrCore. LEA InitCrTable,A0 ; point to the offset table LEA JHideCursor,A1 ; point to 1st jump table entry MOVEQ #7,D1 ; there are 8 vectors BSR JmpTblInit ; now its time to initialize the interrupt dispatch tables LEA AutoInt6,A2 ; point to main vectors LEA Lvl2Int,A0 MOVE.L A0,(A2) ; level "2" dispatcher LEA Lvl2RTS,A1 ; default action (RTS) LEA ExtStsDT,A2 ; now fill in the 2nd level table for MOVE.L A1,(A2)+ ; SCC external/status interrupts ; LEA MV1Int,A0 ; mice get 2 vectors ; MOVE.L A0,(A2)+ MOVE.L A1,(A2)+ MOVE.L A1,(A2)+ ; LEA MH1Int,A0 ; MOVE.L A0,(A2) MOVE.L A1,(A2)+ LEA ,A2 ; fill in vectors to secondary LEA ExtBInt,A0 MOVE.L A0,(A2) LEA ExtAInt,A0 MOVE.L A0,$10(A2) ; read time and parameter ram from clock JSR InitUtil ; initialize the dispatch table from the encoded table found starting at ; "ResTop" (right after the OS) InitROMCore LEA DispatchTab,A1 ; point to Mac Trap dispatch table ; first point all traps to "unimplemented trap receiver" LEA BadTrap,A0 ; get address of "BadTrap" SUB.L RomBase,A0 ; compute offset from RomStart MOVE.L A0,D0 ; get into d-Reg LSR #1,D0 ; divide by 2, turn off high bit MOVE.L A1,A0 ; get dispatch table address MOVE #511,D1 ; there are 512 entries in trap table @1 MOVE.W D0,(A0)+ ; init one entry DBRA D1,@1 ; loop till we do them all ; OK, here is the loop where we init the table LEA Restop,A0 ; begin at the beginning... MOVEQ #0,D2 ; D2 holds "last address" TInitLoop MOVE.B (A0)+,D0 ; get the next byte BMI.S ShortOne ; if negative, its short ; handle the case of a long one ASL #8,D0 ; that was the high byte MOVE.B (A0)+,D0 ; get the low byte InitCCommon MOVE.W D0,D2 ; remember the last one in D2 BEQ.S InitCDone ; if zero, we're done MOVE.W D0,(A1) ; update the table Transparent ADDQ #2,A1 ; skip the word BRA.S TInitLoop ; loop till done ; handle the case of a short one ShortOne AND.W #$007F,D0 ; use low 7 bits BEQ.S Transparent ; if zero, ignore it entirely ADD.W D2,D0 ; add to the previous one BRA.S InitCCommon ; let common code do the rest ; OK, we've initialized the entire dispatch table. Now install the dispatcher ; by setting up the Line1010 vector InitCDone LEA EMT1010,A0 ; get address of dispatcher MOVE.L A0,LINE1010 ; initialize the memory manager and set the system heap to its default size. JSR InitMem ; init memory manager (sys zone current) ; initialize the IO system BSR InitSCC ; init SCC for cursor BSR InitIO ; init unit I/O and drivers ; RDC .IF HdCode = 1 BSR InitHdsk ; init hard disk driver .ENDC ; (RDC) MOVE #$2000,SR ; turn on interrupts ; draw the nice, gray boot screen using QuickDraw. First we must set up ; an A5 world for QuickDraw BootScreen LEA 400(SP),A5 ; leaving room for globals PEA -4(A5) ; set up LisaGraf global area _InitGraf ; Initialize LisaGraf PEA $0000FE00 ; let Grafport be above A7, A5 _OpenPort ; Open the default port MOVE.L (A5),A2 ; point to QuickDraw globals PEA Arrow(A2) ; push address of default cursor _SetCursor ; make it the current one PEA ScreenBits+Bounds(A2) ;point to screen rectangle MOVE.L (SP),-(SP) ;push a second copy _PaintRect ; Draw black screen first MOVE.L #$00100010, -(SP) ; Push the rounding factor PEA Gray(A2) ; push gray _FillRoundRect ; Fill a round rectangle gray ; plot the "happy Mac" icon to show that everythings cool _HideCursor SUB.L A3,A3 ; make sure RAM offset pointer is set up BSR5 HappyMac ; plot the happy Mac icon ; NOTE THAT A5 IS NOW BLOWN!! _ShowCursor ; now perform some initialization for the boot blocks loop ;RDC .IF HdCode = 1 ; first check if boot from hard disk CMP.W #HDRfNum,BootDrive ; hard disk online? BNE.S BootBeep ; skip if not ;(JWP) MOVE.B KeyMap+7,D0 ; load the current option key OR.B OptionSave+1,D0 ; include the state of the option key before reboot BTST #2,D0 ; was the option key down in either case? BEQ.S @0 ; no, continue hard disk setup ;(JWP) MOVE.W #DskRfN,BootDrive ; booting with sony driver BRA.S BootBeep ; continue Sony setup, fall through to RdBootLoop code @0 MOVEQ #HDDrive,D6 ; else set drive for hard disk MOVEQ #0,D4 ; setup initial flash state BRA.S RdBootLoop ; and go start boot .ENDC ;(RDC) ;kwk -- add bootbeep code here, so only makes fart sound for sony boot ; Give a beep to tell the world that the CPU works. (D0/D1 trashed) BootBeep MOVE.W #$1,D0 ; set the speaker volume to low TRAPTO _SetVolume MOVE.L #$800,D0 ; wavelength (in microsecs) MOVE.L #$100,D1 ; duration (in milliseconds) TRAPTO _Beep ; beep it ; (kwk) RdBootBlks LEA QMark,A0 ; get address of question mark sysmbol MOVE.L A0,D7 ; and keep it in D7 MOVEQ #1,D6 ; initial drive number BTST #4,SPMisc2 ; try external drive first? BEQ.S @1 ; br if set for internal ADDQ #1,D6 ; bump to external @1 MOVEQ #3,D3 ; drive switch mask MOVEQ #0,D4 ; D4 holds the flash state TST.B MBState ; if mouse button is down, eject it first BPL.S GetGDsk1 ; now try to read in the boot blocks RdBootLoop MOVE.L SP,A0 ; use space above stack, below QD globals ;RDC .IF HdCode = 1 MOVE.W BootDrive,IORefNum(A0) ; driver refnum .ELSE MOVE.W #DskRfN,IORefNum(A0) ; Sony driver refnum .ENDC ;(RDC) MOVE.W #1,IOPosMode(A0) ; position relative to start CLR.L IOPosOffset(A0) ; start at byte position 0 MOVE.L #$00010000,A1 ; save for later use . . . MOVE.L A1,IOBuffer(A0) ; load boot blocks at $00010000 MOVE.L #$400,IOReqCount(A0) ; two 512-byte blocks MOVE.W D6,IODrvNum(A0) ; set up the drive number MOVE.W D6,BootDrive ; remember the boot drive in low memory _Read ; do it synchronously BEQ GoLaunchIt ; if no error, try to launch it ; there was some kind of error when trying to read the boot blocks. See if ; the disk was offline CMP.W #OffLinErr,D0 ; no disk in place? BEQ.S GoFlashIt ; br if so CMP.W #NoDriveErr,D0 ; no disk at all? BNE.S GetGDsk1 ; br if not ; this disk isn't there at all, so toggle to the other one and stop toggling EOR D3,D6 ; toggle drive number MOVEQ #0,D3 ; no more toggling BRA.S GoFlashIt ; try the next one ; the disk was online, but there was some kind of error. Eject it and mark ; that it was a bad disk by pointing D7 to the X symbol. GetGDsk1 ;RDC .IF HdCode = 1 CMP.W #HDDrive,D6 ; don't eject if using hard disk BEQ.S @1 .ENDC ;(RDC) MOVE.L SP,A0 MOVE.W #DskRfN,IORefNum(A0); driver refnum MOVE.W #EjectCode,CSCode(A0) MOVE.W D6,IODrvNum(A0) _Control ; eject the bad diskette @1 LEA XMark,A0 ; get address of the X symbol MOVE.L A0,D7 ; point D7 to it MOVEQ #8,D5 ; D5 holds the timeout for the X ; at this point we should give the user some feedback as to whats going on ; by flashing the disk icon. GoFlashIt MOVEM.L D3-D7,-(SP) ; preserve our state registers LSR #1,D4 ; check the flash parity BCC.S @1 ; if off, skip MOVEQ #0,D7 ; plot the plain one @1 BSR.S PlotDisk ; plot the disk icon ; now restore the registers and delay for a short while DonePDisk MOVEM.L (SP)+,D3-D7 ; restore the registers MOVEQ #3,D0 ; get delay count SWAP D0 @1 SUBQ.L #1,D0 ; delay BNE.S @1 ; for a while ; advance to the next state ADDQ #1,D4 ; bump the flash parity SUBQ #1,D5 ; decrement timeout count BNE.S FlipDisk ; if non-zero, we're cool ; the timeout has expired so switch to the question mark again LEA QMark,A0 ; point to the question mark MOVE.L A0,D7 ; update D7 ; look at the other drive FlipDisk ;RDC .IF HdCode = 1 MOVE.W #DskRfN,BootDrive ; set refnum for floppy CMP.W #HDDrive,D6 ; using hard disk? BNE.S @1 ; skip if not SUBQ #1,D5 ; else decr timeout count BNE.S GoFlashIt ; and continue flashing BRA RdBootBlks ; else go try first floppy @1 .ENDC ;(RDC) EOR D3,D6 ; flip disk number BRA RdBootLoop ; if at first you don't succeed... GoLaunchIt CMP.W #$4C4B,(A1)+ ; is it true boot code? BNE.S GetGDsk1 ; go eject if its not MOVE.L A1,-(SP) ; save entry address _HideCursor BSR5 HappyMac ; plot the happy Mac ; !!!!!!!!!!!!!!!! This is a horrendous kludge used to get around another ; !!!!!!!!!!!!!!!! horrendous kludge in the 1.0 system boot blocks. MOVE.L (SP),A1 ; retrieve the launch address MOVE.W 4(A1),D0 ; look at the version word CMPI.W #$12,D0 ; anything > 12 we will leave alone BGT.S GoToIt MOVE.W #$8,D1 ; set up the world for our new entry MOVE.W #$BE,2(A1) ; change a BRA X to a BRA Y GoToIt RTS ; launch it! ; plot the disk icon with appropriate overlay (blank,qMark or cross) ; overlay pointed to by D7 PlotDisk _HideCursor MOVE.L Ticks,D0 SyncLoop CMP.L Ticks,D0 ;sync with the video BEQ.S SyncLoop ;by wait for TICKS to change LEA DiskIcon,A4 ;get address of Mac icon ;RDC .IF HdCode = 1 CMP.W #HDDrive,D6 ;using hard disk? BNE.S @2 ;skip if not LEA HdskIcon,A4 ;else reset icon ptr .ENDC ;(RDC) @2 MOVE.L ScreenLow,A2 ;get vaguely centered screen address ADDA.W MidPoint,A2 ; <15Apr85> BSR6 PutIcon0 ;plot the icon TST D7 ;is there an overlay? BEQ.S @1 ;if not, skip MOVE.L ScreenLow,A2 ;get vaguely centered screen address CLR.L D0 ;clear for use <15Apr85> MOVE.W ScreenRow,D0 ;get bytes per row <15Apr85> MULU #16,D0 ; <15Apr85> ADD.L D0,A2 ;compute place to plot it <15Apr85> ADDA.W MidPoint,A2 ; <15Apr85> ADDQ.L #1,A2 ; <15Apr85> MOVE.L D7,A4 ;point A4 at the symbol ADD.L A3,A2 ;add in RAM base address MOVEQ #14,D2 ;15 lines to plot BSR6 PSLoop ;plot it @1 _ShowCursor RTS ; receiver for unimplemented core routines BadTrap MOVEQ #12,D0 ; get DS alert ID for bad traps BRA SystemError ; invoke the DS manager ; initialize the SCC to receive mouse interrupts InitSCC MOVE.L #SCCWBase,A0 ; point to SCC base write address (chan B) MOVE.L #SCCRBase,A1 ; point to SCC base read address (chan B) MOVE.L A0,SCCWr ; set up SCC read and write base addresses MOVE.L A1,SCCRd ; in low memory for cheaper accesses RTS ; a short routine used to set up ram-based jump tables from rom-routine ; offset tables . . . JmpTblInit MOVE.L A0,D0 ; remember its address @1 MOVEQ #0,D2 ; clear high part for arithmetic MOVE.W (A0)+,D2 ; get the next offset ADD.L D0,D2 ; compute the address MOVE.L D2,(A1)+ ; install it in the jump table DBRA D1,@1 ; loop for all 8 vectors RTS ; InitIO initializes the I/O system by building the Unit Table and ; issuing initialization calls to all the component drivers. ; DriverTable is the address offset table used to inititialize ROM based drivers ; contains an offset to the driver and a word specifying the unit number NumRomDrivers .EQU 6 ; currently, there are 6 ROM-based drivers FirstUnit .EQU 3 ; unit number of first one is 3 UnitEntries .EQU 32 ; default # of entries in unit table DriverTable JMP SoundDrvr ; sound driver JMP DiskDrvr ; Sony disk driver JMP AsyncAIn ; serial port A input JMP AsyncAOut ; serial port A output JMP AsyncBIn ; serial port B input JMP AsyncBOut ; serial port B output InitIO ; first compute the size of the unit table and allocate it MOVEQ #UnitEntries,D0 ; get number of entries in unit table MOVE.W D0,UnitNtryCnt ; save for IOCore checking ASL.L #2,D0 ; 4 bytes needed per entry _NewPtr ,SYS,CLEAR ; allocate it and zero out the memory MOVE.L A0,UTableBase ; and save its address ; now step through the ROM-based driver initialization table, initializing all ROM ; based drivers LEA DriverTable,A2 ; get address of table MOVEQ #NumRomDrivers-1,D1 ; get number of entries in table MOVEQ #FirstUnit,D7 ; get first unit number InitIOLoop ADDQ #2,A2 ; skip over JMP opcode MOVE.L A2,A1 ; get current "PC" MOVEQ #0,D0 ; clear high part for address math MOVE.W (A2)+,D0 ; get the offset ADD.L D0,A1 ; compute driver address ; allocate a device control entry for the driver AllocDCE MOVE.W D7,D0 ; get unit number NOT.W D0 ; derive the refNum SUB #IOQElSize,SP MOVE.W D0,IORefNum(SP) ; for later _DrvrInstall ; get a DCE (pass refnum in D0) ; now retrieve DCE pointer MOVE.W #1,CSCode(SP) ; 'get DCE' status call MOVE.L SP,A0 _Status MOVE.L CSParam(A0),A3 ; DCE handle MOVE.L (A3),A3 ; DCE pointer ; initialize the Device Control Entry (DCE) (some of it, anyway) MOVE.L A1,(A3)+ ; put in pointer to DCtlDriver CLR.W (A3) ; clear ram-based flag in driver MOVE.B DrvrFlags(A1),(A3) ; flags from driver -> DCE DCtlFlags ; open only the disk and sound ROM-based drivers at this time CMP #5,D7 ;is it a serial one? BCC.S @1 ;if so, don't open LEA DrvrName(A1),A1 MOVE.L A1,IOFileName(SP) CLR.B IOPermssn(SP) ; r/w permissions MOVE.L SP,A0 _Open ; open it! @1 ADD #IOQElSize,SP NextUnitIO ADDQ #1,D7 ; bump unit number DBRA D1,InitIOLoop ; loop till all are done RTS ;RDC .IF HdCode = 1 ;-------------------------------------------------------------------- ; Special initialize routine for hard disk driver. ; Sets up BootDrive location with boot device (default is hard disk ; if it is connected and OK). ;-------------------------------------------------------------------- InitHdsk MOVE.L HDiskStart,A1 ; get ptr to hard disk driver MOVEQ #0,D1 ; one driver to init MOVEQ #HdskID,D7 ; setup driver id BSR.S AllocDCE ; and go init it MOVEQ #-1,D0 ; clear space for parameter block @0 CLR.W -(SP) DBRA D0,@0 MOVE.L SP,A0 ; save ptr MOVE.W #HdRfNum,D0 ; setup refnum MOVE.W D0,IORefNum(A0) MOVE.W D0,BootDrive ; save as potential boot device refnum MOVE.W #HDDrive,IODrvNum(A0) ; set drive # MOVE.W #InitCode,CSCode(A0) ; and code for init of controller _Control ; go do device init TST D0 ; any errors? BEQ.S @1 ; no, exit normally CMP.W #LisaDskErr,D0 ; Lisa disk attached? BEQ.S @1 ; treat as no error for now (may be shared) CMP.W #MWDskErr,D0 ; MacWorks direct-start disk attached? BEQ.S @1 ; yes, no error MOVE.W #DskRfn,BootDrive ; else default to Sony @1 ADD #IOQElSize,SP ; restore stack RTS ; and exit ; compressed icon for Profile hard disk HdskIcon .BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF .BYTE $FF,$FF,$0F,$7F,$FF,$FF,$FE,$F0 .BYTE $FF,$FF,$FF,$FF,$4F,$1B,$F8,$30 .BYTE $4F,$1B,$F8,$30,$0F,$FF,$FF,$FF .BYTE $FF,$20,$67,$FF,$9F,$E6,$18,$60 .BYTE $18 .ALIGN 2 .ENDC ;(RDC) ;-------------------------------------------------------------------- ; ; Procedure ScreenSize (var x: Pixels; var y: Pixels); ; ScreenSize TRAPTO _ScreenSize ; ScreenSize MOVEM.L (SP)+,A0/A1 ; return address, var y MOVE.W D1,(A1) ; vertical dimension MOVE.L (SP)+,A1 ; var x MOVE.W D0,(A1) ; horizontal dimension JMP (A0) ; return ;-------------------------------------------------------------------- ; File: StartMain.Text ; MACWORKS copy ;___________________________________________________________________ ; ; StartMain must be placed at the very beginning of ; the ROM. It contains the hardware start vectors ; and low level initialization code. ; ; written by Larry Kenyon, Feb 1983 ; ; Modification History: ; ; 27-Mar-83 AJH New bootBeep, code krunch, etc. ; 13-Apr-83 AJH Made beep shorter, got rid of Talk jump ; 17-Apr-83 AJH Made emergency eject do drive 2 ; 17-Apr-83 AJH made it set screen to black before beep ; 20-Apr-83 AJH removed disk vectors from jump table; made CritErr ; increment the screen to show signs of life. ; 29-Apr-83 AJH made CritErr force the disk off ; 01-May-83 AJH made things work on 512K proto ; 23-Jun-83 AJH removed emergency disk eject, and IWM init ; 13 Jul 83 LAK added changes suggested at code walkthru: added back ; longmemtest, removed rammovin test completely, ; numerous code changes as suggested. ; 13 Jul 83 SC Removed D0Info, D1Info1 and made inline in CritErr w/4x6 font ; 06 Aug 83 LAK Added IWM initialization back in. ; 06 Aug 83 SC Hacked out BootBeep for general call(SystemBeep in DeepShit) ; 16 Aug 83 SC Added duration to BootBeep ; 20 Aug 83 AJH Enters DeepShit through alternate entry point ; Changed $40000A restart to really reboot ; 23 Aug 83 LAK Reenabled ROM checksum test. ; XX XXX 83 JWP Heavily modified for MacWorks. ; 22 Apr 84 KWK Bumped rev number for next release of MacWorks: 4/1/84 ; release = $69, next release (June 84?) = $70 ; 25 Apr 84 KWK Bumped rev number again, as 4/1 or 4/6 release version ; number = $70 (what the hell was version 69?) ; 17 Jul 84 KWK Moved BootBeep code to StartInit (bypassed for hrddsk boot) ; 9 Nov 84 KWK Bumped rev number to $80, Rev C version 0.91 ; Note: Must stay $80 for Hard Disk Install to work! ; 11 Dec 84 KWK Removed Paint It Black from main init path ; 11 Jan 85 JWP Initialize OptionSave to 0 only when we hard boot ; <15Apr85> RDC Add changes for square dots update, new rev # ;___________________________________________________________________ .PROC LTest,0 .ORG 0 ; org'ed at 0 but runs at $400000 Base BRA.S PreBoot ; actual first byte of rom .WORD $0000 ; filler .WORD $0040 ; .WORD AfterBoot ; starting PC for a Reboot Version .WORD $81FF ; Lisa version in hi-byte ; (word @ location $400008) ; ROM routine jump table BRA AfterBoot ; $40 000A - reboot BRA GetGDsk1 ; $40 000E - eject disk, and reboot ; ;------------------------------------------------------------------------------- ; PreBoot TST.B MacJmp ; is LisaBug around? BEQ.S CopyROM ; no - don't enable an NMI key MOVE.W #47,D0 ; enable switching between screens TRAPTO _SetToggleKey MOVE.W #$21,D0 ; enable the NMI key TRAPTO _SetNMIKey ; ; Copy the "ROM" code from where it was loaded to $400000 (logical). ; CopyROM LEA Base,A0 MOVE.L #$400000,A1 LEA StartBoot-Base(A1),A2 MOVE.W #$4000,D0 ; copy 64k byte ROM to final pos. @1 MOVE.L (A0)+,(A1)+ SUB.W #1,D0 BNE.S @1 SUB.L #16,A0 ; back off slightly MOVE.L A0,TopOfMem ; save top of memory CLR.W OptionSave ; start off in a clean state (JWP) ; eject the preboot diskette MOVE #$2000,SR ; turn on interrupts MOVE.L SonyStart,A0 ; get start of disk #1 routines MOVE.W #5,D6 ; eject command MOVE.W #1,D4 ; eject drive #1 JSR (A0) ; go ahead and eject it! @2 TST.B SonyDone ; wait for cmd complete BNE.S @2 MOVE #$2700,SR ; turn off interrupts JMP (A2) ; jump into the "ROM" code AfterBoot MOVE #$2700,SR ; turn off interrupts LEA Lvl1DT,A1 ; point to dispatch table MOVE.L (A1)+,A0 ; get Rick's vbl handler TrapTo _SetVBLRoutine ; set address of current VBL handler MOVE.L (A1)+,A0 ; get Rick's keyboard handler TrapTo _SetKeyRoutine ; set address of Mac's keyboard handler ; fall through to StartBoot ; ;------------------------------------------------------------------------------- StartBoot MOVE.L #SCCRBase,A1 ; point to SCC base read address (chan B) MOVE.B (A1),D2 ; read to make sure SCC is sync'ed up MOVE.L #SCCWBase,A0 ; point to SCC base write address (chan B) MOVE.L #SCCWBase,A0 ; delay MOVE.B #$09,(A0) ; write register 9 MOVE.L #SCCWBase,A0 ; delay MOVE.L #SCCWBase,A0 ; delay MOVE.B #$C0,(A0) ; Force Hardware Reset SUB.L A3,A3 ; get RAM start address (= 0) MOVE.L ScreenLow,A2 ; point to the screen ; BSR6 BlackScreen ; Paint It Black (c) 1966 Jagger/Richards (removed kwk -- 12/11/84) BRA SysInit ; continue to boot ; We found a nasty error so draw the dead Mac icon and some numbers CritErr MOVE.L ScreenLow,A2 ; start at the top of the screen BSR6 BlackScreen ; clear display screen before we write on it MOVE A4,D0 ; get failing test number in D0 BSR5 DeadMac ; plot the dead Mac (preserve D0,D1) CLR.L D2 ; clear for use <15Apr85> MOVE.W ScreenRow,D2 ; get bytes per row <15Apr85> ; This plots 6 nibbles on screen contained in D0/D1. The first two digits are the ; test number that failed and the last four digits are the code (eg. bad bit #'s, ; etc.) SWAP D0 ; put test number in high word MOVE D1,D0 ; put code in low word LSL.L #8,D0 ; position in high bits ; A2 points to screen at "vaguely centered" plus 34 scanlines -1 for extra digit MOVE.L ScreenLow,A2 ; get address of top of screen MOVE.L D2,D4 ; get bytes per row <15Apr85> MULU #34,D4 ; compute plot point <15Apr85> ADD.L D4,A2 ; <15Apr85> ADDA.W MidPoint,A2 ; final offset to icon <15Apr85> SUBQ.L #1,A2 ; <15Apr85> MOVEQ #5,D4 ; size digits to plot MOVE.L D2,D6 ; get bytes per row <15Apr85> MULU #6,D6 ; compute offset between chars <15Apr85> SUBQ #1,D6 ; <15Apr85> nextDigit ROL.L #4,D0 ; get nibble in low order MOVE D0,D5 ; get into working register AND #$F,D5 ; isolate the nibble MULU #3,D5 ; 3 bytes per digit LEA numFont(D5),A1 ; point to start of digit's map MOVEQ #-61,D1 ; now mask off extras with $C3 MOVEQ #2,D3 chLoop MOVE.B (A1),D5 ; get the next byte LSR #2,D5 ; get high nibble OR D1,D5 MOVE.B D5,(A2) ADD D2,A2 ; next scan line <15Apr85> MOVE.B (A1)+,D5 ; get the next byte LSL #2,D5 ; get low nibble OR D1,D5 MOVE.B D5,(A2) ADD D2,A2 ; next scan line <15Apr85> DBRA D3,chLoop SUB D6,A2 ; point to next char <15Apr85> DBRA D4,nextDigit ; and go plot it MULU #8,D2 ; position E 8 lines down <15Apr85> ADD D2,A2 ; <15Apr85> deadLoop ADDQ.L #1,D0 SWAP D0 MOVE.B D0,(A2) ; plot 3rd byte MOVE.B (A2),1(A2) ; symmetry is nice SWAP D0 BRA deadLoop ; The digits 0-F are 4x6 bitmaps stored as 3bytes/digit numFont .BYTE $96,$42,$69 ; 0 .BYTE $B3,$BB,$B1 ; 1 .BYTE $96,$ED,$B0 ; 2 .BYTE $0E,$9E,$69 ; 3 .BYTE $66,$60,$EE ; 4 .BYTE $07,$1E,$69 ; 5 .BYTE $87,$16,$69 ; 6 .BYTE $0E,$DD,$BB ; 7 .BYTE $96,$96,$69 ; 8 .BYTE $96,$68,$E1 ; 9 .BYTE $96,$60,$66 ; A .BYTE $16,$16,$61 ; B .BYTE $87,$77,$78 ; C .BYTE $16,$66,$61 ; D .BYTE $07,$17,$70 ; E .BYTE $07,$17,$77 ; F ; next come some exception routines. "ToDeepShit" pulls off the return ; address to figure out which one it was GenExcps BSR.S ToDeepShit ; bus error BSR.S ToDeepShit ; address error BSR.S ToDeepShit ; illegal instruction BSR.S ToDeepShit ; zero divide BSR.S ToDeepShit ; check instruction BSR.S ToDeepShit ; trapv instruction BSR.S ToDeepShit ; privilege violation BSR.S ToDeepShit ; trace BSR.S ToDeepShit ; line 1010 BSR.S ToDeepShit ; line 1111 BSR.S ToDeepShit ; other exceptions IRQException ADDQ #2,SP ; pop off the status register BSR.S ToDeepShit ; interrupt exceptions ; ; BlackScreen fills the screen with black, naturally ; BlackScreen MOVEQ #-1,D3 ; black MOVE.W #scrnLSize-1,D2 ; number of longs on the screen - 1 @1 MOVE.L D3,(A2)+ DBRA D2,@1 ; blacken it to preserve phosphor RTS6 ; ToDeepShit receives all the hardware exceptions. It derives the ; deepShit ID from the return address on the stack and then invokes the ; deepShit manager ToDeepShit ; MOVEM.L A0-A7/D0-D7,$7FC80 ; save all regs for debug LEA GenExcps,A0 ; get address of receiver table MOVE.L (SP)+,D0 ; get return address SUB.L A0,D0 ; compute delta LSR #1,D0 ; divide by 2 BRA SysErr2 ; go to deepShit manager (alternate entry) ; we passed the testing of critical system components, so on to initialization ; first set up the exception vectors, then clear memory to all ones... SysInit TST.B MacJmp ; is LisaBug around? BNE.S ClearMem ; yes - don't muck with exception stuff ; LisaBug must not exist so set up RAM exception vectors ourselves MOVE.L #8,A0 ; vectors start at 8 LEA GenExcps,A1 ; first set up 7 general exceptions MOVEQ #6,D0 @2 MOVE.L A1,(A0)+ ADDQ.L #2,A1 DBRA D0,@2 ADDQ.L #2,A1 ; skip past the Trace exception ADDQ.L #4,A0 MOVE.L A1,(A0)+ ; Line 1010 ADDQ.L #2,A1 MOVE.L A1,(A0)+ ; Line 1111 ADDQ.L #2,A1 MOVEQ #12,D0 Othr1Loop MOVE.L A1,(A0)+ ; set up some 'others' DBRA D0,Othr1Loop ; LEA IRQException,A2 ; then set up the 7 autovectors ; MOVEQ #6,D0 ;IOELoop ; MOVE.L A2,(A0)+ ; DBRA D0,IOELoop ; ; ADD.L #$1C,A0 ; skip the interrupt vectors ; MOVEQ #31,D0 ;Othr2Loop ; MOVE.L A1,(A0)+ ; set up the rest of the 'others' ; DBRA D0,Othr2Loop ; ; now clear memory (most of) ; ClearMem MOVE.W #$100,A0 ; start near bottom of memory MOVEQ #-1,D1 MOVE.W #$C0,D0 ; clear up to debugger at $400 @3 MOVE.L D1,(A0)+ SUB.W #1,D0 ; decrement counter BNE.S @3 ; loop till done MOVE.L TopOfMem,D2 ; calculate how much left to clear MOVE.L #$800,A0 ; start clearing after debugger globals SUB.L A0,D2 LSR.L #2,D2 ; compute number of longs of memory @4 MOVE.L D1,(A0)+ ; set memory to negative ones ($FF) SUB.L #1,D2 ; decrement counter BNE.S @4 ; loop till done OffOverlay MOVE.L #$0000FC00,SP ; put the stack below $10000 ; fall thru to boot code (in StartInit) ; FILE Stub.text ; MacWorks source ; ; For the non-debugging version of MacWorks, the Bootconfig.data file ; on the MacWorks sony specifies that Stub.obj is loaded instead of ; Lisabug/LisaBug2 ; ; .INCLUDE tlasm-DBUGEQU.TEXT ; ; PROCEDURE STARTUP ; ; entry point to the debugger ; .PROC STARTUP,0 ; MOVE.L (A7)+,RTNADDR ; save return address to boot rom MOVE.W #$2700,TRAPSR ; make sure interrupts are off ; ; Copy monitor/lisabug globals from [$100, $300] to [$600, $800] for Mac. ; MOVE.W #$80,D0 ; copy 128 longs MOVE.W #$100,A0 ; from $100+ MOVE.W #$600,A1 ; to $600+ COPYLP MOVE.L (A0)+,(A1)+ ; copy next long SUB.W #1,D0 BNE.S COPYLP ; ; Zap 64 bytes (ie. 16 longs - the Lisa/Mac secondary dispatch) at $192 with -1 ; MOVE.W #16,D0 ; copy 16 longs of -1 MOVE.L #-1,D1 MOVE.W #$192,A1 ; to $192+ FILLLP MOVE.L D1,(A1)+ ; fill next long SUB.W #1,D0 BNE.S FILLLP EXIT LEA JUNK,A0 MOVE.L A0,$10C JUNK MOVE.L RTNADDR,A0 ; get return address JMP (A0) ; return to boot rom ; .END ; FILE VBLCORE.TEXT ; MACWORKS Copy ;----------------------------------------------------------------------- ; ; This file contains the core routines pertaining to the vertical ; retrace manager. VINSTALL installs a routine into the vertical ; retrace task list while VREMOVE removes it. ; ; written by Andy Hertzfeld 05-May-81 ; ; MODIFICATION HISTORY: ; ; 17-sep-81 bmw vinstall returns zero in d0 if it's happy ; 04-Jun-82 LAK use phase in VINSTALL to determine initial count ; 26-Jul-82 LAK phase of zero specifies no offset (used for exact one ; shots) - mod to VINSTALL ; 18-Jun-83 AJH saved 2 bytes by moving CoreStub ; 08-Aug-83 LAK added a comment only. ; 1-Nov-84 KWK inline VInstall patch for Modulo 65536 problem ; ;------------------------------------------------------------------------ .INCLUDE Tlasm-SYSEQU.TEXT .INCLUDE Tlasm-SYSERR.TEXT .DEF VINSTALL,VREMOVE .REF ENQUEUE,DEQUEUE .DEF CORESTUB ;stub for unimplemented routines .PROC VBLCORE,0 ;------------------------------------------------------------------------ ; ; Routine: VINSTALL ; ; Arguments: A0 (input) : address of vertical retrace control block ; D0 (output): error code - 0 no error ; -2 invalid queue element type ; ; Function: Installs a vertical retrace routine which is called after ; VBLCOUNT(A0) video frames. If VBLPHASE(A0) is non-zero (between ; 1 and VBLCOUNT(A0), inclusive), a phase offset will be added ; to the initial count which will be between 0 and VBLCOUNT(A0)-1, ; depending upon the current TICKS count; up to VBLCOUNT(A0) ; routines may be installed with different phases and invoked ; after different vertical retrace interrupts. ; ; Registers Used: D0,D1,A0,A1 ;------------------------------------------------------------------------ VINSTALL CMP #VTYPE,VBLTYPE(A0) ;is it the proper type? BEQ.S VIOK ;if so,skip VTYPWRONG MOVEQ #VTYPERR,D0 ;flag the error RTS VIOK MOVE.W VBLCOUNT(A0),D1 ;form rem(ticks/count) BEQ.S @2 ;avoid divide by zero ; kwk -- install modulo problem patch (avoid TICKS > 65536 as DIVU loses significant bits) MOVEQ #0,D0 ;clear out ticks count MOVE.W TICKS+2,D0 ;get TICKS MOD 65536 DIVU D1,D0 ;form TICKS/VBLCOUNT SWAP D0 ;then get the remainder MOVE.W VBLPHASE(A0),D1 ;first do some phase biasing BEQ.S @2 ;but only if phase is non-zero SUB.W D1,D0 ;subtract the phase ADDQ #1,D0 ;and add 1 for offset BPL.S @1 ;if positive, we're ok NEG D0 ;otherwise, make it positive @1 ADD.W D0,VBLCOUNT(A0) ;and bias the count @2 LEA VBLQUEUE,A1 ;get address of queue JSR ENQUEUE ;install it in the queue MOVEQ #0,D0 ;flag the non-error RTS ; and return... ;----------------------------------------------------------------------- ; ; The VREMOVE core routine removes a vertical retrace control block from the ; VBL queue. On entry, A0 points to the control block. D0 returns the error ; code; all other registers are preserved. ; ;----------------------------------------------------------------------- ; VREMOVE CMP #VTYPE,VBLTYPE(A0) ;is it the proper type? BNE.S VTYPWRONG ; MOVE.L A1,-(SP) ;preserve A1 LEA VBLQUEUE,A1 ;get address of queue JSR DEQUEUE ;remove it from the queue MOVE.L (SP)+,A1 ;restore A1 CoreStub RTS ;return DeQueue error code ; .END  RTS lab_2 CLR.B HfsFWorkshopDTR/LisaRSC01SCOMSC01SCOMàŽôXÍTop MOVE.L #$510,D0 _NewPtr ,Sys, Clear; (D0/byteCount:Size):A0\Ptr BNE com_1 ADDA.L #$ÿÿSmartcom II / Macintosh V2.2 BÿÿÿÿÀ@ØêF      Òן¸rÁŸ¸rÁ ‡ ‡UntitledÿÿÿÿŸ¸wlÿÿÿÿŸ¸wlÿÿÿÿŸ¸wkÿÿÿÿŸ¸w^Ÿ¸rÄŸ¸rÄŸ¸rÄŸ¸rÄŸ¸rÄŸ¸rÄŸ¸rÄŸ¸rÄŸ¸rÄŸ¸rÄŸ¸wkƒŸ¸w*ƒŸ¸w*ƒŸ¸w]ƒŸ¸wkŸ¸wkŸ¸rÄŸ¸rÄŸ¸w!Ÿ¸w"Ÿ¸w"Ÿ¸w"Ÿ¸w"Ÿ¸w"Ÿ¸w"Ÿ¸w"Ÿ¸w" Ÿ¸w" Ÿ¸w" Ÿ¸w" Ÿ¸w" Ÿ¸w"Ÿ¸w"Ÿ¸w"Ÿ¸w"Ÿ¸w#Ÿ¸w#Ÿ¸w#Ÿ¸w#Ÿ¸w#Ÿ¸w#Ÿ¸w#Ÿ¸w#Ÿ¸w#Ÿ¸w#Ÿ¸w#Ÿ¸w#Ÿ¸w#Ÿ¸w#Ÿ¸w# Ÿ¸w#!Ÿ¸w#"Ÿ¸w##Ÿ¸w#$Ÿ¸w#%Ÿ¸w#&Ÿ¸w#'Ÿ¸w#(Ÿ¸w#)Ÿ¸w#�*Ÿ¸w#Ÿ¸w%Ÿ¸w%Ÿ¸w%Ÿ¸w%Ÿ¸w%Ÿ¸w%Ÿ¸w%Ÿ¸w%Ÿ¸w% Ÿ¸w% Ÿ¸w% Ÿ¸w% Ÿ¸w% Ÿ¸w%Ÿ¸w%Ÿ¸w%Ÿ¸w%Ÿ¸w&Ÿ¸w&Ÿ¸w&Ÿ¸w&Ÿ¸w&Ÿ¸w&Ÿ¸w&Ÿ¸w&Ÿ¸w&Ÿ¸w&Ÿ¸w&Ÿ¸w&Ÿ¸w&Ÿ¸w&Ÿ¸w& Ÿ¸w&!Ÿ¸w&"Ÿ¸w&#Ÿ¸w&$Ÿ¸w&%Ÿ¸w&&Ÿ¸w&'Ÿ¸w&(Ÿ¸w&)Ÿ¸w&*Ÿ¸w&+Ÿ¸w&,Ÿ¸w&-Ÿ¸w&.Ÿ¸w&/Ÿ¸w&0Ÿ¸w&1Ÿ¸w&�2Ÿ¸w'�Ÿ¸w>Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w? Ÿ¸w? Ÿ¸w? Ÿ¸w? Ÿ¸w? Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w?Ÿ¸w@Ÿ¸w@Ÿ¸w@Ÿ¸w@�Ÿ¸w@Ÿ¸wAŸ¸wAŸ¸wAŸ¸wAŸ¸wAŸ¸wA�Ÿ¸wAŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wB Ÿ¸wB Ÿ¸wB Ÿ¸wB Ÿ¸wB Ÿ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wBŸ¸wCŸ¸wCŸ¸wCŸ¸wC Ÿ¸wC!Ÿ¸wC"Ÿ¸wC#Ÿ¸wC$Ÿ¸wC%Ÿ¸wC�&Ÿ¸wCŸ¸wEŸ¸wEŸ¸wEŸ¸wEŸ¸wEŸ¸wEŸ¸wEŸ¸wEŸ¸wE Ÿ¸wE Ÿ¸wE Ÿ¸wE Ÿ¸wE Ÿ¸wEŸ¸wEŸ¸wEŸ¸wEŸ¸wEŸ¸wEŸ¸wEŸ¸wEŸ¸wEŸ¸wEŸ¸wEŸ¸wFŸ¸wFŸ¸wFŸ¸wFŸ¸wFŸ¸wFŸ¸wFŸ¸wF Ÿ¸wF!Ÿ¸wF"Ÿ¸wF#Ÿ¸wF$Ÿ¸wF%Ÿ¸wF&Ÿ¸wF'Ÿ¸wF(Ÿ¸wF)Ÿ¸wF*Ÿ¸wF+Ÿ¸wF,Ÿ¸wF�-Ÿ¸wF Ÿ¸wH Ÿ¸wH Ÿ¸wH Ÿ¸wH Ÿ¸wH Ÿ¸wH Ÿ¸wH Ÿ¸wH Ÿ¸wH  Ÿ¸wH  Ÿ¸wH  Ÿ¸wH  Ÿ¸wH  Ÿ¸wH Ÿ¸wI Ÿ¸wI Ÿ¸wI Ÿ¸wI Ÿ¸wI Ÿ¸wI Ÿ¸wI Ÿ¸wI Ÿ¸wI Ÿ¸wI Ÿ¸wI Ÿ¸wI Ÿ¸wI Ÿ¸wI Ÿ¸wI Ÿ¸wI Ÿ¸wI Ÿ¸wI  Ÿ¸wI !Ÿ¸wI "Ÿ¸wI #Ÿ¸wI $Ÿ¸wI %Ÿ¸wI &Ÿ¸wI 'Ÿ¸wI (Ÿ¸wI )Ÿ¸wI *Ÿ¸wI +Ÿ¸wI ,Ÿ¸wI -Ÿ¸wI .Ÿ¸wJ /Ÿ¸wJ 0Ÿ¸wJ 1Ÿ¸wJ 2Ÿ¸wJ 3Ÿ¸wJ 4Ÿ¸wJ 5Ÿ¸wJ 6Ÿ¸wJ 7Ÿ¸wJ 8Ÿ¸wJ 9Ÿ¸wJ :Ÿ¸wJ ;Ÿ¸wJ <Ÿ¸wJ =Ÿ¸wJ >Ÿ¸wJ ?Ÿ¸wJ @Ÿ¸wJ AŸ¸wJ BŸ¸wJ CŸ¸wJ DŸ¸wJ �EŸ¸wJ Ÿ¸wW Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX  Ÿ¸wX  Ÿ¸wX  Ÿ¸wX  Ÿ¸wX  Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX Ÿ¸wX �Ÿ¸wY Ÿ¸wZ Ÿ¸wZ �Ÿ¸wZ Ÿ¸wZ Ÿ¸wZ Ÿ¸wZ Ÿ¸wZ Ÿ¸wZ Ÿ¸wZ Ÿ¸wZ Ÿ¸wZ �Ÿ¸wZ ƒŸ¸w[ Ÿ¸w[Ÿ¸rÁ