.H Copyright (c) 1988-2002, Gary D. Campbell NAME =PASS3 CODE=01400 1400 NEXT ------------- LINK: PASS3 --------------------- : Code in this module fans out to P3xx (xx=type of the .OBJ file), : which does the final relocation of code into a .COM image in OBJECT. : Each fixup involving an external is entered into XPATCH [@COM][#DEF] : 1400 PASS.3 ENTRY 1400 AA=%(BP+DBOT) Reset Default DBSE 1403 %(BP+DBSE)=AA 1406 SI,DS=%(BP+XPT) Bump XPT past the E-O-Code Entry 1409 SI=(SI+4) 140C %(BP+XPT)=SI 140F DI=%0 Initial "CMIN" (min code address) 1413 %(BP+OBJ)=DI 1416 %(BP+CMAX)=DI 1419 SI,DS=%(BP+FB) Pointer to File Base (1st .OBJ) 141C ES=%(BP+OBJ+2) DI,ES = Object Pointer (.COM) 141F DO CALL SET.PARMS HL = @ for .OBJ type. 1422 SWAP HL,BP Push addresses 1424 PUSH %(BP+8) 4th address = PASS 3 PROC function 1427 PUSH %(BP+10) [PAD][ 0 ] 142A SWAP HL,BP -- Push other parms Above -- 142C POP %(BP+PAD) 142F POP %BP -- Pop NEXT PARMS Here -- 1432 AA=%(SI+1) Save [Word][Byte] Max Tokens just 1435 %(BP+TFB)=AA in case it's an FB type file. 1438 %(BP+CBSE)=DI 143B CALL INIT.LST 143E CALL %%BP Call PROC function for .OBJ type. 1441 CALL MIN.SI 1444* $SI:0 1447 LOOP UNTIL EQ 1449 SI,DS=%(BP+OBJ) SI = "CMIN" (tracking MIN .OBJ code) 144C %(BP+FB)=SI 144F %(BP+FB+2)=DS 1452 DI=%(BP+CMAX) 1455 %(BP+EOF)=DI 1458 AA=DS 145A* DI:0 145C IF EQ, 145E* AA=AA+01000 1461 %(BP+EOF+2)=AA 1464 RETURN .PAD=10 1470 INIT.FB A=$SI+ Get the initial fixup key byte (and skip). 1471 SWAP AA,BC 1472 AA=%SI+ Get (and set) Total Data Allocated 1473 %(BP+TDA)=AA (for wrapup by P3FB the FB Proc Function) 1476 AA=BC 1478* BC=BC AND 03F 147C* BC=BC-03 Compute the remaining skip 147F* A::0C0 & test the Key Bits. 1481 IF NZ, 1483 PUSH %SI Here, we have CODE= and/or DATA= 1485+ SI=SI+2 We must skip over them & 1487+ BC=BC-2 deduct the count. 1489* A::080 148B IF NZ, 148D POP %(BP+CBSE) Save a CODE= 1490 DI=%(BP+CBSE) 1493* A::040 1495 * IF ZR,EXIT 1497 PUSH %SI 1499+ SI=SI+2 149B+ BC=BC-2 149D POP %(BP+DBSE) Save a DATA= 14A0 RETURN 14A1 EMIT.BC A=$(BP+PAD) Here, we move BC bytes 14A4* DI:%(BP+CMAX) from $SI --> $DI 14A7 IF GT, 14A9 SWAP DI,%(BP+CMAX) If jumping ahead into a new 14AC DO $DI+=A area of memory, we need to 14AD* DI:%(BP+CMAX) insert PAD bytes into the 14B0 LOOP UNTIL EQ area skipped. 14B2 IF EQ, 14B4 AA=DI Here we just move the bytes. 14B6 DO UNTIL BC=0 $DI+=$SI+ BC=BC-1 LOOP (BC>0) 14B8* AA=AA XOR DI 14BA IF NEG, Did we wraparound memory? 14BC* DI:0 14BE * IF NEG,EXIT No, just crossed 32K. 14C0 IF NZ,CALL WARN.4 Yes, issue warning. 14C5 %(BP+CMAX)=DI 14C8 RETURN 14C9* DI:%(BP+OBJ) Did we jump backward? 14CC IF LT, 14CE SWAP DI,%(BP+OBJ) Here is a new minimum object. 14D1+ DO DI=DI-1 So, issue PAD bytes. 14D2 ES: $DI=A 14D5* DI:%(BP+OBJ) 14D8 LOOP UNTIL EQ 14DA DO (BC>0) 14DC* ES: A:$DI Here, we emit into memory 14DF IF NE,CALL WARN.4 already skipped over, so we 14E4 $DI+=$SI+ should find a PAD in every 14E5 BC=BC-1 byte we replace. LOOP (BC>0) 14E7 RETURN .PAD=10 14F0 WARN.4 PUSH DS Overwrite or Wraparound 14F1 PUSH SI 14F2 PUSH ES 14F3 PUSH DI 14F4 PUSH BC 14F5 AA=DI 14F7 SWAP DI,%(BP+CERR) 14FA* DI=DI-AA 14FC* DI:-4 14FF IF LT, 1501 CALL WRITE.HEX 1504 SI=@W.4 1507 CALL DSPLY 150A POP BC 150B POP DI 150C POP ES 150D POP SI 150E POP DS 150F RETURN 1510*FIX.FB BC=0 1512 A=$SI+ Load & Test fixup "Key" 1513 PUSH AA 1514* A::080 1516 IF NZ, 1518* A::040 Code/Data Relative 151A AA=%(BP+CBSE) 151D IF NZ, (Code Relative) 151F AA=%(BP+DBSE) Data Relative 1522* AA=AA+%SI 1524 %DI+=AA 1525+ SI=SI+1 1526+ BC=BC+1 1527 IF ZR, 1529* A::040 152B * IF ZR,EXIT 152D A=$SI 152F CALL EVAL.FB 1532 AA=%SI 1534* A:$(BP+TFB) 1537 IF LE, 1539+ DI=DI+2 153B* A':0 153D IF NZ, 153F* DE=DE-DI 1541 ES: %(DI-2)=DE 1545+ SI=SI+1 1546+ BC=BC+1 1547 * EXIT 1549 ELSE ES: $DI=E 154C+ DI=DI+1 154D* ELSE DI:%(BP+CMAX) 1550 IF GT, 1552 %(BP+CMAX)=DI 1555+ SI=SI+1 1556+ BC=BC+1 1557 POP AA 1558 BC=~BC 155A* AA=AA AND 3F 155D* BC=BC+AA 155F RETURN .PAD=10 1570 FIND.FB SI,DS=%(BP+LST) Every CALL* here results in an 1573* BC=0 XPATCH ENTRY = [@Code][@Def#] 1575* DO SI=SI+BC (msb of Def# flags an error). 1577 BC=%SI If a Quad is accessed, the XPATCH 1579* C::0E0 entry is used to find the follow-on. 157C IF ZR, 157E* C::010 _________________ 1581 * IF ZR,EXIT / (S = Skip) \ 1583* A:$(SI+1) [T S][ DEF ][next] 1586 * IF EQ,EXIT T=0 New Entry (no def) 1588* A:$(SI+2) 1 Quad follow-on entry 158B * IF EQ,EXIT 2 Old Def (reset) 158D* BC=BC AND 0F 3 Absolute Definition 1591 * IF NZ,LOOP 1593 CALL CRASH NOTE: This routine wrecks all regs. 1596 %(BP+CNOW)=DI (On CALL DI=Current Code Emit Index) 1599 FIND.DEF ENTRY 1599 DI,ES=%(BP+SYM) 159C A=$SI *CALL (A=NEXT Token; TOS=DI) 159E* AA=AA AND 0F RETURN (DE=Abs Def of Token) 15A1* HL=0 15A3+ DO HL=HL+1 Count the Entry Number. 15A4 ES: C=$DI 15A7* BC=BC AND 0F 15AB IF ZR,CALL CRASH 15B0* A:C 15B2 IF EQ, 15B4 PUSH SI 15B5 SI=(SI+3) 15B8 DI=(DI+3) 15BB* BC=BC-03 15BE DO UNTIL BC=0 * $SI+:$DI+ BC=BC-1 LOOP EQ (BC>0) 15C0 POP SI 15C1 * IF EQ,EXIT 15C3* DI=DI+BC 15C5 LOOP 15C7* DI=DI-AA 15C9 ES: DE=%(DI+1) 15CD* ES: $DI::0F0 15D1 IF ZR, 15D3* H=H OR 080 This bit = Error Bit in XPATCH entry. 15D6 PUSH DS 15D7 PUSH SI 15D8 SI,DS=%(BP+XPT) (EMIT.XP) 15DB AA=%(BP+CNOW) 15DE %SI=AA [ @CodeEmit ] 15E0 %(SI+2)=HL [* ], where * is error bit. 15E3* SI=SI+04 15E6 %(BP+XPT)=SI 15E9 POP SI 15EA POP DS 15EB RETURN .PAD=10 15F0 FB.EXPR A=$(SI+2) EXPR = [E7][TKN][OP][word][word] 15F3* A::0F0 [E5][TKN][OP][word] 15F5 IF NZ, 15F7 CALL CLEAN.FB 15FA A=$(SI+2) 15FD DE=%(SI+3) 1600* $SI:0E7 1603 IF NE, 1605* $SI:0E5 1608 IF NE,CALL CRASH Unexpected Node Type 160D*UNARY.FB: A:1 160F IF EQ, 1611* DE=-DE 1613 RETURN 1614* A:2 1616 IF EQ, 1618 DE=~DE 161A RETURN 161B CALL CRASH Unexpected OPerator. 161E BC=%(SI+5) 1621* A::4 OP = [w1 w2 bb uu] 1623 IF ZR, w? = 00 ABS bb = 10 (w1+w2) 1625* DE=DE+BC 01 xxx 11 (w1-w2) 1627 * EXIT 10 CR uu = 01 -(w1 bb w2) 1629* ELSE DE=DE-BC 11 DR 10 ~(w1 bb w2) 162B* A=A AND 3 162D IF NZ,GOTO UNARY.FB 162F RETURN 1630*CLEAN.FB $(SI+2)=$(SI+2) AND 0F 1634* A=A XOR $(SI+2) 1637 DE=@CFB 163A GOTO A.FCN 163D CFB: =010,@AX,020,@AC,030,@AD,040,@XA,050,@XX,060,@XC,070,@XD 1652 =080,@CA,090,@CX,0A0,@CC,0B0,@CD,0C0,@DA,0D0,@DX,0E0,@DC,0F0,@DD 166A DC: CALL DA 166D AC: AA=%(SI+5) 1670* AA=AA+%(BP+CBSE) 1673 %(SI+5)=AA 1676 RETURN 1677 CD: CALL CA 167A AD: AA=%(SI+5) 167D* AA=AA+%(BP+DBSE) 1680 %(SI+5)=AA 1683 RETURN 1684 CC CALL AC 1687 CA: AA=%(SI+3) 168A* AA=AA+%(BP+CBSE) 168D %(SI+3)=AA 1690 RETURN 1691 DD: CALL AD 1694 DA: AA=%(SI+3) 1697* AA=AA+%(BP+DBSE) 169A %(SI+3)=AA 169D RETURN .PAD=10 16A0 XC: CALL XA 16A3 GOTO AC 16A5 XD: CALL XA 16A8 GOTO AD 16AA CX: CALL AX 16AD GOTO CA 16AF DX: CALL AX 16B2 GOTO DA 16B4 AX: AA=%(SI+5) 16B7 CALL EVAL.FB 16BA %(SI+5)=DE 16BD RETURN 16BE XX: CALL AX 16C1 XA: AA=%(SI+3) 16C4 CALL EVAL.FB 16C7 %(SI+3)=DE 16CA RETURN 16CB EVAL.FB PUSH BC RETURN DE=value; wreck AA,HL 16CC PUSH DS Preserve BC,SI,DS,DI,ES,BP 16CD PUSH SI 16CE EQ.FB: CALL GET.FB 16D1 IF ZR, 16D3 PUSH ES A = Token we couldn't find. 16D4 PUSH DI 16D5 CALL FIND.FB Find the symbol in SYMTAB. 16D8 POP DI DE = value of symbol=Token 16D9 POP ES 16DA POP SI 16DB POP DS 16DC POP BC $SI = 84: TKN 16DD RETURN 94: TKN 16DE SWAP BC,DE A4: TKN [Code Rel] 16E0* $SI::040 B4: TKN [Data Rel] 16E3 IF NZ, Ex: 16E5 CALL FB.EXPR 16E8 * EXIT 16EA* ELSE $SI::020 Code or Data Relative? 16ED * IF ZR,NEXT 16EF* $SI::010 16F2 IF ZR, 16F4* DE=DE+%(BP+CBSE) Code. 16F7 * EXIT 16F9* ELSE DE=DE+%(BP+DBSE) Data. 16FC * EXIT 16FE* ELSE $SI::010 1701 IF NZ, 1703 SWAP AA,DE 1704 GOTO EQ.FB 1706 POP SI 1707 POP DS 1708 POP BC DE = Absolute. 1709 RETURN .PAD=10 1710 P3FB ENTRY SI,DS=Begin Fixup Area of .OBJ file. 1710 CALL INIT.FB BC=ByteCount; DI,ES=Target OBJECT 1713 DO CALL EMIT.BC 1716* $SI:0 1719 * IF EQ,EXIT 171B CALL FIX.FB 171E LOOP 1720 AA=%(BP+TDA) 1723* %(BP+DBSE)=%(BP+DBSE)+AA 1726+ SI=SI+2 1728 RETURN 1729 P33X ENTRY SI,DS=Begin Fixup Area of .OBJ file. 1729 CALL IF3X (Uses same INIT as PASS1) 172C DO CALL EMIT.BC BC=ByteCount; DI,ES=Target OBJECT 172F* $SI:0 1732 * IF EQ,EXIT 1734 CALL FIX.3X 1737 LOOP 1739 AA=%(BP+TDA) 173C* AA:0 173E IF NZ, 1740 CALL EVAL.XX (this is the only call to EVAL.XX) 1743 %(BP+DBSE)=HL 1746+ SI=SI+2 1748 RETURN 1749*FIX.3X BC=0 174B A=$SI+ Load & Test fixup "Key" 174C PUSH AA 174D* A::080 174F IF NZ, 1751* A::040 Code/Data Relative 1753 AA=%(BP+CBSE) 1756 IF NZ, (Code Relative) 1758 AA=%(BP+DBSE) Data Relative 175B* AA=AA+%SI 175D %DI+=AA 175E+ SI=SI+1 175F+ BC=BC+1 1760 IF ZR, 1762* A::040 1764 * IF ZR,EXIT 1766 PUSH BC Here we have a by Token:Key 1767 CALL KEY.3X CALL function(Key), which will 176A POP BC Emit any $DI & bump DI. 176B+ SI=SI+1 176C+ BC=BC+1 176D* ELSE DI:%(BP+CMAX) 1770 IF GT, 1772 %(BP+CMAX)=DI 1775+ SI=SI+1 1776+ BC=BC+1 1777 POP AA 1778 BC=~BC 177A* AA=AA AND 3F 177D* BC=BC+AA 177F RETURN .PAD=10 1790 KEY.3X A=$SI 1792* AA=AA AND 0F CALL function(Key), which will 1795* AA=AA+AA Emit any $DI & bump DI. 1797* AA=AA+K3X 179A SWAP AA,BP 179B BP=%BP 179E SWAP AA,BP 179F GOTO %AA 17A1 K3X: =@CE3X,@EB3X,@EW3X,@EQ3X,@PE3X,@EB3X,@EW3X,@EQ3X 17B1 =@ER3X,@EB3X,@EW3X,@EQ3X,@EW3X,@EQ3X,@EW3X,@EQ3X 17C1 EB3X DE=(DI+1) Emit a Byte 17C4 CALL EVAL.3X 17C7 SWAP AA,HL 17C8 $DI+=A 17C9 RETURN 17CA EW3X DE=(DI+2) Emit a Word 17CD CALL EVAL.3X 17D0 EMIT.W SWAP AA,HL 17D1 %DI+=AA 17D2 RETURN 17D3 EQ3X DE=(DI+4) Emit a Quad 17D6 CALL EVAL.3X 17D9 EMIT.Q SWAP AA,HL 17DA %DI+=AA 17DB SWAP AA,BC 17DC %DI+=AA 17DD RETURN 17DE CE3X CALL EVAL.3X CODE= fixup 17E1 SWAP HL,DI 17E3 NEW.DI: A=$(BP+PAD) 17E6* DI:%(BP+CMAX) 17E9 IF GT, 17EB %(BP+CMAX)=DI 17EE SWAP HL,DI 17F0 DO $DI+=A 17F1* DI:HL 17F3 LOOP UNTIL EQ 17F5 RETURN 17F6* DI:%(BP+OBJ) 17F9 IF LT, 17FB HL=DI 17FD SWAP HL,%(BP+OBJ) 1800 DO ES: $HL=A 1803+ HL=HL-1 1804* HL:DI 1806 LOOP UNTIL LT 1808 RETURN 1809 PE3X CALL EVAL.3X .PAD= fixup 180C SWAP AA,HL 180D HL=DI 180F CALL SET.PAD 1812 GOTO NEW.DI .PAD=10 1820 ER3X CALL EVAL.3X Emit Repeat 1823 SI=(SI+3) 1826 BC=4096 1829 DO PUSH HL 182A PUSH BC 182B CALL KEY.3X 182E POP BC 182F POP HL 1830+ HL=HL-1 1831 * IF ZR,EXIT 1833 BC=BC-1 * LOOP (BC>0) 1835 CALL CRASH 1838 A=$(SI-1) 183B PUSH BP 183C BP=SP 183E %(BP+6)=AA 1841 POP BP 1842 RETURN 1843 RETURN 0020 CNXT=020 (4) CNOW + Emit Length (set just below) 1844 EVAL.3X %(BP+CNXT)=DE For EVAL.AA (set by caller for Self-Rel) 1847 %(BP+CNOW)=DI For FIND.DEF 184A AA=%SI 184C EVAL.XX PUSH %(BP+XPT) <----- This entry only called from P33X. 184F* DI:294F 02C11 1853 IF EQ, **** debug trap 1855 NOP 1856 CALL EVAL.AA <----- Located in PASS2, and ONLY 1859 POP AA CALLED from these wrappers. 185A IF LE, 185C PUSH DS NC + NZ (good value & size) 185D PUSH SI 185E SI,DS=%(BP+XPT) 1861* AA:SI 1863 IF EQ, 1865 %SI=DI 1867 %(SI+2)=@0 186C SI=(SI+4) 186F %(BP+XPT)=SI 1872* $(SI-1)=$(SI-1) OR 080 1876 POP SI 1877 POP DS 1878* HL=0 187A* BC=0 187C RETURN 187D NEXT . 1400 DBOT 1403 DBSE 1406 XPT 1413 OBJ 1416 CMAX 1419 FB 141F SET.PARMS 142C PAD 1435 TFB 1438 CBSE 143B INIT.LST 1441 MIN.SI 1455 EOF 1473 TDA 14F7 CERR 1501 WRITE.HEX 1504 W.4 1507 DSPLY 1570 LST 1593 CRASH 1596 CNOW 1599 SYM 163A A.FCN 16CE GET.FB 1729 IF3X 180F SET.PAD 1856 EVAL.AA