Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.2 9/18/84; site ut-dillo.UUCP Path: utzoo!watmath!clyde!bonnie!akgua!gatech!ut-sally!ut-ngp!ut-dillo!darin From: darin@ut-dillo.UUCP (Darin Adler) Newsgroups: net.sources.mac Subject: Source code for TMON Extended User Area (part 3 of 7) Message-ID: <233@ut-dillo.UUCP> Date: Sun, 8-Dec-85 14:35:36 EST Article-I.D.: ut-dillo.233 Posted: Sun Dec 8 14:35:36 1985 Date-Received: Tue, 10-Dec-85 05:48:20 EST Distribution: net Organization: UTexas Computation Center, Austin, Texas Lines: 1024 Part 3 of the source code for the Extended User Area. # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. -----cut here-----cut here-----cut here-----cut here----- #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # EUA.Asm.3 # This archive created: Sun Dec 8 13:28:11 1985 # By: Darin Adler () echo shar: extracting EUA.Asm.3 '(29699 characters)' cat << \SHAR_EOF > EUA.Asm.3 TST.W D0 ;Check the return code. BNE.S @12 ;If nonzero, show an error. MOVE #@13-A,D0 MOVE.B UserInform,D1 ;Check UserInform. BMI.S @12 ;If an interrupt took place, fall into the Monitor. MOVEM.L (SP)+,D0/A0 ;Otherwise exit. MOVE.L nasty0,0 ;Trash location zero. RTS @13 TRAPMon 'Interrupt' @12 ADD.W #12,SP ;Dispose the return address and D0, D1, and A1. MOVE.L 4+4*4(SP),4*4(SP) LEA A,A0 LEA (A0,D0.W),A0 ;Fall into the Monitor with the appropriate message. MOVE.L A0,4+4*4(SP) MOVEM.L (SP)+,D0/D1/A0/A1/A5 RTS ;Jump to the appropriate TRAP #$F instruction. ;This routine flips a bit in the upper left corner. FlipBit MOVE.B #1,CrsrBusy ;Mark the cursor busy. CMP.W #$A700,CrsrAddr+2 ;Is the cursor in the upper left? BNE.S NoCursorFlip CursorFlip BCHG #7,CrsrSave ;Flip the bit in the area under the cursor. NoCursorFlip BCHG #7,$3FA700 ;Flip the bit on the screen. CLR.B CrsrBusy ;The cursor isn't busy any more. RTS ;This routine turns the A000 subhooks on and off. A000 SUBQ.B #1,D7 BCS.S @4 ;No arguments given. Delete the intercepting BNE.S @1 ;subroutine. MOVE.W D0,D1 ;If one argument is given, the second argument @1 AND.W #$1FF,D0 ;is set to the first one. AND.W #$1FF,D1 CMP.W D0,D1 BCC.S @2 ;Make sure D0<=D1. EXG D0,D1 @2 CLR.W (A0)+ ;The subroutine is installed. MOVE.W D0,(A0)+ ;Store the two arguments. MOVE.W D1,(A0)+ ;Install the subroutine. SUBQ.B #3,D7 BNE.S @4 ;If there is no PC range, indicate that fact. MOVE.L Lo3Bytes,D4 ;Clear the high bytes of the two addresses. AND.L D4,D2 AND.L D4,D3 CMP.L D2,D3 BCC.S @3 ;Make sure D2<=D3. EXG D2,D3 @3 MOVE.L D2,(A0)+ ;Store the PC range. MOVE.L D3,(A0)+ BRA.S A000OnOff @4 ST (A0) ;This routine turns the A000 dispatcher on or off depending on the situation A000OnOff MOVE.W #A000Hook-A,_A000Hook-A(A2) MOVE.B TrapRList,D0 ;The subroutine isn't installed. BEQ.S @1 MOVE.B TrapSList,D0 BEQ.S @1 MOVE.B TrapDList,D0 BEQ.S @1 MOVE.B TrapCList,D0 BEQ.S @1 MOVE.B TrapIList,D0 BEQ.S @1 MOVE.B TrapGList,D0 BEQ.S @1 CLR.W _A000Hook-A(A2) ;Remove the subroutine. @1 RTS ;############################ ;## ## ;## A000 subhook section ## ;## ## ;############################ ; ;The following are the subhooks for A000 trap intercepts. ; ; ;The following is for heap check, scramble and/or purge. ; ScrambleHook MOVEM.L D2-D7/A2-A6,-(SP) SUB.W #$1E,D0 ;Is this a _NewPtr? BEQ.S @22 ;YES. SUBQ.W #$22-$1E,D0 ;NO. Is this a _NewHandle? BEQ.S @22 ;YES. SUBQ.W #$27-$22,D0 ;NO. Is this a _ReallocHandle? BEQ.S @22 ;YES. MOVEM.L 62(SP),D1/D2/A1 ;NO. Test for a _SetPtrSize or _SetHandleSize ADDQ.W #$27-$20,D0 BEQ.S @21 SUBQ.W #$24-$20,D0 BNE.S @23 ;None of these. Don't do a heap scramble. MOVE.L (A1),A1 ;De-reference the handle in a _SetHandleSize @21 SUBQ.W #8,A1 MOVE.L (A1),D2 ;Get the size of the memory manager block. AND.L Lo3Bytes,D2 SUBQ.L #8,D2 ;Subtract the size of the header. MOVEQ #$0F,D3 ;Also subtract the correction value. AND.B (A1),D3 SUB.L D3,D2 CMP.L D1,D2 ;Is the new size greater than the old size? BGE.S @23 ;If not, don't scramble. @22 BSR ScrambleHeap ;Call the ScrambleHeap routine. BRA.S @24 @23 MOVEQ #0,D0 ;If not scrambled, return error code of zero. @24 MOVEM.L (SP)+,D2-D7/A2-A6 RTS ; ;The following is for recording each trap. ; RecordHook MOVEM.L D2/A2,-(SP) LEA RecordData+2,A1 TST.B (A1)+ ;If master switch is off, do nothing. BMI.S @4 MOVE.B (A1)+,D2 ;Get the halting flag. MOVE.W (A1)+,D1 ;Get the number of messages. MOVE.L (A1),A2 ;Get the address of the table. TST.B D2 ;Is halting enabled? BEQ.S @1 MOVE #@6-A,D0 ;YES. If the table is about to overflow, exit. CMP.W -6(A1),D1 BLS.S @5 @1 ADDQ.W #1,-6(A1) ;One more message is present. ADDQ.W #6,A1 MOVE.W (A1),D2 ;Decrement the pointer to the current message BNE.S @2 ;storing place. MOVE.W D1,D2 @2 SUBQ.W #1,D2 MOVE.W D2,(A1) ASL.W #4,D2 ;Copy the message. ADD.W D2,A2 MOVE.W (A0),(A2)+ ;Copy the opcode. MOVE.W Ticks+2,(A2)+ ;Copy the time. MOVE.L A0,(A2)+ ;Copy its PC. BTST #3,(A0) BNE.S @3 MOVE.L $1A(SP),(A2)+ ;Also copy the values of D0 and A0. MOVE.L $22(SP),(A2) BRA.S @4 @3 MOVE.L $38(SP),(A2)+ ;Get the values of the top 8 stack bytes. MOVE.L $3C(SP),(A2)+ ;At this point the stack looks like this: ; D2 A2 Ret B D0 A0 Ret D0 D1 A0 A1 Ret A5 SR PC stk0 stk2 ; 0000 0000 0000 00 0011 1111 1111 1111 1122 2222 2222 2222 2233 33 3333 3333 3333 ; 0123 4567 89AB CD EF01 2345 6789 ABCD EF01 2345 6789 ABCD EF01 23 4567 89AB CDEF @4 MOVEQ #0,D0 ;No errors. @5 MOVEM.L (SP)+,D2/A2 RTS @6 TRAPMon 'Record full' ; ;The following is for discipline. ; DisciplineHook ;At this point the stack looks like this: ; Ret B D0 A0 Ret D0 D1 A0 A1 Ret A5 SR PC stack ; 0000 00 0000 1111 1111 1122 2222 2222 3333 3333 3344 44 4444 4455 ; 0123 45 6789 0123 4567 8901 2345 6789 0123 4567 8901 23 4567 8901 MOVEM.L A2/A4/A6/D7,-(SP) LEA 4*4+18(SP),A4 ;point A4 to the registers LEA 4*4+48(SP),A6 ;point A6 to the stack ;At this point A6 points to the old stack and A4 points to this: ; D0 D1 A0 A1 Ret A5 SR PC ; 0000 0000 0011 1111 1111 2222 22 2222 ; 0123 4567 8901 2345 6789 0123 45 6789 RegD0 EQU 0(A4) RegD1 EQU 4(A4) RegA0 EQU 8(A4) RegA1 EQU 12(A4) RegA5 EQU 20(A4) RegSR EQU 24(A4) RegPC EQU 26(A4) Stack0 EQU 0(A6) Stack2 EQU 2(A6) Stack4 EQU 4(A6) Stack6 EQU 6(A6) Stack8 EQU 8(A6) Stack10 EQU 10(A6) Stack12 EQU 12(A6) Stack14 EQU 14(A6) Stack16 EQU 16(A6) Stack18 EQU 18(A6) Stack20 EQU 20(A6) Stack22 EQU 22(A6) Stack24 EQU 24(A6) Stack26 EQU 26(A6) Stack28 EQU 28(A6) ;The discipline code may trash D0, D1, A0, A1 and A2 MOVE.W (A0),D1 ;Get the actual trap word. BTST #11,D1 ;Check what kind of trap. BNE.S ToolboxTrap OSTrap LEA OSTraps,A0 AND.W #$FF,D1 ;Get the trap number. BRA.S DisciplineTrap ToolboxTrap BTST #10,D1 ;Check if it is auto-pop. BEQ.S @1 ADDQ #4,A6 ;Skip over auto-pop return address. @1 LEA ToolTraps,A0 AND.W #$1FF,D1 ;Get the trap number. DisciplineTrap MOVEQ #0,D7 ADD.W D1,D1 MOVE.W 0(A0,D1.W),D1 ;Find the discipline code. BEQ.S NoDiscipline JSR 0(A0,D1.W) ;Call on discipline. NoDiscipline MOVE.W D7,D0 ;Return the error code. MOVEM.L (SP)+,A2/A4/A6/D7 RTS ; ;The following is for checksumming on each trap. ; ChecksumHook MOVE.L D2,-(SP) MOVEQ #0,D2 ;Calculate the checksum. MOVEM.L ChecksumValue+2,D0/D1 BSR Checker MOVEQ #0,D0 CMP.W ChecksumValue,D2 ;If the checksum matches, no error. BEQ.S @1 MOVE #@2-A,D0 ;Otherwise report the checksum error. @1 MOVE.L (SP)+,D2 RTS @2 TRAPMon 'Checksum failed' ; ;The following is for trap intercept. ; InterceptHook MOVE #@1-A,D0 ;Always cause an error. RTS @1 TRAPMon 'Trap intercepted' ; ;The following is for trap signalling. ; SignalHook MOVEQ #0,D0 MOVE.B UserInform,D1 ;Cause an error if UserInform is nonzero. BEQ.S @1 MOVE #@2-A,D0 @1 RTS @2 TRAPMon 'Trap signal' ;######################################### ;## ## ;## Heap check/scramble/purge section ## ;## ## ;######################################### ;+-----------------------------------------+ ;| Check, scramble, and/or purge the Heap. | ;+-----------------------------------------+ ;| ;|ENTRY: ScrambleHeap ;| ;|OUT: D0.L' Zero if scramble successful; HeapError-A otherwise. ;| ;|Destroys D1-D7,A0-A6. ;| ScrambleHeap MOVE.L SP,A2 MOVE.B CurrentHeap,D0 BSR GetZone ;Get the requested heap zone. BNE ScrambleError MOVE.B PurgeAlso,D0 BEQ.S @1 BSR.S PurgeHeap @1 LEA 48(A6),A3 CLR.L (A3)+ ScrambleLoop MOVEQ #0,D0 ;(Give a return code of 0 if exiting.) CMP.L (A6),A3 ;Exit if done. BEQ ScrambleEnd BSR GetBlockInfo ;Get information about the first block. BMI.S ScrambleLoop ;If it can't be moved, fetch the next block. MOVE.B CheckOnly,D2 ;If it isn't supposed to be moved, also fetch the BPL.S ScrambleLoop ;next block. MOVE.B D0,D3 ;Save the information about the first block. MOVE.L D1,D4 MOVE.L A4,A5 ;A3 is the current address. CMP.L (A6),A3 ;D3 is the type of the first block. BEQ.S ScrambleClr ;D4 is the length of the first block. BSR GetBlockInfo ;A5 is the address of the first block. BMI.S ScrambleClr ;D0 is the type of the second block. ADD.B D3,D0 ;D1 is the length of the second block. BEQ.S Scramble2Blank ;A4 is the address of the second block. BMI ScrambleSwap TST.B D3 BEQ.S ScrambleAlter2nd MOVEQ #0,D6 BSR.S AlterCount ;Get all the free areas after the block. BSR.S AlterLen ;Find their total length. BSR.S Alter1st ;Swap a block with a free area. The block is first. EXG D1,D4 MOVE.L A5,A0 MOVE.L A3,A1 MOVE.L D1,D0 _BlockMove ScrambleClr2 MOVEQ #4,D1 ;Don't touch the next block. BSR.S ScrambleClear BRA.S ScrambleLoop ScrambleAlter2nd BSR.S Alter2nd ;Swap a free area with a block. The block is MOVE.L A4,A0 ;second. MOVE.L A5,A1 MOVE.L D1,D0 MOVE.L D0,D5 _BlockMove MOVE.L D4,(A3) ;Store the length of the free area. BRA.S ScrambleLoop Scramble2Blank MOVE.L A4,A3 ;Skip past one blank block. ScrambleClr TST.B D3 ;Check if the first block is a free area. BNE.S ScrambleLoop ;If not, don't clear it. CMP.B #$C1,D0 ;In the special case that the first block is a free BNE.S ScrambleClr2 ;block and the second one an immovable free block, MOVE.L D1,-(SP) ;consolidate the two blocks. MOVEQ #0,D1 ;Erase the first long word of the second free block BSR.S ScrambleClear ;as well. MOVE.L (SP)+,D1 ADD.L D1,-(A5) BRA.S ScrambleLoop PurgeHeap MOVE.L theZone,-(SP) ;Call MaxMem to do a purge. MOVE.L A6,theZone _MaxMem MOVE.L (SP)+,theZone RTS Alter1st MOVE.L 4(A5),A0 ;Adjust the handle to the first block. ADD.L D1,0(A6,A0.L) RTS AlterCount MOVEQ #0,D7 ;On exit, D7 will contain the number of blocks that MOVE.L A4,A1 ;were found. @1 ADDQ.W #1,D7 CMP.L (A6),A3 ;Don't go past the end of the Heap. BEQ.S @2 BSR GetBlockInfo ;Get a block. CMP.B D0,D6 ;Does it have the desired type? BEQ.S @1 ;YES. Look at the next block. MOVE.L A4,A3 ;NO. Go to the previous block. @2 MOVE.L A1,A4 ;Restore A4. A3 contains one byte past the end of RTS ;the last block found. Alter2nd MOVEQ #$40,D6 ;Skip past any following relocatable blocks. BSR.S AlterCount MOVE.L A1,A3 ;Do a second pass over these blocks. @1 BSR GetBlockInfo SUB.L D4,(A0) ;Adjust the handles of all these blocks. SUBQ.W #1,D7 BNE.S @1 MOVE.L A1,A4 AlterLen MOVE.L A3,D1 ;Find the total length of the blocks that were SUB.L A4,D1 ;found. SUBA.L D4,A3 ;ScrambleLoop will fetch the second block. RTS ScrambleClear MOVE.L D4,(A5)+ ;Clear the first block. (Assumes that it is a free SUB.L D1,D4 ;area). ADD.L D4,A5 MOVE.L #'XYXY',D0 LSR.L #1,D4 ;D4 is the number of words to clear. MOVE.L D4,D1 AND.W #31,D1 ;Use a slower loop to clear a number of words that BRA.S @2 ;is not a multiple of 32 words. @1 MOVE.W D0,-(A5) @2 DBRA D1,@1 LSR.L #5,D4 BEQ.S @5 MOVE.L D0,D1 ;Now use a super-fast loop to clear the rest in MOVE.L D0,D2 ;multiples of 32 words. MOVE.L D0,D3 MOVE.L D0,D7 MOVE.L D0,A0 MOVE.L D0,A1 MOVE.L D0,A4 BRA.S @4 @3 MOVEM.L D0/D1/D2/D3/D7/A0/A1/A4,-(A5) MOVEM.L D0/D1/D2/D3/D7/A0/A1/A4,-(A5) @4 DBRA D4,@3 @5 RTS ScrambleSwap BSR.S Alter2nd ;Swap two blocks. This may not be a very fast BSR.S Alter1st ;operation. MOVE.L #160*5,D2 CMP.L D2,D1 ;If both blocks are large, use the slow algorithm. BLS.S @1 CMP.L D2,D4 BHI.S SlowSwap @1 MOVE.W #160,D2 ;Use a lightning-fast algorithm if at least one SUB.L D2,SP ;block is small enough. Reserve 160 bytes on stack. ADD.L D1,A4 ;A4 now points to the end of the second block. CMP.L D1,D4 BHI.S @10 ADD.L D4,D1 ;D1 now contains the total length. @2 MOVE.L D2,D0 ;The first block is the smaller one. SUB.L D2,D4 BCC.S @3 ;Put either 160 or the remaining length of the first ADD.L D2,D4 ;block into D0, whichever is smaller. MOVE.L D4,D0 MOVEQ #0,D4 @3 MOVE.L A5,A0 ;Save D0 bytes from the beginning of the first MOVE.L SP,A1 ;block. BSR.S FastPush MOVE.L A5,A1 ;Shift the remaining bytes to lower memory to cover NEG.L D0 ;the hole that was created. ADD.L D1,D0 _BlockMove MOVE.L SP,A0 ;Store the saved bytes at the end of the second MOVE.L A4,A1 ;block. SUB.W D3,A1 BSR.S FastPull TST.L D4 BNE.S @2 ;If the swap isn't complete, shift again. BRA.S @20 @10 ADD.L D1,D4 ;D4 now contains the total length. @11 MOVE.L D2,D0 SUB.L D2,D1 BCC.S @12 ;Put either 160 or the remaining length of the ADD.L D2,D1 ;second block into D0, whichever is smaller. MOVE.L D1,D0 MOVEQ #0,D1 @12 MOVE.L A4,A0 ;Save D0 bytes from the end of the second block. SUB.W D0,A0 MOVE.L SP,A1 BSR.S FastPush MOVE.L A5,A0 ;Shift the remaining bytes to higher memory to cover MOVE.L A5,A1 ;the hole that was created. ADD.W D0,A1 NEG.L D0 ADD.L D4,D0 _BlockMove MOVE.L SP,A0 ;Store the saved bytes at the beginning of the MOVE.L A5,A1 ;first block. BSR.S FastPull TST.L D1 BNE.S @11 ;If the swap isn't complete, shift again. @20 ADD.L D2,SP ;Release the memory reserved on the stack and exit. toScrambleLoop BRA ScrambleLoop FastPush MOVE.W D0,D3 FastPull LSR.W #2,D3 ;This is a semi-efficient block move routine that BCC.S @2 ;doesn't have the overhead of calling _BlockMove. MOVE.W (A0)+,(A1)+ BRA.S @2 @1 MOVE.L (A0)+,(A1)+ @2 DBRA D3,@1 MOVE.W D0,D3 RTS SlowSwap BSR.S SlowScramble ;Call the subroutine and go back to the main loop. BRA.S toScrambleLoop SlowScramble MOVE.L A4,A0 ;This is a slower algorithm used for larger blocks. ADD.L D1,A0 ;A0 is one byte beyond the last byte to be moved. ADD.L D4,D1 MOVE.L D1,D7 ;D7 is now the total length. LSR.L #1,D1 ;D1 is now the total length/2. BRA.S @4 @5 ADD.L D7,A1 ;In this loop, continue to swap the word in the CMP.L A0,A1 ;register with the next word in the memory until BNE.S @2 ;the two blocks are transposed. Do not swap any MOVE.W D2,(A1) ;of the words more than once; if that is about to @4 MOVE.W -(A0),D2 ;happen, move the pointer to the preceeding word. MOVE.L A0,A1 BRA.S @3 @1 SUB.L D4,A1 CMP.L A5,A1 BLT.S @5 @2 MOVE.W (A1),D3 MOVE.W D2,(A1) MOVE.W D3,D2 @3 DBRA D1,@1 SUB.L val10000,D1 BCC.S @1 RTS ;+--------------------------+ ;| Get either the system or | ;| application heap zone. | ;| Avoid address errors. | ;+--------------------------+ ;| ;|ENTRY: GetZone ;| ;|IN: Z: flag set for system zone, clear for application zone. ;| ;|OUT: D0.L' ^heap zone. ;| A6' ^heap zone (same as D0.L'). ;| ;|Destroys A3. ;| GetZone BNE.S @1 ;Get the requested heap zone and put it into D0 and LEA SysZone,A3 ;A6, relying on the zero flag on entry: BRA.S @2 ;Z set for system zone, clear for application zone. @1 LEA ApplZone,A3 @2 MOVE.L (A3),D0 BCLR #0,D0 ;If the address is odd, make it even. MOVEA.L D0,A6 RTS ;+------------------------------------------------+ ;| Examine one heap block. If an error is found, | ;| MOVE.L A2,SP, MOVE #HeapError-A,D0, and RTS | ;| are executed. | ;+------------------------------------------------+ ;| ;|ENTRY: GetBlockInfo ;| ;|IN: A3: ^block's header. ;| A6: ^heap zone that contains the block. ;| A2: SP to use in case an error is found. ;| ;|OUT: If an error was found, the error routine is entered. Otherwise, ;| A3' ^next block's header. ;| A4' A3: ;| D1.L' length of this block. ;| CCR' represents TST.B D0'. ;| D0.B' block type ($00,$40,$80,$C0,$C1). ;| =$00' free block. ;| =$40' relocatable block. ;| D2.L' handle value. ;| A0' handle address. ;| =$80' non-relocatable block. ;| =$C0' locked relocatable block. ;| =$C1 a free block that shouldn't be moved. ;| ;|Destroys A0. ;| GetBlockInfo MOVE.L A3,A4 ;Save A3. MOVE.B (A3),D0 ;Get the block type. MOVE.L (A3)+,D1 ;Get the block length. MOVE.L (A3)+,A0 ;Get the handle or heap zone address. AND.L Lo3Bytes,D1 AND.B #$C0,D0 BEQ.S InfoEnd ;If this is a free block, leave. BMI.S InfoRelocatable ;Do relocatable and illegal blocks. MOVEQ #$FFFFFF80,D0 ;This is a nonrelocatable block. The indicated heap CMP.L A0,A6 ;zone address should match A6. BEQ.S InfoEnd ScrambleError MOVE.L A2,SP ;Go to the error routine. MOVE #HeapError-A,D0 RTS HeapError TRAPMon 'Heap error' InfoRelocatable SUB.B #$40,D0 ;If this is a $C0 type block, it is illegal. BMI.S ScrambleError MOVE.L A0,D2 ;If the handle address is odd, the block is illegal. LSR.B #1,D2 BCS.S ScrambleError ADD.L A6,A0 MOVE.L (A0),D2 ;If this relocatable block is locked, give it the BPL.S @1 ;$C0 type. MOVEQ #$FFFFFFC0,D0 @1 AND.L Lo3Bytes,D2 CMP.L D2,A3 ;Make sure that this block's handle points back to BNE.S ScrambleError ;the block. InfoEnd SUBQ.L #8,D1 ;Now add the length of the block to the address. BCS.S ScrambleError ;If the block size is less than eight, give an BTST #0,D1 ;error. BNE.S ScrambleError ADD.L D1,A3 CMP.L (A6),A3 BCS.S @1 BHI.S ScrambleError ;Don't allow blocks beyond the end of the Heap. TST.B D0 ;If the last block is a free area, don't scramble it. BNE.S @1 MOVEQ #$FFFFFFC1,D0 @1 ADDQ.L #8,D1 ;Correct for the two autoincrement instructions. TST.B D0 ScrambleEnd RTS ;###################### ;## ## ;## Label routines ## ;## ## ;###################### ;+--------------------------------------------------------+ ;| Check if D2 is in a 'CODE' resource, and, if so, | ;| attempt to find the name of the routine containing D2. | ;+--------------------------------------------------------+ ;| ;|ENTRY: CodeLabelScan ;| ;|IN: D2.L: address to identify. ;| D0.L: 0. ;| D5.L: if D2 is in a resource, offset from the resource beginning to D2. ;| D6.L: if D2 is in a resource, the resource type; otherwise, 0. ;| D7.L: Bits 0..15 contain the resource ID. Bits 16..23 contain the value of _Inhibits. ;| A4: if D2 is in a resource, beginning address of the heap block. (D2:-D5:) ;| A3: if D2 is in a resource, ending address of the heap block. (D2:-D5:) ;| A5: ^Monitor's variables. ;|(D4 is initialized by the Monitor, but this routine does not use it.) ;| ;|OUT: D0.L'=0 D2 could not be identified. ;| D2.L' D2.L:. ;| D0.L'<>0 D2 was identified. ;| D0.L' first four letters of name. ;| D1.L' last four letters of name. ;| A1' address of the routine's beginning (the LINK instruction). ;| D2.L' D2.L:-A1'. ;| ;|Destroys D1,D3,A0,A1. ;| CodeLabelScan MOVEM.L D4/D6/D7,-(SP) ;Save registers. CMP.L #'CODE',D6 ;Don't search for code routine names unless this is BNE.S @10 ;a code segment. MOVE.L D2,D7 ;D7 will contain D2 truncated to an even value. BCLR #0,D7 MOVE.L D7,A0 MOVE.L A3,D3 ;D3 contains the number of words left to scan SUB.L D7,D3 ;before giving up at $800 or finishing at the end of CMP.W #$800,D3 ;the block. BCS.S @1 MOVE.W #$800,D3 @1 LSR.W #1,D3 ADDQ.L #2,D7 ;Increment the starting position pointer by 2. @19 MOVE.W #$4E75,D1 ;D1.W: RTS MOVE.W #$4ED0,D6 ;D6.W: JMP (A0) MOVE.W #$4E56,D4 ;D4.W: LINK A6,#____ BRA.S @3 @2 MOVE.W (A0)+,D0 ;Get the next word. CMP.W D1,D0 ;Search for one of the above instructions. BEQ.S @20 ;If RTS or JMP (A0) is found, investigate further. CMP.W D6,D0 BEQ.S @20 CMP.W D4,D0 @3 DBEQ D3,@2 ;If the LINK is found first, exit with no label. BNE.S @10 ;If the LINK is the first instruction encountered, CMPA.L D7,A0 ;leave it as it is because it may be the beginning BEQ.S @19 ;of the subroutine. @10 MOVEQ #0,D0 ;Pass back no label code. @11 MOVEM.L (SP)+,D4/D6/D7 ;Return. RTS @20 CMP.W #4,D3 ;If there are less than eight bytes left to scan, BCS.S @10 ;it's not possible to have a full name here. BSR.S CheckUNLK ;Check for an UNLK instruction before the RTS or BNE.S @3 ;JMP (A0). If not found, continue searching. MOVEQ #7,D6 @21 ROL.L #8,D0 ;Check the name to make sure that there are eight ROL.L #8,D1 ;letters of valid ASCII values present. MOVE.B D1,D0 MOVE.B (A0)+,D1 CMP.B #6,D6 BCS.S @22 AND.B #$7F,D1 ;Clear the high bit of the first and second bytes. @22 CMP.B #' ',D1 ;Anything between $20 and $7E is valid. BCS.S @10 CMP.B #$7F,D1 BCC.S @10 DBRA D6,@21 MOVE.W D5,D3 ;A valid name has been found. Now search backwards LSR.W #1,D3 ;for the LINK instruction. MOVE.L D7,A1 @23 CMP.W -(A1),D4 DBEQ D3,@23 BNE.S @10 ;If run out of the block, exit. SUB.L A1,D2 ;Otherwise give the offset in D2 and return BRA.S @11 ;successfully. ;+-------------------------------------------------------+ ;| Make sure that an UNLK A6 instruction exists no more | ;| than ten words in front of A0. Also make sure that | ;| there is no LINK A6 between the UNLK A6 and A0. | ;+-------------------------------------------------------+ ;| ;|ENTRY: CheckUNLK ;| ;|IN: A0: Address from which to search. ;| ;|OUT: Z flag' set if the conditions above satisfied, clear otherwise. ;| ;|Destroys nothing. ;| CheckUNLK MOVEM.L D0/A0,-(SP) ;Save registers. MOVEQ #9,D0 ;Search ten words. @1 CMP.W #$4E5E,-(A0) ;UNLK A6 BEQ.S @2 CMP.W #$4E56,(A0) ;LINK A6,#____ DBEQ D0,@1 MOVEQ #-1,D0 ;If not found or LINK found first, clear Z flag. @2 MOVEM.L (SP)+,D0/A0 ;Return (MOVEM preserves flags). RTS ;+----------------------------------+ ;| Find a given embedded routine | ;| 8-character name in code blocks. | ;| See manual for details. | ;+----------------------------------+ ;| ;|ENTRY: CodeLabelFind ;| ;|IN: D0.L: first four characters of the name converted to upper case. ;| D1.L: last four characters of the name converted to upper case. ;| D7.L: bits 16..23 contain the value of _Inhibits. ;| A5: ^Monitor's variables. ;| ;|OUT: D0.L'=0 the name has been found. ;| D2.L' the location of the routine that has the given name. ;| D0.L'=D0.L: the name has not been found. ;| ;|Destroys D2,D3,A0,A1. ;| CodeLabelFind MOVEM.L D0/D1/D4-D7/A2-A4/A6,-(SP) BTST #16+3,D7 ;If can't scan resources, do nothing. BNE @40 MOVE.L SP,A6 MOVE.L $A50,D1 ;Start with the first resource file. @1 JSR _NextCResFile ;Check the next file. BEQ @40 ;If there is none, no data will be found. MOVE.L A1,A0 MOVE.W (A0)+,D3 ;D3 has the number of types+1. MOVE.L #'CODE',D2 @11 CMP.L (A0)+,D2 ADDQ.W #4,A0 ;Look for blocks of type 'CODE'. DBEQ D3,@11 BNE.S @1 ;If not found, scan the next file. MOVE.W -(A0),D0 ADD.W D0,A1 ;Find the ID list and check for address errors. LSR.W #1,D0 BCS.S @1 MOVE.W -(A0),D6 ;D6 now has the number of 'CODE' IDs in the table. @12 ADDQ.W #8,A1 MOVE.L (A1)+,A0 ;See if this 'CODE' segment is legally in memory. BSR IndirectA0 BCS.S @50 ;NO. TST.W -12(A1) ;YES. If its ID is zero, however, do not scan it. BEQ.S @50 MOVE.L -8(A0),D0 AND.L Lo3Bytes,D0 MOVEQ #$0F,D2 AND.B -8(A0),D2 ;Subtract the size correction from the size. SUB.L D2,D0 MOVEQ #8,D2 SUB.L D2,D0 BMI.S @50 ;If a negative number results, skip to the next LSR.L #1,D0 ;block. CMP.L #$8000,D0 BCS.S @13 MOVE.L #$7FFF,D0 @13 MOVE.W #$4E56,D2 ;D2.W: LINK A6,#____ MOVE.W #$4E75,D3 ;D3.W: RTS MOVE.W #$4ED0,D4 ;D4.W: JMP (A0) BRA.S @21 @20 CMP.W (A0)+,D2 ;Search for a LINK instruction. @21 DBEQ D0,@20 BNE.S @50 ;Not found within the block. @22 MOVEA.L A0,A2 ;Save the address and look for either RTS or BRA.S @24 ;JMP (A0). @23 MOVE.W (A0)+,D5 CMP.W D5,D3 BEQ.S @30 CMP.W D5,D4 BEQ.S @30 CMP.W D5,D2 ;If another LINK is found first, restart this loop. @24 DBEQ D0,@23 BNE.S @50 MOVEQ #-1,D5 ;Clear the Z flag and search again. BRA.S @22 @30 BSR CheckUNLK ;Check for an UNLK instruction before the RTS or BNE.S @24 ;JMP (A0). BSR.S CheckName BNE.S @21 SUBQ.W #2,A2 MOVE.L A2,D2 CLR.L (SP) ;Clear D0 on the stack image. @40 MOVEM.L (SP)+,D0/D1/D4-D7/A2-A4/A6 RTS @50 DBRA D6,@12 ;Examine the next block, or, if there are no more, BRA @1 ;the next file. ;+---------------------------------------------------------------------------------+ ;| Compare the names at (A0)+ and (A6)+. Convert the name at (A0)+ to upper case | ;| and clear the 7th bit in its first 2 characters for the purpose of comparison. | ;| The name at (A6)+ is assumed to be in upper case, as it will be if it was | ;| generated by the Monitor. Both names must be eight characters long. | ;+---------------------------------------------------------------------------------+ ;| ;|ENTRY: CheckName ;| ;|IN: A0: string1, upper or lower case, 7th bit clear or set on first character. ;| A6: string2, upper case only, 7th bit clear. ;| ;|OUT: Z flag' set if uppercase(string1)=string2 ;| clear otherwise. ;| ;|Destroys nothing. ;| CheckName MOVEM.L D0/D1/A1/A2,-(SP) MOVEQ #7,D0 ;Compare eight characters. MOVE.L A6,A1 ;Use copies of A0 and A6. MOVE.L A0,A2 @4 MOVEQ #$7F,D1 ;Clear the high bit of the first character. AND.B (A2)+,D1 BRA.S @3 @1 CMP.B #6,D0 BHS.S @4 MOVE.B (A2)+,D1 @3 CMP.B #'a',D1 ;Convert to upper case. BCS.S @2 CMP.B #'z'+1,D1 BCC.S @2 SUB.B #$20,D1 @2 CMP.B (A1)+,D1 ;Compare and exit as soon as a mismatch is found or DBNE D0,@1 ;eight characters match. MOVEM.L (SP)+,D0/D1/A1/A2 RTS ;+---------------------------+ ;| Find a given 8-character | ;| label in the label table. | ;| See manual for details. | ;+---------------------------+ ;| ;|ENTRY: LabelFind ;| ;|IN: D0.L: first four characters of the name converted to upper case. ;| D1.L: last four characters of the name converted to upper case. ;| D7: bits 16..23 contain the value of _Inhibits. ;| A5: ^Monitor's variables. ;| ;|OUT: D0.L'=0 the name has been found. ;| D2.L' the location of the routine that has the given name. ;| D0.L'=D0.L: the name has not been found. ;| D2.L' unpredictable. ;| ;|Destroys D3,A0,A1. ;| ;| ;|ENTRY: LabelFind. ;| ;|Same as LabelFind except that if D2.B is nonzero, the subroutine will not check if the resource is in ;|memory for resource-relative labels. Moreover, the address of the label will be passed back in ;|A0 if the label is found. However the address of built-in labels is never returned. ;| LabelFind MOVEQ #0,D2 LabelFind. MOVE.B LabelEnabled,D3 ;If there is no table of labels, do nothing. MOVEM.L D0/D1/D5/D6/A3/A4/A6,-(SP) MOVE.L SP,A6 ;A6 points to the saved name on the stack. BMI.S @20 MOVE.L LabelTable,A0 SUBQ.W #8,A0 MOVE.W NumLabels,D3 MOVEQ #-1,D0 ;Clear the Z flag. BRA.S @2 @1 ADD.W #16,A0 ;Check the names in the label table. BSR.S CheckName @2 DBEQ D3,@1 BEQ.S @21 ;If found, continue @20 LEA UALabelTable+8,A0 ;Point to built in label table. MOVE.W #NumUALabels,D3 MOVEQ #-1,D0 BRA.S @22 @23 ADD.W #16,A0 BSR.S CheckName @22 DBEQ D3,@23 @21 BNE.S @10 ;If no match, exit. MOVE.L -(A0),D3 ;Determine whether this is an absolute or MOVE.B D2,D0 ;resource-relative label. MOVE.L -(A0),D2 TST.B (A0) BEQ.S @3 ;If absolute, exit successfully. TST.B D0 BNE.S @3 ;If supposed to pass back label address, exit now. BTST #16+3,D7 ;If resource-relative, resource scanning must not be BNE.S @10 ;inhibited! SWAP D3 JSR _FindRes ;Find the desired resource, and, if all is well, TST.B D0 ;add the offset to its beginning. BNE.S @10 CLR.W D3 SWAP D3 ADD.L D3,D2 @3 LEA UALabelTable,A1 CMP.L A1,A0 BLO.S @24 LEA UALabelTableEnd,A1 CMP.L A1,A0 BHS.S @24 MOVEQ #0,D0 MOVE.L D0,A0 ;Do NOT return a pointer for built-ins @24 CLR.L (SP) ;Clear D0 on the stack image. @10 MOVEM.L (SP)+,D0/D1/D5/D6/A3/A4/A6 @11 RTS ;+------------------------------------+ ;| Search the label table for a label | ;| that could be used to identify D2. | ;| The resource-relative labels will | ;| be ignored if D6 is 0. | ;+------------------------------------+ ;| ;|ENTRY: LabelScan ;| ;|IN: D2.L: address to identify. ;| D0.L: 0. ;| D5.L: if D2 is in a resource, offset from the resource beginning to D2. ;| D6.L: if D2 is in a resource, the resource type; otherwise, 0. ;| D7.L: Bits 0..15 contain the resource ID. Bits 16..23 contain the value of _Inhibits. ;| A4: if D2 is in a resource, beginning address of the heap block. (D2:-D5:) ;| A3: if D2 is in a resource, ending address of the heap block. (D2:-D5:) ;| A5: ^Monitor's variables. ;|(D4 is initialized by the Monitor, but this routine does not use it.) SHAR_EOF if test 29699 -ne "`wc -c EUA.Asm.3`" then echo shar: error transmitting EUA.Asm.3 '(should have been 29699 characters)' fi # End of shell archive exit 0 -- Darin Adler {gatech,harvard,ihnp4,seismo}!ut-sally!ut-dillo!darin