LOADER.LST 125 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906
  1. Listing:
  2. 1 IMPLEMENTATION MODULE Loader;
  3. 2 IMPORT SYSTEM,LoaderA;
  4. 3 FROM LoaderA IMPORT MoveUp,MainName;
  5. ***** ^ duplicate identifier
  6. 4
  7. 5 (*# data(const_in_code=>off) *)
  8. 6 (*# call(o_a_copy=>off,o_a_size=>off) *)
  9. 7 (*# call(seg_name=>null) *)
  10. 8 (*# data(near_ptr=>off,threshold=>0FFFFH) *)
  11. 9 (*#call(inline_max=>1000)*)
  12. 10 (*# call(near_call=>off,overlay=>on) *)
  13. 11
  14. 12 (* limits *)
  15. 13 CONST
  16. 14 MaxName = 80; (* size of module name *)
  17. 15 MaxSeg = 255; (* number of segments in a module *)
  18. 16 MaxEntry = 1000; (* number of entry points in a module *)
  19. 17 MaxModule = 64; (* number of modules *)
  20. 18 MaxGate = 2000;
  21. 19 HeapSize = 6000H;
  22. 20 FileLimit = 10; (* open file limit (temp file not included) *)
  23. 21 TempLimit = 8*100000H; (* 8 Megabytes *)
  24. ***** ^ not supported yet
  25. 22 TempPageShift = 10;
  26. 23 TempPageSize = 1 << TempPageShift;
  27. ***** ^ not supported yet
  28. 24 (*%T EMS*)
  29. 25 CONST EmsPageSize = 4000H DIV TempPageSize;
  30. ***** ^ not supported yet
  31. 26 (*%E*)
  32. 27 CONST PanicSize = 8000H;
  33. 28
  34. 29 TYPE SegKind = (StaticSeg, SwapSeg, MoveSeg, FixedSeg, SystemSeg);
  35. 30 TYPE SegKindSet = SET OF SegKind;
  36. ***** ^ not supported yet
  37. 31
  38. 32 (* tracing controls *)
  39. 33 CONST
  40. 34 MemoryTrace = FALSE;
  41. 35 LoadTrace = FALSE;
  42. 36 ExitTrace = FALSE;
  43. 37 MemTraceSet = SegKindSet{ StaticSeg, SwapSeg, MoveSeg, FixedSeg};
  44. ***** ^ ';' expected
  45. 38 UsageTrace = FALSE;
  46. 39 OutOfMemTrace = FALSE;
  47. 40 MoveTrace = FALSE;
  48. 41 Debuging = FALSE;
  49. 42 GraphUseTrace = FALSE;
  50. 43 TraceToFile = FALSE;
  51. 44
  52. 45 (* emergency tracing *)
  53. 46 CONST
  54. 47 LockTrace = FALSE;
  55. 48 FileTrace = FALSE;
  56. 49 CallTrace = FALSE;
  57. 50 EntryTableTrace = FALSE;
  58. 51 RelocateTrace = FALSE;
  59. 52
  60. 53 (* error messages *)
  61. 54
  62. 55 ErrBase = 8500;
  63. 56
  64. 57 ErrOutOfMem = 0;
  65. 58 ErrTempFileLimit = 1;
  66. 59 ErrLoad = 2;
  67. 60 ErrPoolLimit = 3;
  68. 61 ErrGateLimit = 4;
  69. 62 ErrTempDiskFull = 5;
  70. 63 ErrDiskFull = 6;
  71. 64 ErrTempCreate = 7;
  72. 65 ErrInternal = 8;
  73. 66 ErrNearHeap = 9;
  74. 67 ErrModuleLimit = 10;
  75. 68 ErrInvalidProcedure = 11;
  76. 69 ErrMemoryCorruption = 12;
  77. 70 ErrTooManyUnlocks = 13;
  78. 71 ErrCallChainInvalid = 14;
  79. 72 ErrOpenFail = 15;
  80. 73 ErrNamedImport = 16;
  81. 74 ErrInvalidVUnfix = 17;
  82. 75 ErrInvalidVFix = 18;
  83. 76 ErrInvalidFree = 19;
  84. 77
  85. 78
  86. 79
  87. 80 (*-----------------------------------------------------------------------*)
  88. 81 (* low level file handling *)
  89. 82 (*-----------------------------------------------------------------------*)
  90. 83 (*# save,call(same_ds=>off) *)
  91. 84 (*# call(near_call=>on) *)
  92. 85 (*# call(reg_param=>(bx, dx, cx), reg_saved=>(ds, di, si, st1, st2)) *)
  93. 86 PROCEDURE FileSeek(h:CARDINAL;pos:LONGCARD); IN LoaderA;
  94. 87 (*# call(reg_param=>(dx, ax, cx, bx), reg_saved=>(ds, di, si, st1, st2)) *)
  95. 88 PROCEDURE FileRead(a:ADDRESS;count:CARDINAL;h:CARDINAL); IN LoaderA;
  96. 89 PROCEDURE FileWrite(a:ADDRESS;count:CARDINAL;h:CARDINAL):CARDINAL; IN LoaderA;
  97. 90 (*# call(reg_param=>(bx), reg_saved=>(ds, di, si, st1, st2)) *)
  98. 91 PROCEDURE FileClose(h:CARDINAL); IN LoaderA;
  99. 92 (*# call(reg_param=>(ax,bx,cx,dx,si)) *)
  100. 93 PROCEDURE Exec(psp,ss,sp,cs,ip:CARDINAL); IN LoaderA;
  101. 94 (*# call(reg_param=>(dx, bx, ax), reg_saved=>(ds, di, si, st1, st2)) *)
  102. 95 PROCEDURE FileOpen(name:ARRAY OF CHAR;mode:BITSET):CARDINAL; IN LoaderA;
  103. 96 PROCEDURE DosExit; IN LoaderA;
  104. 97 PROCEDURE FileDelete(name:ARRAY OF CHAR); IN LoaderA;
  105. 98 PROCEDURE FileCreate(name:ARRAY OF CHAR):CARDINAL; IN LoaderA;
  106. 99 PROCEDURE FileCreateNew(VAR name : ARRAY OF CHAR):CARDINAL; IN LoaderA;
  107. 100 (*# call(reg_param=>(bx), reg_saved=>(ds, di, si, st1, st2)) *)
  108. 101 PROCEDURE FileSize(h:CARDINAL):LONGCARD; IN LoaderA;
  109. 102 (*# restore *)
  110. 103
  111. 104
  112. 105
  113. 106 TYPE
  114. 107 ModNum = [1..MaxModule];
  115. 108 SegNum = CARDINAL;
  116. 109 DoSegOp = (Load,Swap,Discard);
  117. 110
  118. 111 TYPE HeapADDR = SHORTADDR;
  119. 112 CONST HeapAdr ::= Ofs;
  120. 113
  121. 114 (*# data(near_ptr=>on) *)
  122. 115
  123. 116 CONST FreeGate = 0;
  124. 117 CONST DeletedGate = 1;
  125. 118 CONST IndirectGate = 0E8H; (* call near *)
  126. 119 CONST DirectGate = 0EAH; (* jump far *)
  127. 120
  128. 121 TYPE
  129. 122 GatePtr = POINTER TO GateRec;
  130. 123 GateRec = RECORD
  131. 124 state : SHORTCARD;
  132. 125 w1 : CARDINAL;
  133. 126 w2 : CARDINAL;
  134. 127 next_direct: GatePtr;
  135. 128 END; (*GateRec*)
  136. 129 (* bits for Seghdr.flags *)
  137. 130 SegAttr = (IsData,Typ2,Typ3,IsIter,IsMove,IsPure,IsPreLoad,IsExRd,
  138. 131 HasReloc,Iop1,Iop2,Iop3,IsDiscard,Is32,IsHuge,DataActive);
  139. 132 SegSet = SET OF SegAttr;
  140. 133 SegPtr = POINTER TO SegRec;
  141. 134 SegRec = RECORD
  142. 135 no_op : SHORTCARD; (* 090H return gates point here *)
  143. 136 jump_op : SHORTCARD; (* 0E9H call gates point here *)
  144. 137 jump_disp : CARDINAL; (* jumps to GateHandler *)
  145. 138 seg_val : CARDINAL;
  146. 139 direct_list: GatePtr;
  147. 140 fix_count : CARDINAL;
  148. 141 (* last four fields are read straight from file *)
  149. 142 sector : CARDINAL;
  150. 143 filebyte : CARDINAL;
  151. 144 flags : SegSet;
  152. 145 membyte : CARDINAL;
  153. 146 END; (*SegRec*)
  154. 147 ModStage = (initial_stage,internal_stage,sub_module_stage,execute_stage);
  155. 148 EntryRec = RECORD
  156. 149 seg : SHORTCARD;
  157. 150 ofs : CARDINAL;
  158. 151 END; (*EntryRec*)
  159. 152 Module = POINTER TO ModuleRec;
  160. 153 ModuleRec = RECORD
  161. 154 file : CARDINAL;
  162. 155 seg_count : CARDINAL;
  163. 156 log_sector_size : CARDINAL;
  164. 157 stage : ModStage;
  165. 158 is_exe : BOOLEAN;
  166. 159 name : POINTER TO ARRAY[0..MaxName] OF CHAR;
  167. 160 seg_info : POINTER TO ARRAY[1..MaxSeg] OF SegRec;
  168. 161 entry_table: POINTER TO ARRAY[1..MaxEntry] OF EntryRec;
  169. 162 module_table:POINTER TO ARRAY[1..MaxModule] OF SHORTCARD;
  170. 163 END; (*ModuleRec*)
  171. 164 (*# data(near_ptr=>off) *)
  172. 165 LoadState = RECORD
  173. 166 (*%T Debuging*)
  174. 167 trap_seg : SegNum; (* for debugging *)
  175. 168 trap_mod : ModNum; (* for debugging *)
  176. 169 trap_off : CARDINAL; (* for debugging *)
  177. 170 trap_alloc : CARDINAL;
  178. 171 (*%E*)
  179. 172 (*%T MemoryTrace*) (* don't trace internal operations *)
  180. 173 internal : BOOLEAN;
  181. 174 (*%E*)
  182. 175 psp : CARDINAL;
  183. 176 stk : CARDINAL;
  184. 177 module_count:CARDINAL;
  185. 178 abort : ExitHandler;
  186. 179 OutOfMem : MemHandler;
  187. 180 file_count : INTEGER;
  188. 181 near_alloc : CARDINAL;
  189. 182 start : CARDINAL; (* start of memory *)
  190. 183 end : CARDINAL; (* last para of normal (not ems) memory *)
  191. 184 freemem : CARDINAL;
  192. 185 allockind : SegKind;
  193. 186 panic_reserve:CARDINAL;
  194. 187 temp_file : CARDINAL;
  195. 188 temp_reserve:LONGINT;
  196. 189 temp_ems : CARDINAL; (* number of temp pages mapped into ems *)
  197. 190 temp_map : ARRAY [0..TempLimit DIV (8*SIZE(BITSET)*TempPageSize)] OF BITSET;
  198. 191 (*%T ExitTrace *)
  199. 192 temp_max : CARDINAL;
  200. 193 (*%E*)
  201. 194 (*%T MoveTrace *)
  202. 195 move_total : LONGCARD;
  203. 196 (*%E*)
  204. 197 ems_frame : CARDINAL;
  205. 198 (*%T EMS*)
  206. 199 ems_present: BOOLEAN;
  207. 200 ems_count : CARDINAL;
  208. 201 ems_temp_handle:CARDINAL;
  209. 202 ems_data_handle:CARDINAL;
  210. 203 (*%E*)
  211. 204 module_list: ARRAY ModNum OF Module;
  212. 205 delay : ModNum;
  213. 206 gate_count : CARDINAL;
  214. 207 gate_table : ARRAY [1..MaxGate] OF GateRec;
  215. 208 (*%T VidSupport*)
  216. 209 vid_present: BOOLEAN;
  217. 210 vid_delayed: BOOLEAN;
  218. 211 vid_id1,
  219. 212 vid_id2 : CARDINAL;
  220. 213 (*%E*)
  221. 214 heap : ARRAY [1..HeapSize] OF SHORTCARD;
  222. 215 Tick : CARDINAL;
  223. 216 END; (*LoadState*)
  224. 217
  225. 218 TYPE A1 = SHORTCARD;
  226. 219 TYPE A2 = ARRAY [1..2] OF SHORTCARD;
  227. 220 TYPE A4 = ARRAY [1..4] OF SHORTCARD;
  228. 221 TYPE A6 = ARRAY [1..6] OF SHORTCARD;
  229. 222 TYPE A7 = ARRAY [1..7] OF SHORTCARD;
  230. 223 TYPE A8 = ARRAY [1..8] OF SHORTCARD;
  231. 224 TYPE A9 = ARRAY [1..9] OF SHORTCARD;
  232. 225 TYPE A12= ARRAY [1..12] OF SHORTCARD;
  233. 226 TYPE A13= ARRAY [1..13] OF SHORTCARD;
  234. 227
  235. 228
  236. 229
  237. 230 TYPE
  238. 231 HandlerRec = RECORD
  239. 232 b01,b02,b03,b04:SHORTCARD;
  240. 233 OffsetShift:SHORTCARD;
  241. 234 b11,b12,b13,b14,b15,b16,b17:SHORTCARD;
  242. 235 PageDisp:CARDINAL;
  243. 236 b21,b22,b23,b24:SHORTCARD;
  244. 237 MemStart:CARDINAL;
  245. 238 b25,b26,b27,b28:SHORTCARD;
  246. 239 MemEnd:CARDINAL;
  247. 240 b29,b30,b31,b32:SHORTCARD;
  248. 241 EmsStart:CARDINAL;
  249. 242 b33,b34,b35,b36:SHORTCARD;
  250. 243 EmsEnd:CARDINAL;
  251. 244 b37:A8;b38:CARDINAL; b39:A4; b40:CARDINAL; b41:A12;
  252. 245 OffsetMask:BITSET;
  253. 246 b42:SHORTCARD;
  254. 247 BlankShift:SHORTCARD;
  255. 248 b5:A13;
  256. 249 QFix:ADDRESS;
  257. 250 b61,b62,b63:SHORTCARD;
  258. 251 END;
  259. 252
  260. 253 CONST
  261. 254 MaxPage = 1024;
  262. 255
  263. 256
  264. 257 TYPE
  265. 258 WP = POINTER TO CARDINAL;
  266. 259 ParaRec = RECORD
  267. 260 Size : CARDINAL; (* Size in paragraphs of alloc *)
  268. 261 Used : CARDINAL; (* Paragraphs currently in use *)
  269. 262 Prev : CARDINAL; (* Previous ParaRec Segment *)
  270. 263 Active : BOOLEAN;
  271. 264 Kind : SegKind; (* Kind of segment *)
  272. 265 Id1,Id2 : CARDINAL;
  273. 266 Lock : CARDINAL; (* Segment Locked in memory *)
  274. 267 Tick : CARDINAL; (* LRU Tick Count *)
  275. 268 END; (*ParaRec*)
  276. 269 T = POINTER TO ParaRec;
  277. 270
  278. 271 CONST H = (SIZE(ParaRec)+15) DIV 16; (* overhead in paragraphs *)
  279. 272
  280. 273
  281. 274 CONST loader_name = 'LOADER';
  282. 275
  283. 276 TYPE t_loader_hdr = ARRAY [1..1] OF SegRec;
  284. 277 CONST loader_hdr = t_loader_hdr(
  285. 278 SegRec(90H, 0E9H, 0, 0, GatePtr(0), 0, 0, 0, SegSet{IsPreLoad}, 0)
  286. 279 );
  287. 280
  288. 281 Entries = 34;
  289. 282
  290. 283 TYPE t_loader_entry = ARRAY [1..Entries] OF EntryRec;
  291. 284 (* N.B. this has to be consistent with loader.exp *)
  292. 285 CONST loader_entry = t_loader_entry (
  293. 286 EntryRec(1,Ofs(LoadModule)),
  294. 287 EntryRec(1,Ofs(UnLoadModule)),
  295. 288 EntryRec(1,Ofs(GetProcAddr)),
  296. 289 EntryRec(1,Ofs(ShrinkHeap)),
  297. 290 EntryRec(1,Ofs(GrowHeap)),
  298. 291 EntryRec(1,Ofs(UserFlush)),
  299. 292 EntryRec(1,Ofs(InvalidProc)),
  300. 293 EntryRec(1,Ofs(InvalidProc)),
  301. 294 EntryRec(1,Ofs(AllocMem)),
  302. 295 EntryRec(1,Ofs(ClearAllocMem)),
  303. 296 EntryRec(1,Ofs(HugeAllocMem)),
  304. 297 EntryRec(1,Ofs(FreeMem)),
  305. 298 EntryRec(1,Ofs(SetExitHandler)),
  306. 299 EntryRec(1,Ofs(SetMemHandler)),
  307. 300 EntryRec(1,Ofs(InvalidProc)),
  308. 301 EntryRec(1,Ofs(LoadSeg)),
  309. 302 EntryRec(1,Ofs(UnloadSeg)),
  310. 303 EntryRec(1,Ofs(Terminate)),
  311. 304 EntryRec(1,Ofs(InvalidProc)),
  312. 305 EntryRec(1,Ofs(RetGate)),
  313. 306 EntryRec(1,Ofs(Avail)),
  314. 307 EntryRec(1,Ofs(TotalAvail)),
  315. 308 EntryRec(1,Ofs(SetEms)),
  316. 309 EntryRec(1,Ofs(Getseg)),
  317. 310 EntryRec(1,Ofs(ExpandMem)),
  318. 311 EntryRec(1,Ofs(HugeExpandMem)),
  319. 312 EntryRec(1,Ofs(HeapWalk)),
  320. 313 EntryRec(1,Ofs(HeapCheck)),
  321. 314 EntryRec(1,Ofs(GetOrdProcAddr)),
  322. 315 EntryRec(1,Ofs(VAlloc)),
  323. 316 EntryRec(1,Ofs(VUnfix)),
  324. 317 EntryRec(1,Ofs(VFix)),
  325. 318 EntryRec(1,Ofs(VUnfixAll)),
  326. 319 EntryRec(1,Ofs(VFree))
  327. 320 );
  328. 321
  329. 322 VAR g:LoadState;
  330. 323
  331. 324 CONST loader_module = ModuleRec (
  332. 325 MAX(CARDINAL),
  333. 326 2,
  334. 327 0,
  335. 328 execute_stage,
  336. 329 FALSE, (* not exe *)
  337. 330 HeapADDR(HeapAdr(loader_name)),
  338. 331 HeapADDR(HeapAdr(loader_hdr)),
  339. 332 HeapADDR(HeapAdr(loader_entry)),
  340. 333 HeapADDR(0)
  341. 334 );
  342. 335
  343. 336
  344. 337
  345. 338 (*-----------------------------------------------------------------------*)
  346. 339 (* inline functions *)
  347. 340 (*-----------------------------------------------------------------------*)
  348. 341 (*# save, call(inline=>on, same_ds=>off) *)
  349. 342 (*# call(reg_saved=>(bx,cx,dx,si,di,ds,es,st1,st2)) *)
  350. 343 INLINE PROCEDURE GetBP():CARDINAL = A2(89H, 0E8H); (* mov ax,bp *)
  351. 344 INLINE PROCEDURE GetSP():CARDINAL = A2(89H, 0E0H); (* mov ax,sp *)
  352. 345 INLINE PROCEDURE Int3() = A1(0CCH);
  353. 346 INLINE PROCEDURE Int66() = A2(0CDH,066H); (* used to enter symdeb *)
  354. 347 (*# call(reg_param=>(si,ax,di,es,cx), reg_saved=>(bx,dx,ds,st1,st2)) *)
  355. 348 INLINE PROCEDURE Move(fr,to : ADDRESS; count : CARDINAL)=
  356. 349 A12(1EH,8EH,0D8H,0D1H,0E9H,0F3H,0A5H,013H,0C9H,0F3H,0A4H,1FH);
  357. 350 (* push ds; mov ds,ax; shr cx,1; rep; movsw; adc cx,cx; rep; movsb; pop ds *)
  358. 351 (*# call(reg_param=>(di,es,cx,ax), reg_saved=>(bx,dx,si,ds,st1,st2)) *)
  359. 352 INLINE PROCEDURE Fill(a:ADDRESS;count:CARDINAL;w:CARDINAL) = A7(0D1H,0E9H,0F3H,0ABH,073H,001H,0AAH);
  360. 353 (*# call(reg_param=>(dx,si,ax)) *)
  361. 354 INLINE PROCEDURE GetCurDir (drive : SHORTCARD;VAR p : ARRAY OF CHAR) =
  362. 355 A8(1EH, 8EH,0D8H, 0B4H,47H, 0CDH,21H, 1FH);
  363. 356 (* push ds; mov ds,ax; mov ah,47H; int 21H; pop ds *)
  364. 357 (*# call(reg_return=>(ax)) *)
  365. 358 INLINE PROCEDURE GetCurDrive():SHORTCARD = A4(0B4H,19H, 0CDH,21H); (* mov ah, 19H; int 21H *)
  366. 359 (*%T EMS*)
  367. 360 (* Ems support *)
  368. 361 (*# call(reg_param=>(ax,bx,dx), reg_saved =>(si,di,ds,st1,st2)) *)
  369. 362 INLINE PROCEDURE EmsTest(ax:CARDINAL):CARDINAL = A2(0CDH,67H);
  370. 363 INLINE PROCEDURE EmsMap(ax:CARDINAL;bx:CARDINAL;dx:CARDINAL) = A2(0CDH,67H);
  371. 364 (*# call(reg_return=>(bx)) *)
  372. 365 INLINE PROCEDURE EmsGet(ax:CARDINAL):CARDINAL = A2(0CDH,67H);
  373. 366 (*# call(reg_return=>(dx)) *)
  374. 367 INLINE PROCEDURE EmsAlloc(ax:CARDINAL;bx:CARDINAL):CARDINAL = A2(0CDH,67H);
  375. 368 (*%E*)
  376. 369 (*# call(reg_param=>(dx,ax)) *)
  377. 370 INLINE PROCEDURE Out (p:CARDINAL;v:SHORTCARD)=SHORTCARD(0EEH);
  378. 371 INLINE PROCEDURE DI()=SHORTCARD(0FAH);
  379. 372 INLINE PROCEDURE EI()=SHORTCARD(0FBH);
  380. 373 (*# restore *)
  381. 374 INLINE PROCEDURE GetTick():CARDINAL;
  382. 375 BEGIN
  383. 376 RETURN g.Tick;
  384. 377 END GetTick;
  385. 378 INLINE PROCEDURE IncTick():CARDINAL;
  386. 379 BEGIN
  387. 380 INC(g.Tick);
  388. 381 RETURN g.Tick;
  389. 382 END IncTick;
  390. 383
  391. 384
  392. 385
  393. 386 (* tracing *)
  394. 387
  395. 388 (*%T TraceToFile*) VAR output_file : CARDINAL; (*%E*)
  396. 389 (*%F TraceToFile*) CONST output_file = 1; (*%E*)
  397. 390
  398. 391 PROCEDURE string(s: ARRAY OF CHAR);
  399. 392 VAR i:CARDINAL;
  400. 393 BEGIN
  401. 394 i := 0;
  402. 395 WHILE s[i]#0C DO
  403. 396 INC(i);
  404. 397 END;
  405. 398 i := FileWrite(ADR(s), i, output_file);
  406. 399 END string;
  407. 400
  408. 401 PROCEDURE eol;
  409. 402 CONST CRLF = CHAR(13) + CHAR(10);
  410. 403 VAR i:CARDINAL;
  411. 404 p:LONGCARD;
  412. 405 BEGIN
  413. 406 i := FileWrite(ADR(CRLF), 2, output_file);
  414. 407 END eol;
  415. 408
  416. 409 PROCEDURE char(c: CHAR);
  417. 410 VAR i:CARDINAL;
  418. 411 BEGIN
  419. 412 i := FileWrite(ADR(c), 1, output_file);
  420. 413 END char;
  421. 414
  422. 415 PROCEDURE hex(n: CARDINAL);
  423. 416 CONST dig = '0123456789ABCDEF';
  424. 417 VAR buf:ARRAY [0..3] OF CHAR;
  425. 418 i:CARDINAL;
  426. 419 BEGIN
  427. 420 FOR i := 0 TO 3 DO
  428. 421 buf[3-i] := dig[n MOD 16];
  429. 422 n := n DIV 16;
  430. 423 END;
  431. 424 i := FileWrite(ADR(buf), 4, output_file);
  432. 425 END hex;
  433. 426
  434. 427 PROCEDURE dec(n: CARDINAL);
  435. 428 VAR div:CARDINAL;
  436. 429 BEGIN
  437. 430 div := n DIV 10;
  438. 431 IF div#0 THEN
  439. 432 dec(div);
  440. 433 END;
  441. 434 char('0' + CHAR(n MOD 10));
  442. 435 END dec;
  443. 436
  444. 437 (*%T GraphUseTrace*)
  445. 438 TYPE graphsegrec = RECORD
  446. 439 seg : CARDINAL;
  447. 440 pos : CARDINAL;
  448. 441 lasttick : CARDINAL;
  449. 442 END;
  450. 443 VAR graphsegs : ARRAY[1..300] OF graphsegrec;
  451. 444 TYPE GTmode = (GTadd,GTdel,GTlru);
  452. 445 PROCEDURE GraphTrace(seg : CARDINAL;
  453. 446 pos : CARDINAL;
  454. 447 mode : GTmode);
  455. 448 VAR i,j,s,segm : CARDINAL;
  456. 449 c : CHAR;
  457. 450
  458. 451 BEGIN
  459. 452 (* IF NOT(4 IN BITSET([40H:17H T]^)) THEN RETURN END; *)
  460. 453 hex([40H:6CH]^);
  461. 454 char(' ');
  462. 455 CASE mode OF
  463. 456 |GTadd: char('¯');
  464. 457 |GTdel: char('®');
  465. 458 |GTlru: char(' ');
  466. 459 END;
  467. 460 IF mode=GTlru THEN string('flush ');hex(pos);
  468. 461 ELSE
  469. 462 char(' ');
  470. 463 hex(seg);
  471. 464 char(' ');hex([pos-1:0 T]^.Used);
  472. 465 END;
  473. 466 char(' ');
  474. 467 j := HIGH(graphsegs);
  475. 468 WHILE (j>0)AND(graphsegs[j].seg=0)DO DEC(j); END;
  476. 469 IF j<HIGH(graphsegs) THEN INC(j); END;
  477. 470 FOR i := 1 TO j DO
  478. 471 s := graphsegs[i].seg;
  479. 472 IF (s=0)OR((s=seg)AND(mode=GTadd)) THEN
  480. 473 IF mode=GTadd THEN
  481. 474 graphsegs[i].seg := seg;
  482. 475 graphsegs[i].pos := pos;
  483. 476 graphsegs[i].lasttick := [pos-1:0 T]^.Tick;
  484. 477 c := '¸';
  485. 478 mode := GTlru;
  486. 479 ELSE
  487. 480 c := ' ';
  488. 481 END;
  489. 482 ELSIF (s=seg)AND(mode=GTdel) THEN
  490. 483 c := '¾';
  491. 484 graphsegs[i].pos := 0;
  492. 485 ELSE
  493. 486 IF graphsegs[i].pos=0 THEN
  494. 487 c := ' ';
  495. 488 ELSE
  496. 489 segm := SegPtr(HeapAdr(g.module_list[s DIV 256]^.seg_info^[s MOD 256]))^.seg_val;
  497. 490 IF graphsegs[i].pos<>segm THEN
  498. 491 graphsegs[i].pos := segm;
  499. 492 c := 'Æ';
  500. 493 ELSIF graphsegs[i].lasttick <> [graphsegs[i].pos-1:0 T]^.Tick THEN
  501. 494 graphsegs[i].lasttick := [graphsegs[i].pos-1:0 T]^.Tick;
  502. 495 c := 'Ã';
  503. 496 ELSE
  504. 497 c := '³';
  505. 498 END;
  506. 499 END;
  507. 500 END;
  508. 501 char(c);
  509. 502 END;
  510. 503 eol;
  511. 504 END GraphTrace;
  512. 505 (*%E*)
  513. 506
  514. 507
  515. 508 PROCEDURE DumpMemory; FORWARD;
  516. 509 PROCEDURE DumpSegName(seg:CARDINAL);FORWARD;
  517. 510
  518. 511 PROCEDURE release_panic; FORWARD;
  519. 512 (*#save,call(reg_param=>())*)
  520. 513 PROCEDURE abort(errno:SHORTCARD);
  521. 514 (*#restore*)
  522. 515
  523. 516 TYPE
  524. 517 fp = POINTER Seg(errno) TO RECORD
  525. 518 bp,ip,cs: CARDINAL;
  526. 519 END; (*fp*)
  527. 520 VAR
  528. 521 bp : fp;
  529. 522 cs,i : CARDINAL;
  530. 523 res : BOOLEAN;
  531. 524 BEGIN
  532. 525 (*%T TraceToFile*)
  533. 526 DumpMemory;
  534. 527 (*%E*)
  535. 528 release_panic;
  536. 529 (*%T CHECK*)
  537. 530 eol;
  538. 531 bp := fp(GetBP());
  539. 532 i := 0;
  540. 533 LOOP
  541. 534 IF (bp = fp(0))OR(i=10) THEN EXIT END;
  542. 535 INC(i);
  543. 536 hex(CARDINAL(bp));string(' ');hex(bp^.ip);string(' ');DumpSegName(bp^.cs);eol;
  544. 537 IF (bp^.bp=0) THEN
  545. 538 EXIT;
  546. 539 ELSIF bp^.bp <= CARDINAL(bp) THEN
  547. 540 EXIT
  548. 541 END; (*IF*)
  549. 542 bp := fp(bp^.bp);
  550. 543 END;
  551. 544 (*%E*)
  552. 545 g.abort(g.module_list[1]^.name^,ErrBase+CARDINAL(errno));
  553. 546 Terminate;
  554. 547 DosExit;
  555. 548 END abort;
  556. 549
  557. 550 PROCEDURE is_mem(seg:CARDINAL):BOOLEAN;
  558. 551 BEGIN
  559. 552 RETURN ((seg >= g.start) & (seg < g.end))
  560. 553 (*%T EMS*)
  561. 554 OR ((seg >= g.ems_frame) & (seg < g.ems_frame + 1000H))
  562. 555 (*%E*)
  563. 556 ;
  564. 557 END is_mem;
  565. 558
  566. 559 PROCEDURE encode_temp(i:CARDINAL):CARDINAL;
  567. 560 BEGIN
  568. 561 IF g.ems_frame < g.start THEN
  569. 562 IF i >= g.ems_frame THEN
  570. 563 INC(i, 1000H);
  571. 564 END;
  572. 565 END;
  573. 566 IF i >= g.start THEN
  574. 567 INC(i, g.end - g.start);
  575. 568 END;
  576. 569 IF g.ems_frame > g.start THEN
  577. 570 IF i >= g.ems_frame THEN
  578. 571 INC(i, 1000H);
  579. 572 END;
  580. 573 END;
  581. 574 (*%T CHECK*) IF (i=0) OR is_mem(i) THEN abort(ErrTempFileLimit) END; (*%E*)
  582. 575 RETURN i;
  583. 576 END encode_temp;
  584. 577
  585. 578 PROCEDURE decode_temp(i:CARDINAL):CARDINAL;
  586. 579 BEGIN
  587. 580 IF g.ems_frame > g.start THEN
  588. 581 IF i >= g.ems_frame THEN
  589. 582 DEC(i,1000H);
  590. 583 END;
  591. 584 END;
  592. 585 IF i >= g.start THEN
  593. 586 DEC(i, g.end - g.start);
  594. 587 END;
  595. 588 IF g.ems_frame < g.start THEN
  596. 589 IF i >= g.ems_frame THEN
  597. 590 DEC(i, 1000H);
  598. 591 END;
  599. 592 END;
  600. 593 RETURN i;
  601. 594 END decode_temp;
  602. 595
  603. 596 (*%T CHECK *)
  604. 597 PROCEDURE CheckAlloc(seg:CARDINAL;err : CARDINAL);
  605. 598 (* checks that block is a valid allocated segment *)
  606. 599 BEGIN
  607. 600 DEC(seg, H);
  608. 601 WITH [seg:0 T]^ DO
  609. 602 IF (seg < g.start) OR
  610. 603 (Kind > MAX(SegKind)) OR
  611. 604 (Used > Size) OR
  612. 605 (Prev + [Prev:0 T]^.Size # seg) OR
  613. 606 ([seg+Size:0 T]^.Prev # seg) THEN
  614. 607 IF err=0 THEN
  615. 608 abort(ErrMemoryCorruption);
  616. 609 ELSE
  617. 610 abort(SHORTCARD(err));
  618. 611 END;
  619. 612 END; (*IF*)
  620. 613 END; (*WITH*)
  621. 614 END CheckAlloc;
  622. 615
  623. 616 PROCEDURE CalcFreeMem():CARDINAL;
  624. 617 VAR
  625. 618 res,p : CARDINAL;
  626. 619 BEGIN
  627. 620 res := 0;
  628. 621 p := g.start;
  629. 622 REPEAT
  630. 623 WITH [p:0 T]^ DO
  631. 624 INC(res,Size - Used);
  632. 625 INC(p,Size);
  633. 626 END; (*WITH*)
  634. 627 UNTIL p = g.start;
  635. 628 RETURN res;
  636. 629 END CalcFreeMem;
  637. 630
  638. 631 PROCEDURE CheckMem;
  639. 632 VAR
  640. 633 p : CARDINAL;
  641. 634 BEGIN
  642. 635 p := g.start;
  643. 636 REPEAT
  644. 637 CheckAlloc(p+H,0);
  645. 638 INC(p,[p:0 T]^.Size);
  646. 639 UNTIL p = g.start;
  647. 640 IF CalcFreeMem() # g.freemem THEN
  648. 641 abort(ErrInternal);
  649. 642 END; (*IF*)
  650. 643 END CheckMem;
  651. 644
  652. 645 (*%E*)
  653. 646
  654. 647 (*%F CHECK*) INLINE (*%E*) PROCEDURE Locked(w:CARDINAL):BOOLEAN;
  655. 648 BEGIN
  656. 649 RETURN ([w-H:0 T]^.Lock # 0);
  657. 650 END Locked;
  658. 651
  659. 652 PROCEDURE SwapMove(VAR seg:CARDINAL);
  660. 653 BEGIN
  661. 654 IF is_mem(seg) THEN
  662. 655 (*%T CHECK*)
  663. 656 CheckAlloc(seg,0);
  664. 657 (*%E*)
  665. 658 WITH [seg-H:0 T]^ DO
  666. 659 (*%T CHECK*)
  667. 660 IF Kind # MoveSeg THEN
  668. 661 abort(ErrInternal);
  669. 662 END;
  670. 663 (*%E*)
  671. 664 Kind := SwapSeg;
  672. 665 Tick := IncTick();
  673. 666 END; (*WITH*)
  674. 667 END; (*IF*)
  675. 668 END SwapMove;
  676. 669
  677. 670 PROCEDURE DumpLockedStatics;
  678. 671 VAR
  679. 672 modnum:ModNum;
  680. 673 segnum:SegNum;
  681. 674 module:Module;
  682. 675 segment:CARDINAL;
  683. 676 BEGIN
  684. 677 string('Locked static segments '); eol;
  685. 678 FOR modnum := 1 TO g.module_count DO
  686. 679 module := g.module_list[modnum];
  687. 680 string(module^.name^);
  688. 681 string(' : ');
  689. 682 FOR segnum := 1 TO module^.seg_count DO
  690. 683 segment := module^.seg_info^[segnum].seg_val;
  691. 684 IF is_mem(segment) THEN
  692. 685 WITH [segment-H:0 T]^ DO
  693. 686 IF Lock<>0 THEN
  694. 687 dec(segnum);
  695. 688 char('(');
  696. 689 dec(Lock);
  697. 690 char(')');
  698. 691 char(' ');
  699. 692 END
  700. 693 END;
  701. 694 END;
  702. 695 END;
  703. 696 eol;
  704. 697 END;
  705. 698 END DumpLockedStatics;
  706. 699
  707. 700 PROCEDURE DumpSegKind(kind:SegKind);
  708. 701 BEGIN
  709. 702 CASE kind OF
  710. 703 | StaticSeg: string('sta');
  711. 704 | SwapSeg: string('swa');
  712. 705 | MoveSeg: string('mov');
  713. 706 | FixedSeg: string('fix');
  714. 707 | SystemSeg: string('sys');
  715. 708 END;
  716. 709 END DumpSegKind;
  717. 710
  718. 711 PROCEDURE DumpSegName(seg:CARDINAL);
  719. 712 BEGIN
  720. 713 WITH [seg-H:0 T]^ DO
  721. 714 CASE Kind OF
  722. 715 | StaticSeg:
  723. 716 string(g.module_list[Id1]^.name^);
  724. 717 char('.');
  725. 718 hex(Id2);
  726. 719 | SwapSeg:
  727. 720 DumpSegName(Id2); char(':'); hex(Id1);
  728. 721 | MoveSeg:
  729. 722 DumpSegName(Id2); char(':'); hex(Id1);
  730. 723 ELSE
  731. 724 hex(seg);
  732. 725 END;
  733. 726 END;
  734. 727 END DumpSegName;
  735. 728
  736. 729 PROCEDURE DumpSeg(s:ARRAY OF CHAR;seg:CARDINAL);
  737. 730 BEGIN
  738. 731 string(s);
  739. 732 WITH [seg-H:0 T]^ DO
  740. 733 hex(seg);
  741. 734 (*string(' Size='); hex(Size);*)
  742. 735 string(' Used='); hex(Used);
  743. 736 (*string(' Prev='); hex(Prev);*)
  744. 737 string(' Free='); hex(Size-Used);
  745. 738 string(' Kind=');
  746. 739 DumpSegKind(Kind);
  747. 740 string(' Lock='); dec(Lock);
  748. 741 string(' Name='); DumpSegName(seg);
  749. 742 CASE Kind OF
  750. 743 | MoveSeg, SwapSeg, StaticSeg: string(' Age='); dec(GetTick()-Tick);
  751. 744 END;
  752. 745 eol;
  753. 746 END;
  754. 747 END DumpSeg;
  755. 748
  756. 749 PROCEDURE TraceSeg(s:ARRAY OF CHAR; seg:CARDINAL);
  757. 750 BEGIN
  758. 751 hex(g.freemem);
  759. 752 char(' ');
  760. 753 hex(seg);
  761. 754 char(' ');
  762. 755 string(s);
  763. 756 WITH [seg-H:0 T]^ DO
  764. 757 string(' Size='); hex(Used);
  765. 758 string(' Kind=');
  766. 759 DumpSegKind(Kind);
  767. 760 CASE Kind OF
  768. 761 | MoveSeg, SwapSeg, StaticSeg: string(' Name='); DumpSegName(seg);
  769. 762 IF GetTick()#Tick THEN
  770. 763 string(' Age='); dec(GetTick()-Tick);
  771. 764 END;
  772. 765 END;
  773. 766 eol;
  774. 767 END;
  775. 768 END TraceSeg;
  776. 769
  777. 770 (* splits free space of block p, returning lower half *)
  778. 771 PROCEDURE SplitLow(size:CARDINAL; p:CARDINAL):CARDINAL;
  779. 772 VAR
  780. 773 res : CARDINAL;
  781. 774 free : CARDINAL;
  782. 775 BEGIN
  783. 776 WITH [p:0 T]^ DO
  784. 777 res := p + Used;
  785. 778 free := Size - Used;
  786. 779 Size := Used;
  787. 780 END; (*WITH*)
  788. 781 WITH [res:0 T]^ DO
  789. 782 IF p # res THEN
  790. 783 Prev := p;
  791. 784 END; (*IF*)
  792. 785 Size := free;
  793. 786 Used := size;
  794. 787 END; (*WITH*)
  795. 788 WITH [res+free:0 T]^ DO
  796. 789 Prev := res;
  797. 790 END; (*WITH*)
  798. 791 DEC(g.freemem,size);
  799. 792 RETURN res;
  800. 793 END SplitLow;
  801. 794
  802. 795 (* Trys to find a block with with free space >= size, begin search at *)
  803. 796 (* s, end at e. *)
  804. 797 PROCEDURE Try(size:CARDINAL; s,e:CARDINAL):CARDINAL;
  805. 798 VAR
  806. 799 p,res : CARDINAL;
  807. 800 BEGIN
  808. 801 IF size = 0 THEN
  809. 802 RETURN 0;
  810. 803 END; (*IF*)
  811. 804 p := s;
  812. 805 LOOP
  813. 806 WITH [p:0 T]^ DO
  814. 807 IF Size - Used >= size THEN
  815. 808 RETURN p;
  816. 809 END; (*IF*)
  817. 810 INC(p,Size);
  818. 811 IF p = e THEN
  819. 812 RETURN 0;
  820. 813 END; (*IF*)
  821. 814 END; (*WITH*)
  822. 815 END; (*LOOP*)
  823. 816 END Try;
  824. 817
  825. 818 (* An area is a sequence of blocks satisfying ~Locked except for the *)
  826. 819 (* first block. *)
  827. 820
  828. 821 (* Returns size of possible free space in area starting at s..e, *)
  829. 822 (* assuming blocks of size < req can be evacuated *)
  830. 823 PROCEDURE Poss(s,e:CARDINAL; req:CARDINAL):CARDINAL;
  831. 824 VAR
  832. 825 res : CARDINAL;
  833. 826 BEGIN
  834. 827 WITH [s:0 T]^ DO
  835. 828 IF Active THEN
  836. 829 RETURN 0;
  837. 830 END; (*IF*)
  838. 831 res := Size - Used;
  839. 832 INC(s,Size);
  840. 833 END; (*WITH*)
  841. 834 WHILE s # e DO
  842. 835 WITH [s:0 T]^ DO
  843. 836 INC(res,Size);
  844. 837 IF Size >= req THEN
  845. 838 DEC(res,Used);
  846. 839 END; (*IF*)
  847. 840 INC(s,Size);
  848. 841 END; (*WITH*)
  849. 842 END; (*WHILE*)
  850. 843 RETURN res;
  851. 844 END Poss;
  852. 845
  853. 846 (* Returns amount of free space in area s..e. *)
  854. 847 PROCEDURE Got(s,e:CARDINAL):CARDINAL;
  855. 848 VAR
  856. 849 res : CARDINAL;
  857. 850 BEGIN
  858. 851 res := 0;
  859. 852 WHILE s # e DO
  860. 853 WITH [s:0 T]^ DO
  861. 854 INC(res,Size);
  862. 855 DEC(res,Used);
  863. 856 INC(s,Size);
  864. 857 END; (*WITH*)
  865. 858 END; (*WHILE*)
  866. 859 RETURN res;
  867. 860 END Got;
  868. 861
  869. 862 PROCEDURE NextArea(r:CARDINAL):CARDINAL;
  870. 863 BEGIN
  871. 864 INC(r,[r:0 T]^.Size);
  872. 865 LOOP
  873. 866 WITH [r:0 T]^ DO
  874. 867 IF Lock<>0 THEN
  875. 868 RETURN r;
  876. 869 END; (*IF*)
  877. 870 INC(r,Size);
  878. 871 END; (*WITH*)
  879. 872 END; (*LOOP*)
  880. 873 END NextArea;
  881. 874
  882. 875 (* Find area containing r *)
  883. 876 PROCEDURE Find(r:CARDINAL):CARDINAL;
  884. 877 BEGIN
  885. 878 WHILE [r:0 T]^.Lock=0 DO
  886. 879 r := [r:0 T]^.Prev;
  887. 880 END; (*WHILE*)
  888. 881 RETURN r;
  889. 882 END Find;
  890. 883
  891. 884 (* Returns largest Poss(s,e,req) less than bound over all areas s..e *)
  892. 885 PROCEDURE MaxPoss(req:CARDINAL; VAR sm,em:CARDINAL):CARDINAL;
  893. 886 VAR
  894. 887 s,e : CARDINAL;
  895. 888 max,try : CARDINAL;
  896. 889 BEGIN
  897. 890 s := g.start;
  898. 891 max := 0;
  899. 892 REPEAT
  900. 893 e := NextArea(s); (*<<<*)
  901. 894 try := Poss(s,e,req); (*<<<*)
  902. 895 IF (try > max) THEN
  903. 896 sm := s;
  904. 897 em := e;
  905. 898 max := try;
  906. 899 END; (*IF*)
  907. 900 s := e;
  908. 901 UNTIL s = g.start;
  909. 902 RETURN max;
  910. 903 END MaxPoss;
  911. 904
  912. 905 CONST
  913. 906 (*%T DEBUG*)
  914. 907 Hide = 10H;
  915. 908 (*%E*)
  916. 909 (*%F DEBUG*)
  917. 910 Hide = 200H;
  918. 911 (*%E*)
  919. 912
  920. 913 (* Returns largest Got(s,e) over all areas s..e *)
  921. 914 PROCEDURE Avail():CARDINAL;
  922. 915 VAR
  923. 916 s,e : CARDINAL;
  924. 917 max,try : CARDINAL;
  925. 918 BEGIN
  926. 919 g.allockind := FixedSeg;
  927. 920 s := g.start;
  928. 921 max := 0;
  929. 922 REPEAT
  930. 923 e := NextArea(s); (*<<<*)
  931. 924 try := Got(s,e); (*<<<*)
  932. 925 IF (try > max) THEN
  933. 926 max := try;
  934. 927 END; (*IF*)
  935. 928 s := e;
  936. 929 UNTIL s = g.start;
  937. 930 IF max<Hide+2 THEN RETURN 0 END;
  938. 931 RETURN max-Hide-2;
  939. 932 END Avail;
  940. 933
  941. 934 PROCEDURE MemPic;
  942. 935 VAR
  943. 936 tmp:CARDINAL;
  944. 937 used:CARDINAL;
  945. 938 lock:BOOLEAN;
  946. 939 BEGIN
  947. 940 string('MemPic=');
  948. 941 tmp := g.start;
  949. 942 used := 0;
  950. 943 lock := FALSE;
  951. 944 REPEAT
  952. 945 WITH [tmp:0 T]^ DO
  953. 946 IF Lock # 0 THEN
  954. 947 lock := TRUE;
  955. 948 END;
  956. 949 INC(used, Used);
  957. 950 IF Size > Used THEN
  958. 951 IF lock THEN
  959. 952 char('+');
  960. 953 ELSE
  961. 954 char('.');
  962. 955 END;
  963. 956 dec(used);
  964. 957 char('_');
  965. 958 dec(Size-Used);
  966. 959 used := 0;
  967. 960 lock := FALSE;
  968. 961 END;
  969. 962 tmp := tmp + Size;
  970. 963 END;
  971. 964 UNTIL tmp = g.start;
  972. 965 eol;
  973. 966 END MemPic;
  974. 967
  975. 968 PROCEDURE MemStat;
  976. 969 VAR
  977. 970 kind : SegKind;
  978. 971 ucount,tcount,
  979. 972 usize,tsize : ARRAY SegKind OF CARDINAL;
  980. 973 dummy : CARDINAL;
  981. 974 tmp : CARDINAL;
  982. 975
  983. 976 TDummy : T;
  984. 977 BEGIN
  985. 978 FOR kind := MIN(SegKind) TO MAX(SegKind) DO
  986. 979 tcount[kind] := 0;
  987. 980 ucount[kind] := 0;
  988. 981 tsize[kind] := 0;
  989. 982 usize[kind] := 0;
  990. 983 END; (*FOR*)
  991. 984 tmp := g.start;
  992. 985 REPEAT
  993. 986 WITH [tmp:0 T]^ DO
  994. 987 TDummy := [tmp:0 T];
  995. 988 INC(tsize[Kind],Used);
  996. 989 INC(tcount[Kind]);
  997. 990 IF Lock=0 THEN
  998. 991 INC(usize[Kind],Used);
  999. 992 INC(ucount[Kind]);
  1000. 993 END; (*IF*)
  1001. 994 INC(tmp,Size);
  1002. 995 END; (*WITH*)
  1003. 996 UNTIL tmp = g.start;
  1004. 997 dec(g.freemem);
  1005. 998 char('/');
  1006. 999 dec(MaxPoss(0FFFFH,dummy,dummy));
  1007. 1000 FOR kind := MIN(SegKind) TO FixedSeg DO
  1008. 1001 char(' ');
  1009. 1002 IF (usize[kind] # 0) & (usize[kind] # tsize[kind]) THEN
  1010. 1003 dec(tcount[kind]-ucount[kind]);
  1011. 1004 char(':');
  1012. 1005 dec(tsize[kind]-usize[kind]);
  1013. 1006 char('/');
  1014. 1007 dec(ucount[kind]);
  1015. 1008 char(':');
  1016. 1009 dec(usize[kind]);
  1017. 1010 ELSE
  1018. 1011 dec(tcount[kind]);
  1019. 1012 char(':');
  1020. 1013 dec(tsize[kind]);
  1021. 1014 END; (*IF*)
  1022. 1015 END; (*FOR*)
  1023. 1016 (*%T MoveTrace *)
  1024. 1017 string(' M=');
  1025. 1018 dec(CARDINAL(g.move_total DIV 400H));
  1026. 1019 char('k');
  1027. 1020 (*%E*)
  1028. 1021 eol;
  1029. 1022 MemPic;
  1030. 1023 END MemStat;
  1031. 1024
  1032. 1025 PROCEDURE DumpMemory;
  1033. 1026 VAR tmp:CARDINAL;
  1034. 1027 BEGIN
  1035. 1028 string('Memory dump'); eol;
  1036. 1029 tmp := g.start;
  1037. 1030 REPEAT
  1038. 1031 WITH [tmp:0 T]^ DO
  1039. 1032 DumpSeg('dump ', tmp+H);
  1040. 1033 tmp := tmp + Size;
  1041. 1034 END;
  1042. 1035 UNTIL tmp = g.start;
  1043. 1036 MemStat;
  1044. 1037 (*%T TraceToFile*)
  1045. 1038 FileClose(output_file);
  1046. 1039 output_file := 1;
  1047. 1040 (*%E*)
  1048. 1041 END DumpMemory;
  1049. 1042
  1050. 1043 PROCEDURE TotalAvail():CARDINAL;
  1051. 1044 VAR
  1052. 1045 res,p : CARDINAL;
  1053. 1046 BEGIN
  1054. 1047 (*%T CHECK*)
  1055. 1048 IF g.freemem # CalcFreeMem() THEN
  1056. 1049 abort(ErrInternal);
  1057. 1050 END; (*IF*)
  1058. 1051 (*%E*)
  1059. 1052 res := g.freemem;
  1060. 1053 IF res > Hide THEN
  1061. 1054 DEC(res,Hide); (* keep 8k free to stop too much shuffling *)
  1062. 1055 ELSE
  1063. 1056 res := 0;
  1064. 1057 END; (*IF*)
  1065. 1058 RETURN res;
  1066. 1059 END TotalAvail;
  1067. 1060
  1068. 1061 PROCEDURE Free(seg:CARDINAL);
  1069. 1062 VAR
  1070. 1063 prev,next : CARDINAL;
  1071. 1064
  1072. 1065 TDummy : T;
  1073. 1066 BEGIN
  1074. 1067 IF seg=0 THEN RETURN END;
  1075. 1068 (*%T CHECK*)
  1076. 1069 CheckAlloc(seg,ErrInvalidFree);
  1077. 1070 (*%E*)
  1078. 1071 DEC(seg);
  1079. 1072 WITH [seg:0 T]^ DO
  1080. 1073 TDummy := [seg:0 T];
  1081. 1074 (*%T MemoryTrace*)
  1082. 1075 IF (Kind IN MemTraceSet) & (~ g.internal) THEN
  1083. 1076 TraceSeg('Free ',seg+H);
  1084. 1077 (* MemStat;*)
  1085. 1078 END; (*IF*)
  1086. 1079 (*%E*)
  1087. 1080 INC(g.freemem,Used);
  1088. 1081 IF seg = g.start THEN
  1089. 1082 Used := 1;
  1090. 1083 Lock := 1;
  1091. 1084 Kind := SystemSeg;
  1092. 1085 DEC(g.freemem);
  1093. 1086 ELSE
  1094. 1087 next := seg + Size;
  1095. 1088 prev := Prev;
  1096. 1089 [next:0 T]^.Prev := prev;
  1097. 1090 [prev:0 T]^.Size := next-prev;
  1098. 1091 END; (*IF*)
  1099. 1092 END; (*WITH*)
  1100. 1093 (*%T CHECK*)
  1101. 1094 CheckMem;
  1102. 1095 (*%E*)
  1103. 1096 END Free;
  1104. 1097
  1105. 1098 PROCEDURE TempAlloc(count:CARDINAL):CARDINAL;
  1106. 1099 VAR
  1107. 1100 i,j:CARDINAL;
  1108. 1101 found:CARDINAL;
  1109. 1102 BEGIN
  1110. 1103 i := 0;
  1111. 1104 LOOP
  1112. 1105 IF i > HIGH(g.temp_map) THEN
  1113. 1106 abort(ErrTempFileLimit);
  1114. 1107 END;
  1115. 1108 IF g.temp_map[i] # BITSET{0..15} THEN
  1116. 1109 EXIT;
  1117. 1110 END;
  1118. 1111 INC(i);
  1119. 1112 END;
  1120. 1113 (* search for count consecutive bits *)
  1121. 1114 j := 0;
  1122. 1115 found := 0;
  1123. 1116 LOOP
  1124. 1117 IF j IN g.temp_map[i] THEN
  1125. 1118 found := 0;
  1126. 1119 ELSE
  1127. 1120 INC(found);
  1128. 1121 IF found = count THEN
  1129. 1122 EXIT;
  1130. 1123 END;
  1131. 1124 END;
  1132. 1125 INC(j);
  1133. 1126 IF j = 16 THEN
  1134. 1127 j := 0;
  1135. 1128 INC(i);
  1136. 1129 IF i > HIGH(g.temp_map) THEN
  1137. 1130 abort(ErrTempFileLimit);
  1138. 1131 END;
  1139. 1132 END;
  1140. 1133 END;
  1141. 1134 (* set the bits *)
  1142. 1135 LOOP
  1143. 1136 INCL(g.temp_map[i], j);
  1144. 1137 DEC(found);
  1145. 1138 IF found=0 THEN
  1146. 1139 EXIT;
  1147. 1140 END;
  1148. 1141 IF j=0 THEN
  1149. 1142 DEC(i);
  1150. 1143 j := 15;
  1151. 1144 ELSE
  1152. 1145 DEC(j);
  1153. 1146 END;
  1154. 1147 END;
  1155. 1148 i := 1 + j + i*16;
  1156. 1149 (*%T ExitTrace *) IF i+CARDINAL(count)-1 > g.temp_max THEN g.temp_max := i+CARDINAL(count)-1; END; (*%E*)
  1157. 1150 RETURN i;
  1158. 1151 END TempAlloc;
  1159. 1152
  1160. 1153 PROCEDURE TempFree(i:CARDINAL;count:CARDINAL);
  1161. 1154 VAR j:CARDINAL;
  1162. 1155 BEGIN
  1163. 1156 DEC(i);
  1164. 1157 j := i MOD 16;
  1165. 1158 i := i DIV 16;
  1166. 1159 REPEAT
  1167. 1160 (*%T CHECK*) IF ~ (j IN g.temp_map[i]) THEN abort(ErrInternal) END; (*%E*)
  1168. 1161 EXCL(g.temp_map[i], j);
  1169. 1162 INC(j);
  1170. 1163 IF j = 16 THEN
  1171. 1164 j := 0;
  1172. 1165 INC(i);
  1173. 1166 END;
  1174. 1167 DEC(count);
  1175. 1168 UNTIL count = 0;
  1176. 1169 END TempFree;
  1177. 1170
  1178. 1171
  1179. 1172 PROCEDURE reserve_panic;
  1180. 1173 BEGIN
  1181. 1174 IF g.panic_reserve = 0 THEN
  1182. 1175 g.panic_reserve := TempAlloc(PanicSize DIV TempPageSize);
  1183. 1176 END;
  1184. 1177 END reserve_panic;
  1185. 1178
  1186. 1179 PROCEDURE release_panic;
  1187. 1180 BEGIN
  1188. 1181 IF g.panic_reserve # 0 THEN
  1189. 1182 TempFree(g.panic_reserve, PanicSize DIV TempPageSize);
  1190. 1183 g.panic_reserve := 0;
  1191. 1184 END;
  1192. 1185 END release_panic;
  1193. 1186
  1194. 1187 PROCEDURE TempXfer(action:DoSegOp;VAR tpv:CARDINAL;seg,off:CARDINAL;count:CARDINAL);
  1195. 1188 VAR
  1196. 1189 (*%T EMS*)
  1197. 1190 ems_page,ems_off,
  1198. 1191 (*%E*)
  1199. 1192 p,amount,tp,
  1200. 1193 temp_size : CARDINAL;
  1201. 1194 BEGIN
  1202. 1195 tp := tpv;
  1203. 1196 IF action = Load THEN
  1204. 1197 tpv := seg;
  1205. 1198 ELSE
  1206. 1199 tpv := 0;
  1207. 1200 END; (*IF*)
  1208. 1201 IF count = 0 THEN
  1209. 1202 RETURN;
  1210. 1203 END; (*IF*)
  1211. 1204 temp_size := 1+((count-1) DIV TempPageSize);
  1212. 1205 IF action = Swap THEN
  1213. 1206 tp := TempAlloc(temp_size);
  1214. 1207 tpv := encode_temp(tp);
  1215. 1208 ELSIF (tp # 0) & ~ is_mem(tp) THEN
  1216. 1209 tp := decode_temp(tp);
  1217. 1210 TempFree(tp, temp_size);
  1218. 1211 END; (*IF*)
  1219. 1212 IF (action = Load) & (tp = 0) THEN
  1220. 1213 Fill([seg:off],count,0);
  1221. 1214 ELSIF action # Discard THEN
  1222. 1215 (*%T EMS*)
  1223. 1216 LOOP
  1224. 1217 IF tp <= g.temp_ems THEN
  1225. 1218 amount := TempPageSize;
  1226. 1219 IF amount > count THEN
  1227. 1220 amount := count;
  1228. 1221 END; (*IF*)
  1229. 1222 ems_page := (tp-1) DIV EmsPageSize;
  1230. 1223 ems_off := ((tp-1) MOD EmsPageSize) * TempPageSize;
  1231. 1224 IF seg+(off DIV 16) >= g.ems_frame+800H THEN
  1232. 1225 p := 0;
  1233. 1226 ELSE
  1234. 1227 p := 3;
  1235. 1228 INC(ems_off, 0C000H);
  1236. 1229 END; (*IF*)
  1237. 1230 EmsMap(4400H+p,ems_page,g.ems_temp_handle);
  1238. 1231 IF action=Swap THEN
  1239. 1232 Move([seg:off],[g.ems_frame:ems_off],amount);
  1240. 1233 ELSE
  1241. 1234 Move([g.ems_frame:ems_off],[seg:off],amount);
  1242. 1235 END; (*IF*)
  1243. 1236 EmsMap(4400H+p,p,g.ems_data_handle);
  1244. 1237 DEC(count,amount);
  1245. 1238 IF count = 0 THEN
  1246. 1239 EXIT;
  1247. 1240 END;
  1248. 1241 INC(off,amount);
  1249. 1242 INC(tp);
  1250. 1243 ELSE
  1251. 1244 (*%E*)
  1252. 1245 FileSeek(g.temp_file,LONGCARD(tp-g.temp_ems-1) * TempPageSize);
  1253. 1246 IF action=Swap THEN
  1254. 1247 IF FileWrite([seg:off],count,g.temp_file) # count THEN
  1255. 1248 abort(ErrTempDiskFull);
  1256. 1249 END; (*IF*)
  1257. 1250 ELSE
  1258. 1251 FileRead([seg:off],count,g.temp_file);
  1259. 1252 END; (*IF*)
  1260. 1253 (*%T EMS*)
  1261. 1254 EXIT;
  1262. 1255 END; (*IF*)
  1263. 1256 END; (*LOOP*)
  1264. 1257 (*%E*)
  1265. 1258 END; (*IF*)
  1266. 1259 END TempXfer;
  1267. 1260
  1268. 1261 PROCEDURE Para(size:CARDINAL):CARDINAL;
  1269. 1262 BEGIN
  1270. 1263 IF size = 0 THEN
  1271. 1264 RETURN 0;
  1272. 1265 ELSE
  1273. 1266 RETURN 1 + ((size-1) DIV 16);
  1274. 1267 END;
  1275. 1268 END Para;
  1276. 1269
  1277. 1270 PROCEDURE P;
  1278. 1271 BEGIN
  1279. 1272 string('trap');
  1280. 1273 eol;
  1281. 1274 END P;
  1282. 1275
  1283. 1276 PROCEDURE GetSeg(module:Module;segnum:SegNum):SegPtr;
  1284. 1277 BEGIN
  1285. 1278 RETURN SegPtr(HeapAdr(module^.seg_info^[segnum]));
  1286. 1279 END GetSeg;
  1287. 1280
  1288. 1281 PROCEDURE SetIndirect(seghdr:SegPtr);
  1289. 1282 VAR
  1290. 1283 gate : GatePtr;
  1291. 1284 BEGIN
  1292. 1285 gate := seghdr^.direct_list;
  1293. 1286 seghdr^.direct_list := GatePtr(0);
  1294. 1287 WHILE gate<>GatePtr(0) DO
  1295. 1288 gate^.state := IndirectGate;
  1296. 1289 gate^.w2 := gate^.w1;
  1297. 1290 gate^.w1 := CARDINAL(seghdr) - CARDINAL(gate) - 2;
  1298. 1291 gate := gate^.next_direct;
  1299. 1292 END;
  1300. 1293 END SetIndirect;
  1301. 1294
  1302. 1295 PROCEDURE Gate(off:CARDINAL;seghdr:SegPtr;iscall:BOOLEAN):CARDINAL;
  1303. 1296 VAR
  1304. 1297 disp:CARDINAL;
  1305. 1298 hash:CARDINAL;
  1306. 1299 gp,ff:GatePtr;
  1307. 1300 BEGIN
  1308. 1301 disp := CARDINAL(seghdr)-3;
  1309. 1302 IF iscall THEN
  1310. 1303 INC(disp);
  1311. 1304 END;
  1312. 1305 hash := 1 + (disp + off) MOD MaxGate;
  1313. 1306 gp := GatePtr(HeapAdr(g.gate_table[hash]));
  1314. 1307 ff := GatePtr(0);
  1315. 1308 LOOP
  1316. 1309 CASE gp^.state OF
  1317. 1310 | FreeGate :
  1318. 1311 IF ff # GatePtr(0) THEN
  1319. 1312 gp := ff;
  1320. 1313 ELSE
  1321. 1314 INC(g.gate_count);
  1322. 1315 IF g.gate_count = MaxGate THEN
  1323. 1316 abort(ErrGateLimit);
  1324. 1317 END;
  1325. 1318 END;
  1326. 1319 gp^.state := IndirectGate;
  1327. 1320 gp^.w2 := off;
  1328. 1321 gp^.w1 := disp - CARDINAL(gp);
  1329. 1322 EXIT;
  1330. 1323 | DeletedGate :
  1331. 1324 IF ff = GatePtr(0) THEN
  1332. 1325 ff := gp;
  1333. 1326 END;
  1334. 1327 | IndirectGate :
  1335. 1328 IF (gp^.w2 = off) & (gp^.w1 + CARDINAL(gp) = disp) THEN
  1336. 1329 EXIT;
  1337. 1330 END;
  1338. 1331 | DirectGate :
  1339. 1332 IF (gp^.w1 = off) & (gp^.w2 = seghdr^.seg_val) THEN
  1340. 1333 EXIT;
  1341. 1334 END;
  1342. 1335 END;
  1343. 1336 IF gp = GatePtr(HeapAdr(g.gate_table[MaxGate])) THEN
  1344. 1337 gp := GatePtr(HeapAdr(g.gate_table[1]));
  1345. 1338 ELSE
  1346. 1339 INC(CARDINAL(gp),SIZE(gp^));
  1347. 1340 END;
  1348. 1341 END;
  1349. 1342 RETURN CARDINAL(gp);
  1350. 1343 END Gate;
  1351. 1344
  1352. 1345 PROCEDURE RetGate(off, seg:CARDINAL):ADDRESS;
  1353. 1346 VAR
  1354. 1347 modnum:ModNum;
  1355. 1348 segnum:SegNum;
  1356. 1349 seghdr:SegPtr;
  1357. 1350 BEGIN
  1358. 1351 (*%T CHECK*) CheckAlloc(seg,0); (*%E*)
  1359. 1352 WITH [seg-1:0 T]^ DO
  1360. 1353 modnum := Id1;
  1361. 1354 segnum := Id2;
  1362. 1355 END;
  1363. 1356 seghdr := GetSeg(g.module_list[modnum], segnum);
  1364. 1357 RETURN [Seg(g) : Gate(off, seghdr, FALSE)];
  1365. 1358 END RetGate;
  1366. 1359
  1367. 1360 PROCEDURE Append(VAR s:ARRAY OF CHAR;e:ARRAY OF CHAR); (*String*)
  1368. 1361 VAR i,j:CARDINAL;
  1369. 1362 BEGIN
  1370. 1363 i := 0;
  1371. 1364 WHILE s[i]#0C DO
  1372. 1365 INC(i);
  1373. 1366 END;
  1374. 1367 j := 0;
  1375. 1368 LOOP
  1376. 1369 s[i] := e[j];
  1377. 1370 IF s[i] = 0C THEN
  1378. 1371 EXIT;
  1379. 1372 END;
  1380. 1373 INC(i);
  1381. 1374 INC(j);
  1382. 1375 END;
  1383. 1376 END Append;
  1384. 1377
  1385. 1378 PROCEDURE PathOpen(tail:ARRAY OF CHAR):CARDINAL;
  1386. 1379 CONST pathname='PATH=';
  1387. 1380 VAR
  1388. 1381 envptr : POINTER TO ARRAY [0..999] OF CHAR;
  1389. 1382 envseg,i,j:CARDINAL;
  1390. 1383 c:CHAR;
  1391. 1384 file:CARDINAL;
  1392. 1385 path:ARRAY [0..255] OF CHAR;
  1393. 1386 BEGIN
  1394. 1387 file := FileOpen(tail, BITSET(0)); (* Try local *)
  1395. 1388 IF file # MAX(CARDINAL) THEN RETURN file; END;
  1396. 1389 envseg := [g.psp: 2CH]^;
  1397. 1390 envptr := [envseg: 0];
  1398. 1391
  1399. 1392 i := 0;
  1400. 1393 j := 0;
  1401. 1394 LOOP (* search for 'PATH=' *)
  1402. 1395 c := pathname[j];
  1403. 1396 IF c=0C THEN
  1404. 1397 EXIT;
  1405. 1398 END;
  1406. 1399 IF c # envptr^[i] THEN
  1407. 1400 j := 0;
  1408. 1401 WHILE envptr^[i]#0C DO
  1409. 1402 INC(i);
  1410. 1403 END;
  1411. 1404 INC(i);
  1412. 1405 IF envptr^[i]=0C THEN
  1413. 1406 EXIT;
  1414. 1407 END;
  1415. 1408 ELSE
  1416. 1409 INC(j);
  1417. 1410 INC(i);
  1418. 1411 END;
  1419. 1412 END;
  1420. 1413
  1421. 1414 j := 0;
  1422. 1415 LOOP
  1423. 1416 c := envptr^[i];
  1424. 1417 path[j] := c;
  1425. 1418 IF (c = ';') OR (c=0C) THEN
  1426. 1419 IF c#'\' THEN
  1427. 1420 path[j] := '\';
  1428. 1421 INC(j);
  1429. 1422 END;
  1430. 1423 path[j] := 0C;
  1431. 1424 Append(path,tail);
  1432. 1425 file := FileOpen(path, BITSET(0));
  1433. 1426 IF file # MAX(CARDINAL) THEN
  1434. 1427 EXIT;
  1435. 1428 END;
  1436. 1429 IF c = 0C THEN
  1437. 1430 EXIT;
  1438. 1431 END;
  1439. 1432 j := 0;
  1440. 1433 ELSE
  1441. 1434 INC(j);
  1442. 1435 END;
  1443. 1436 INC(i);
  1444. 1437 END;
  1445. 1438 RETURN file;
  1446. 1439 END PathOpen;
  1447. 1440
  1448. 1441 PROCEDURE ModuleRead(module:Module;pos:LONGCARD;a:ADDRESS;count:CARDINAL):BOOLEAN;
  1449. 1442 VAR
  1450. 1443 modnum:ModNum;
  1451. 1444 victim:Module;
  1452. 1445 fullname:ARRAY [0..99] OF CHAR;
  1453. 1446 file:CARDINAL;
  1454. 1447 BEGIN
  1455. 1448 IF count=0 THEN
  1456. 1449 RETURN FALSE;
  1457. 1450 END;
  1458. 1451 file := module^.file;
  1459. 1452 modnum := 1;
  1460. 1453 WHILE ((file = MAX(CARDINAL)) & (g.file_count >= FileLimit)) OR
  1461. 1454 (g.file_count > FileLimit)
  1462. 1455 DO
  1463. 1456 (*%T CHECK*) IF modnum > g.module_count THEN abort(ErrInternal); END; (*%E*)
  1464. 1457 victim := g.module_list[modnum];
  1465. 1458 IF (victim^.file # MAX(CARDINAL)) & (victim^.file # file) THEN
  1466. 1459 FileClose(victim^.file);
  1467. 1460 IF FileTrace THEN
  1468. 1461 string('Close file ');
  1469. 1462 string(victim^.name^);
  1470. 1463 eol;
  1471. 1464 END;
  1472. 1465 victim^.file := MAX(CARDINAL);
  1473. 1466 DEC(g.file_count);
  1474. 1467 END;
  1475. 1468 INC(modnum);
  1476. 1469 END;
  1477. 1470 IF file = MAX(CARDINAL) THEN
  1478. 1471 fullname[0] := 0C;
  1479. 1472 Append(fullname, module^.name^);
  1480. 1473 IF module^.is_exe THEN
  1481. 1474 Append(fullname, '.exe');
  1482. 1475 ELSE
  1483. 1476 Append(fullname, '.dll');
  1484. 1477 END;
  1485. 1478 file := PathOpen(fullname);
  1486. 1479 module^.file := file;
  1487. 1480 IF FileTrace THEN
  1488. 1481 string('Open file ');
  1489. 1482 string(fullname);
  1490. 1483 IF file = MAX(CARDINAL) THEN
  1491. 1484 string(' - failed to open !!');
  1492. 1485 END;
  1493. 1486 eol;
  1494. 1487 END;
  1495. 1488 IF file = MAX(CARDINAL) THEN
  1496. 1489 RETURN TRUE;
  1497. 1490 END;
  1498. 1491 INC(g.file_count);
  1499. 1492 END;
  1500. 1493 FileSeek(file, pos);
  1501. 1494 FileRead(a, count, file);
  1502. 1495 RETURN FALSE;
  1503. 1496 END ModuleRead;
  1504. 1497
  1505. 1498 (*%T VidSupport*)
  1506. 1499 (*# save, call(reg_param=>(ax,bx,cx,dx,si),
  1507. 1500 reg_saved =>(ds,es,di,st1,st2), inline=>on) *)
  1508. 1501 PROCEDURE debug_int(data_ptr:ADDRESS;name_ptr:ADDRESS;action:CARDINAL) =
  1509. 1502 A2(0CDH,063H);
  1510. 1503 (*# restore *)
  1511. 1504
  1512. 1505 TYPE VidAction = (VID_XX, VID_LOAD_MODULE, VID_LOAD_SEG, VID_UNLOAD_SEG);
  1513. 1506
  1514. 1507 PROCEDURE TellVid(modnum:ModNum;segnum:SegNum;action:VidAction);
  1515. 1508 TYPE
  1516. 1509 StrPtr = POINTER TO ARRAY[0..79] OF CHAR;
  1517. 1510 SegListPtr = POINTER TO SegListRec;
  1518. 1511 DllLoadPtr = POINTER TO DllLoadRec;
  1519. 1512 SegListRec = RECORD
  1520. 1513 new_rlc : CARDINAL;
  1521. 1514 module : DllLoadPtr;
  1522. 1515 ext_deps : SHORTADDR;
  1523. 1516 seg_val : CARDINAL;
  1524. 1517 seg_size : CARDINAL;
  1525. 1518 reloc_num : CARDINAL;
  1526. 1519 type : CARDINAL;
  1527. 1520 use_count : SHORTCARD;
  1528. 1521 lru_count : SHORTCARD;
  1529. 1522 status : SHORTCARD;
  1530. 1523 seg_no : SHORTCARD;
  1531. 1524 (*%T EMS*)
  1532. 1525 ems_page : SHORTCARD;
  1533. 1526 ems_size : SHORTCARD;
  1534. 1527 (*%E*)
  1535. 1528 ref_count : CARDINAL;
  1536. 1529 swap_pos : CARDINAL;
  1537. 1530 END;
  1538. 1531
  1539. 1532
  1540. 1533 DllLoadRec = RECORD
  1541. 1534 total_entries : CARDINAL;
  1542. 1535 entries : ADDRESS;
  1543. 1536 segs : SegListPtr;
  1544. 1537 total_segments : CARDINAL;
  1545. 1538 status : SHORTCARD;
  1546. 1539 entry_point : PROC;
  1547. 1540 module_no : SHORTCARD;
  1548. 1541 END;
  1549. 1542
  1550. 1543 VAR
  1551. 1544 m:DllLoadRec;
  1552. 1545 s:SegListRec;
  1553. 1546 dp:ADDRESS;
  1554. 1547 name:ARRAY [0..255] OF CHAR;
  1555. 1548 module:Module;
  1556. 1549 BEGIN
  1557. 1550 IF g.vid_present THEN
  1558. 1551 module := g.module_list[modnum];
  1559. 1552 m.total_segments := module^.seg_count;
  1560. 1553 IF action = VID_LOAD_MODULE THEN
  1561. 1554 dp := ADR(m);
  1562. 1555 ELSE
  1563. 1556 dp := ADR(s);
  1564. 1557 s.module := ADR(m);
  1565. 1558 s.seg_no := SHORTCARD(segnum);
  1566. 1559 s.seg_val := module^.seg_info^[segnum].seg_val;
  1567. 1560 s.seg_size := module^.seg_info^[segnum].membyte;
  1568. 1561 END;
  1569. 1562 name[0] := 0C;
  1570. 1563 Append(name, module^.name^);
  1571. 1564 IF module^.is_exe THEN
  1572. 1565 Append(name, '.EXE');
  1573. 1566 ELSE
  1574. 1567 Append(name, '.DLL');
  1575. 1568 (*Int66;*)
  1576. 1569 END;
  1577. 1570 debug_int(dp, ADR(name), CARDINAL(action));
  1578. 1571 END;
  1579. 1572 END TellVid;
  1580. 1573
  1581. 1574 PROCEDURE TellVidMove;
  1582. 1575 BEGIN
  1583. 1576 IF g.vid_delayed THEN
  1584. 1577 g.vid_delayed := FALSE;
  1585. 1578 TellVid(g.vid_id1,g.vid_id2,VID_LOAD_SEG);
  1586. 1579 END;
  1587. 1580 END TellVidMove;
  1588. 1581
  1589. 1582 PROCEDURE FindVid;
  1590. 1583 VAR
  1591. 1584 iv:POINTER TO ADDRESS;
  1592. 1585 cp:POINTER TO ARRAY [0..0] OF CHAR;
  1593. 1586 BEGIN
  1594. 1587 iv := [0:63H*4];
  1595. 1588 cp := iv^;
  1596. 1589 IF (cp^[-3]='V') & (cp^[-2]='I') & (cp^[-1]='D') THEN
  1597. 1590 g.vid_present := TRUE;
  1598. 1591 END;
  1599. 1592 END FindVid;
  1600. 1593 (*%E*)
  1601. 1594
  1602. 1595
  1603. 1596 PROCEDURE MakeSys(seg:CARDINAL); FORWARD;
  1604. 1597
  1605. 1598
  1606. 1599 PROCEDURE ReserveDisk(amount:LONGCARD):BOOLEAN;
  1607. 1600 VAR dummy:CHAR;
  1608. 1601 BEGIN
  1609. 1602 INC(g.temp_reserve, amount);
  1610. 1603 IF (g.temp_reserve > LONGINT(FileSize(g.temp_file))) THEN
  1611. 1604 FileSeek(g.temp_file, g.temp_reserve + 1001H);
  1612. 1605 dummy := 'x';
  1613. 1606 IF FileWrite(ADR(dummy), 1, g.temp_file) # 1 THEN
  1614. 1607 DEC(g.temp_reserve, amount);
  1615. 1608 RETURN FALSE;
  1616. 1609 END;
  1617. 1610 END;
  1618. 1611 RETURN TRUE;
  1619. 1612 END ReserveDisk;
  1620. 1613
  1621. 1614 PROCEDURE ReleaseDisk(amount:LONGCARD);
  1622. 1615 BEGIN
  1623. 1616 DEC(g.temp_reserve, amount);
  1624. 1617 END ReleaseDisk;
  1625. 1618
  1626. 1619 PROCEDURE TempHandle():CARDINAL;
  1627. 1620 BEGIN
  1628. 1621 RETURN g.temp_file;
  1629. 1622 END TempHandle;
  1630. 1623
  1631. 1624
  1632. 1625 (*# save,data(const_in_code=>on) *)
  1633. 1626 CONST TempFileName = '\tstemp00.$$$';
  1634. 1627 CONST FullTempFileName =
  1635. 1628 'A:\ ';
  1636. 1629 (*%T EMS*)
  1637. 1630 CONST EmsName = 'EMMXXXX0';
  1638. 1631 (*%E*)
  1639. 1632 (*# restore *)
  1640. 1633
  1641. 1634 PROCEDURE SetEms(on:BOOLEAN):BOOLEAN;
  1642. 1635 (*%T EMS*)
  1643. 1636 VAR
  1644. 1637 ems:CARDINAL;
  1645. 1638 i,p:CARDINAL;
  1646. 1639 ems_page,ems_off:CARDINAL;
  1647. 1640 avail:CARDINAL;
  1648. 1641 LABEL restore_data, return;
  1649. 1642 (*%E*)
  1650. 1643 BEGIN
  1651. 1644 (*%T EMS*)
  1652. 1645 release_panic;
  1653. 1646 IF (g.ems_temp_handle # 0) = on THEN
  1654. 1647 GOTO return;
  1655. 1648 END;
  1656. 1649 IF on THEN
  1657. 1650 IF g.ems_data_handle = 0 THEN
  1658. 1651 IF ~ g.ems_present THEN
  1659. 1652 GOTO return;
  1660. 1653 END;
  1661. 1654 avail := EmsGet(4200H); (* get number of free pages *)
  1662. 1655 IF avail < 4 THEN
  1663. 1656 GOTO return;
  1664. 1657 END;
  1665. 1658 g.ems_count := avail;
  1666. 1659 g.ems_data_handle := EmsAlloc(4300H, 4); (* allocate free pages *)
  1667. 1660 (* put 64K block in free memory chain*)
  1668. 1661 FOR p := 0 TO 3 DO
  1669. 1662 EmsMap(4400H+p, p, g.ems_data_handle);
  1670. 1663 END;
  1671. 1664 MakeSys(g.ems_frame + 1000H - 1);
  1672. 1665 MakeSys(g.ems_frame);
  1673. 1666 WITH [g.ems_frame:0 T]^ DO
  1674. 1667 Used := 0;
  1675. 1668 INC(g.freemem, Size);
  1676. 1669 END;
  1677. 1670 END;
  1678. 1671 avail := EmsGet(4200H); (* get number of free pages *)
  1679. 1672 IF avail = 0 THEN
  1680. 1673 GOTO return;
  1681. 1674 END;
  1682. 1675 g.ems_temp_handle := EmsAlloc(4300H, avail); (* allocate free pages *)
  1683. 1676 g.temp_ems := avail * EmsPageSize;
  1684. 1677 ReleaseDisk(LONGINT(g.temp_ems)*TempPageSize);
  1685. 1678 END;
  1686. 1679 (* transfer pages from temp file to/from ems *)
  1687. 1680 FOR i := 0 TO g.temp_ems-1 DO
  1688. 1681 IF (i MOD 16) IN g.temp_map[i DIV 16] THEN
  1689. 1682 ems_page := i DIV EmsPageSize;
  1690. 1683 ems_off := (i MOD EmsPageSize) * TempPageSize;
  1691. 1684 EmsMap(4400H, ems_page, g.ems_temp_handle);
  1692. 1685 FileSeek(g.temp_file, LONGCARD(i)*TempPageSize);
  1693. 1686 IF on THEN
  1694. 1687 FileRead([g.ems_frame:ems_off], TempPageSize, g.temp_file);
  1695. 1688 ELSE
  1696. 1689 IF FileWrite([g.ems_frame:ems_off], TempPageSize, g.temp_file) # TempPageSize THEN
  1697. 1690 GOTO restore_data;
  1698. 1691 END;
  1699. 1692 END;
  1700. 1693 END;
  1701. 1694 END;
  1702. 1695 IF ~ on THEN
  1703. 1696 IF ~ ReserveDisk(LONGINT(g.temp_ems)*TempPageSize) THEN
  1704. 1697 GOTO restore_data;
  1705. 1698 END;
  1706. 1699 EmsMap(4500H, 0, g.ems_temp_handle); (* free temp pages *)
  1707. 1700 g.ems_temp_handle := 0;
  1708. 1701 g.temp_ems := 0;
  1709. 1702 END;
  1710. 1703 restore_data:
  1711. 1704 EmsMap(4400H, 0, g.ems_data_handle); (* restore data page *)
  1712. 1705 return:
  1713. 1706 reserve_panic;
  1714. 1707 RETURN g.ems_temp_handle # 0;
  1715. 1708 (*%E*)
  1716. 1709 (*%F EMS*)
  1717. 1710 RETURN FALSE;
  1718. 1711 (*%E*)
  1719. 1712 END SetEms;
  1720. 1713
  1721. 1714 PROCEDURE DoSeg(modnum:ModNum;segnum:SegNum;op:DoSegOp):CARDINAL; FORWARD;
  1722. 1715
  1723. 1716 PROCEDURE DoDelay;
  1724. 1717 VAR
  1725. 1718 module : Module;
  1726. 1719 modnum : ModNum;
  1727. 1720 segnum : SegNum;
  1728. 1721 segment : CARDINAL;
  1729. 1722 gate : GatePtr;
  1730. 1723 seghdr : SegPtr;
  1731. 1724 seginfosize : CARDINAL;
  1732. 1725 BEGIN
  1733. 1726 IF g.delay # 0 THEN
  1734. 1727 modnum := g.delay;
  1735. 1728 g.delay := 0;
  1736. 1729 module := g.module_list[modnum];
  1737. 1730 (* swap out all segments *)
  1738. 1731 FOR segnum := 1 TO module^.seg_count DO
  1739. 1732 segment := DoSeg(modnum,segnum,Discard);
  1740. 1733 END; (*FOR*)
  1741. 1734 (* delete gates *)
  1742. 1735 seginfosize := module^.seg_count * SIZE(SegRec);
  1743. 1736 gate := GatePtr(HeapAdr(g.gate_table));
  1744. 1737 LOOP
  1745. 1738 IF gate^.state = IndirectGate THEN
  1746. 1739 seghdr := SegPtr(gate^.w1 + CARDINAL(gate) + 3);
  1747. 1740 IF CARDINAL(seghdr) - CARDINAL(module^.seg_info) < seginfosize THEN
  1748. 1741 gate^.state := DeletedGate;
  1749. 1742 END; (*IF*)
  1750. 1743 END; (*IF*)
  1751. 1744 IF gate = GatePtr(HeapAdr(g.gate_table[MaxGate])) THEN
  1752. 1745 EXIT;
  1753. 1746 END; (*IF*)
  1754. 1747 INC(CARDINAL(gate),SIZE(GateRec));
  1755. 1748 END; (*LOOP*)
  1756. 1749 (* close file *)
  1757. 1750 IF (module^.file # MAX(CARDINAL)) THEN
  1758. 1751 FileClose(module^.file);
  1759. 1752 IF FileTrace THEN
  1760. 1753 string('Close file ');
  1761. 1754 string(module^.name^);
  1762. 1755 eol;
  1763. 1756 END; (*IF*)
  1764. 1757 module^.file := MAX(CARDINAL);
  1765. 1758 DEC(g.file_count);
  1766. 1759 END; (*IF*)
  1767. 1760 (* free heap if last module *)
  1768. 1761 IF modnum = g.module_count THEN
  1769. 1762 DEC(g.module_count);
  1770. 1763 Fill(ADR(module^),g.near_alloc - CARDINAL(module),0);
  1771. 1764 g.near_alloc := CARDINAL(module);
  1772. 1765 END; (*IF*)
  1773. 1766 END; (*IF*)
  1774. 1767 END DoDelay;
  1775. 1768
  1776. 1769 PROCEDURE UnLoadModule(modnum:CARDINAL);
  1777. 1770 BEGIN
  1778. 1771 IF g.delay # modnum THEN
  1779. 1772 DoDelay;
  1780. 1773 END;
  1781. 1774 g.delay := modnum;
  1782. 1775 END UnLoadModule;
  1783. 1776
  1784. 1777
  1785. 1778
  1786. 1779 PROCEDURE GetOrdProcAddr (modnum:CARDINAL;entry:CARDINAL):ADDRESS;
  1787. 1780 VAR
  1788. 1781 offset:CARDINAL;
  1789. 1782 module:Module;
  1790. 1783 BEGIN
  1791. 1784 module := g.module_list[modnum];
  1792. 1785 offset := Gate(module^.entry_table^[entry].ofs,
  1793. 1786 GetSeg(module, SegNum(module^.entry_table^[entry].seg)), TRUE);
  1794. 1787 RETURN [Seg(g) : offset];
  1795. 1788 END GetOrdProcAddr;
  1796. 1789
  1797. 1790 PROCEDURE New(size:CARDINAL):HeapADDR;
  1798. 1791 (* Allocate bytes from Near Heap *)
  1799. 1792 VAR res:HeapADDR;
  1800. 1793 BEGIN
  1801. 1794 res := SHORTADDR(g.near_alloc);
  1802. 1795 INC(g.near_alloc,size);
  1803. 1796 IF g.near_alloc > Ofs(g.heap[HeapSize]) THEN
  1804. 1797 abort(ErrNearHeap);
  1805. 1798 END; (*IF*)
  1806. 1799 RETURN res;
  1807. 1800 END New;
  1808. 1801
  1809. 1802 PROCEDURE Length(s: ARRAY OF CHAR):CARDINAL; (*String*)
  1810. 1803 VAR i:CARDINAL;
  1811. 1804 BEGIN
  1812. 1805 i := 0;
  1813. 1806 WHILE s[i]#0C DO
  1814. 1807 INC(i);
  1815. 1808 END;
  1816. 1809 RETURN i;
  1817. 1810 END Length;
  1818. 1811
  1819. 1812 PROCEDURE Compare(s1,s2:ARRAY OF CHAR):BOOLEAN; (*String*)
  1820. 1813 VAR
  1821. 1814 i : CARDINAL;
  1822. 1815 BEGIN
  1823. 1816 i := 0;
  1824. 1817 LOOP
  1825. 1818 IF s1[i] # s2[i] THEN
  1826. 1819 RETURN FALSE;
  1827. 1820 END;
  1828. 1821 IF s1[i] = 0C THEN
  1829. 1822 RETURN TRUE;
  1830. 1823 END;
  1831. 1824 INC(i);
  1832. 1825 END;
  1833. 1826 END Compare;
  1834. 1827
  1835. 1828
  1836. 1829 PROCEDURE GetNextFree(seg : CARDINAL;VAR fsize : CARDINAL) : CARDINAL;
  1837. 1830 (* Returns next area > seg that is not being used for anything *)
  1838. 1831 (* Used for spawn *)
  1839. 1832 VAR p:CARDINAL; fseg : CARDINAL;
  1840. 1833 BEGIN
  1841. 1834 p := g.start;
  1842. 1835 LOOP
  1843. 1836 WITH [p:0 T]^ DO
  1844. 1837 IF p+Used>seg THEN
  1845. 1838 fseg := p+Used;
  1846. 1839 fsize := Size-Used;
  1847. 1840 IF (fsize>0) THEN
  1848. 1841 (*%T EMS*)
  1849. 1842 IF (g.ems_data_handle = 0) OR
  1850. 1843 (fseg<g.ems_frame) OR
  1851. 1844 (fseg>g.ems_frame+1000H)
  1852. 1845 THEN
  1853. 1846 EXIT;
  1854. 1847 END;
  1855. 1848 (*%E*)
  1856. 1849 (*%F EMS*)
  1857. 1850 EXIT;
  1858. 1851 (*%E*)
  1859. 1852 END;
  1860. 1853 END;
  1861. 1854 p := p+Size;
  1862. 1855 END;
  1863. 1856 IF p = g.start THEN
  1864. 1857 fseg := 0;
  1865. 1858 EXIT;
  1866. 1859 END;
  1867. 1860 END;
  1868. 1861 RETURN fseg;
  1869. 1862 END GetNextFree;
  1870. 1863
  1871. 1864 (*%F CHECK*) INLINE (*%E*) PROCEDURE Lock(seg:CARDINAL);
  1872. 1865 BEGIN
  1873. 1866 IF LockTrace THEN
  1874. 1867 string('Lock '); hex(seg); eol;
  1875. 1868 END;
  1876. 1869 (*%T CHECK*)
  1877. 1870 CheckAlloc(seg,0);
  1878. 1871 (*%E*)
  1879. 1872 INC([seg-H:0 T]^.Lock);
  1880. 1873 END Lock;
  1881. 1874
  1882. 1875 (*%F CHECK*) INLINE (*%E*) PROCEDURE UnLock(seg:CARDINAL);
  1883. 1876 BEGIN
  1884. 1877 IF LockTrace THEN
  1885. 1878 string('UnLock '); hex(seg); eol;
  1886. 1879 END;
  1887. 1880 (*%T CHECK*)
  1888. 1881 CheckAlloc(seg,0);
  1889. 1882 IF [seg-H:0 T]^.Lock = 0 THEN abort(ErrTooManyUnlocks); END;
  1890. 1883 (*%E*)
  1891. 1884 DEC([seg-H:0 T]^.Lock);
  1892. 1885 END UnLock;
  1893. 1886
  1894. 1887
  1895. 1888 PROCEDURE DoSwap(seg : CARDINAL);
  1896. 1889 (* Only called for StaticSeg and SwapSeg *)
  1897. 1890 VAR
  1898. 1891 dummy : CARDINAL;
  1899. 1892 seghdr : SegPtr;
  1900. 1893 BEGIN
  1901. 1894 WITH [seg:0 T]^ DO
  1902. 1895 IF Kind=StaticSeg THEN
  1903. 1896 (*%T CHECK*)
  1904. 1897 seghdr := SegPtr(HeapAdr(g.module_list[Id1]^.seg_info^[Id2]));
  1905. 1898 IF seghdr^.direct_list<>GatePtr(0) THEN
  1906. 1899 abort(ErrInternal);
  1907. 1900 END;
  1908. 1901 (*%E*)
  1909. 1902 dummy := DoSeg(Id1,Id2,Swap);
  1910. 1903 ELSIF Kind=SwapSeg THEN
  1911. 1904 TempXfer(Swap,[Id2:Id1 WP]^,seg+1,0,([seg:0 T]^.Used-1)*16);
  1912. 1905 Free(seg+1);
  1913. 1906 ELSE
  1914. 1907 (*%T CHECK*)
  1915. 1908 abort(ErrInternal);
  1916. 1909 (*%E*)
  1917. 1910 END;
  1918. 1911 END;
  1919. 1912 END DoSwap;
  1920. 1913
  1921. 1914
  1922. 1915 PROCEDURE IsActive(seghdr:SegPtr):BOOLEAN;
  1923. 1916 TYPE
  1924. 1917 fp = POINTER Seg(seghdr) TO RECORD
  1925. 1918 bp,ip,cs: CARDINAL;
  1926. 1919 END; (*fp*)
  1927. 1920 VAR
  1928. 1921 bp : fp;
  1929. 1922 cs : CARDINAL;
  1930. 1923 res : BOOLEAN;
  1931. 1924 BEGIN
  1932. 1925 res := FALSE;
  1933. 1926 cs := seghdr^.seg_val;
  1934. 1927 bp := fp(GetBP());
  1935. 1928 REPEAT
  1936. 1929 (*%T CHECK*)
  1937. 1930 IF bp^.bp # 0 THEN
  1938. 1931 CheckAlloc(bp^.cs,ErrCallChainInvalid);
  1939. 1932 END; (*IF*)
  1940. 1933 (*%E*)
  1941. 1934 IF bp^.cs = cs THEN
  1942. 1935 bp^.ip := Gate(bp^.ip,seghdr,FALSE);
  1943. 1936 bp^.cs := Seg(g);
  1944. 1937 res := TRUE;
  1945. 1938 END; (*IF*)
  1946. 1939 (*%T CHECK*)
  1947. 1940 IF ((bp^.bp=0)AND(bp^.ip # 1234H)) OR
  1948. 1941 ((bp^.bp<>0)AND(bp^.bp <= CARDINAL(bp))) THEN
  1949. 1942 abort(ErrCallChainInvalid);
  1950. 1943 END; (*IF*)
  1951. 1944 (*%E*)
  1952. 1945 bp := fp(bp^.bp);
  1953. 1946 UNTIL bp = fp(0);
  1954. 1947 RETURN res;
  1955. 1948 END IsActive;
  1956. 1949
  1957. 1950 PROCEDURE MyCaller():CARDINAL;
  1958. 1951 VAR
  1959. 1952 res : BOOLEAN;
  1960. 1953 TYPE
  1961. 1954 fp = POINTER Seg(res) TO RECORD
  1962. 1955 bp,ip,cs: CARDINAL;
  1963. 1956 END; (*fp*)
  1964. 1957 VAR
  1965. 1958 bp : fp;
  1966. 1959 BEGIN
  1967. 1960 res := FALSE;
  1968. 1961 bp := fp(GetBP());
  1969. 1962 REPEAT
  1970. 1963 (*%T CHECK*)
  1971. 1964 IF bp^.bp # 0 THEN
  1972. 1965 CheckAlloc(bp^.cs,ErrCallChainInvalid);
  1973. 1966 END; (*IF*)
  1974. 1967 IF ((bp^.bp=0)AND(bp^.ip # 1234H)) OR
  1975. 1968 ((bp^.bp<>0)AND(bp^.bp <= CARDINAL(bp))) THEN
  1976. 1969 abort(ErrCallChainInvalid);
  1977. 1970 END; (*IF*)
  1978. 1971 (*%E*)
  1979. 1972 IF bp^.cs<>Seg(MyCaller) THEN
  1980. 1973 RETURN bp^.cs;
  1981. 1974 END;
  1982. 1975 bp := fp(bp^.bp);
  1983. 1976 UNTIL bp = fp(0);
  1984. 1977 RETURN 0;
  1985. 1978 END MyCaller;
  1986. 1979
  1987. 1980
  1988. 1981 PROCEDURE RelocStatic(seghdr:SegPtr;new:CARDINAL);
  1989. 1982 TYPE
  1990. 1983 fp = POINTER Seg(seghdr) TO RECORD
  1991. 1984 bp,ip,cs: CARDINAL;
  1992. 1985 END; (*fp*)
  1993. 1986 VAR
  1994. 1987 bp : fp;
  1995. 1988 cs : CARDINAL;
  1996. 1989 gate : GatePtr;
  1997. 1990 BEGIN
  1998. 1991 cs := seghdr^.seg_val;
  1999. 1992 seghdr^.seg_val := new;
  2000. 1993 gate := seghdr^.direct_list;
  2001. 1994 WHILE gate # GatePtr(0) DO
  2002. 1995 gate^.w2 := new;
  2003. 1996 gate := gate^.next_direct;
  2004. 1997 END; (*WHILE*)
  2005. 1998 bp := fp(GetBP());
  2006. 1999 REPEAT
  2007. 2000 IF bp^.cs = cs THEN
  2008. 2001 bp^.cs := new;
  2009. 2002 (*%T CHECK*)
  2010. 2003 ELSIF bp^.bp # 0 THEN
  2011. 2004 CheckAlloc(bp^.cs,ErrCallChainInvalid);
  2012. 2005 (*%E*)
  2013. 2006 END; (*IF*)
  2014. 2007 (*%T CHECK*)
  2015. 2008 IF ((bp^.bp=0)AND(bp^.ip # 1234H)) OR
  2016. 2009 ((bp^.bp<>0)AND(bp^.bp <= CARDINAL(bp))) THEN
  2017. 2010 abort(ErrCallChainInvalid);
  2018. 2011 END; (*IF*)
  2019. 2012 (*%E*)
  2020. 2013 bp := fp(bp^.bp);
  2021. 2014 UNTIL bp = fp(0);
  2022. 2015 END RelocStatic;
  2023. 2016
  2024. 2017 PROCEDURE DoFlushAll;
  2025. 2018 VAR
  2026. 2019 tmp : CARDINAL;
  2027. 2020 change : BOOLEAN;
  2028. 2021 BEGIN
  2029. 2022 REPEAT
  2030. 2023 change := FALSE;
  2031. 2024 tmp := g.start;
  2032. 2025 REPEAT
  2033. 2026 WITH [tmp:0 T]^ DO
  2034. 2027 IF (Lock = 0) & (Kind # MoveSeg) THEN
  2035. 2028 IF Kind=StaticSeg THEN
  2036. 2029 SetIndirect(SegPtr(HeapAdr(g.module_list[Id1]^.seg_info^[Id2])));
  2037. 2030 END;
  2038. 2031 DoSwap(tmp);
  2039. 2032 change := TRUE;
  2040. 2033 END; (*IF*)
  2041. 2034 INC(tmp,Size);
  2042. 2035 END; (*WITH*)
  2043. 2036 UNTIL tmp = g.start;
  2044. 2037 UNTIL ~change;
  2045. 2038 END DoFlushAll;
  2046. 2039
  2047. 2040 PROCEDURE TinyFlush; FORWARD;
  2048. 2041
  2049. 2042 (* Should do long jump to reset point, Also OutOfDisk needs doing *)
  2050. 2043 PROCEDURE OutOfMem(request:CARDINAL);
  2051. 2044 BEGIN
  2052. 2045 IF OutOfMemTrace THEN
  2053. 2046 string('Out of memory.');
  2054. 2047 eol;
  2055. 2048 DumpMemory;
  2056. 2049 MemStat;
  2057. 2050 END; (*IF*)
  2058. 2051 IF ~g.OutOfMem(request) THEN
  2059. 2052 abort(ErrOutOfMem);
  2060. 2053 END; (*IF*)
  2061. 2054 END OutOfMem;
  2062. 2055
  2063. 2056 PROCEDURE FlushLRU(req:CARDINAL);
  2064. 2057 VAR
  2065. 2058 tmp : CARDINAL;
  2066. 2059 lru : CARDINAL;
  2067. 2060 age,maxage : CARDINAL;
  2068. 2061 res : BOOLEAN;
  2069. 2062 i : CARDINAL;
  2070. 2063 wants : CARDINAL;
  2071. 2064 ssize : CARDINAL;
  2072. 2065 seghdr : SegPtr;
  2073. 2066 BEGIN
  2074. 2067 (*%T GraphUseTrace*)
  2075. 2068 GraphTrace(0,req,GTlru);
  2076. 2069 (*%E*)
  2077. 2070 wants := req+400H;
  2078. 2071 (*%T CHECK*)
  2079. 2072 CheckMem;
  2080. 2073 (*%E*)
  2081. 2074 TinyFlush;
  2082. 2075
  2083. 2076 tmp := g.start;
  2084. 2077 (* Mark all segments as indirect to help LRU *)
  2085. 2078 REPEAT
  2086. 2079 WITH [tmp:0 T]^ DO
  2087. 2080 IF (Kind =StaticSeg) & (Lock=0) THEN
  2088. 2081 seghdr := SegPtr(HeapAdr(g.module_list[Id1]^.seg_info^[Id2]));
  2089. 2082 IF seghdr^.direct_list<>GatePtr(0) THEN
  2090. 2083 SetIndirect(seghdr);
  2091. 2084 END;
  2092. 2085 END; (*IF*)
  2093. 2086 INC(tmp,Size);
  2094. 2087 END; (*WITH*)
  2095. 2088 UNTIL tmp = g.start;
  2096. 2089 [MyCaller()-H:0 T]^.Tick := IncTick();
  2097. 2090 LOOP
  2098. 2091 ssize := 0;
  2099. 2092 maxage := 0;
  2100. 2093 tmp := g.start;
  2101. 2094 lru := 0;
  2102. 2095 REPEAT
  2103. 2096 WITH [tmp:0 T]^ DO
  2104. 2097 IF (Kind # MoveSeg) & (Lock=0) THEN
  2105. 2098 age := GetTick() - Tick;
  2106. 2099 IF (age >= maxage) THEN
  2107. 2100 lru := tmp;
  2108. 2101 maxage := age;
  2109. 2102 END; (*IF*)
  2110. 2103 END; (*IF*)
  2111. 2104 INC(tmp,Size);
  2112. 2105 END; (*WITH*)
  2113. 2106 UNTIL tmp = g.start;
  2114. 2107 IF lru # 0 THEN
  2115. 2108 WITH [lru:0 T]^ DO
  2116. 2109 ssize := Used;
  2117. 2110 DoSwap(lru);
  2118. 2111 (*%T UsageTrace*)
  2119. 2112 string('Age=');
  2120. 2113 dec(maxage);
  2121. 2114 string('Req=');
  2122. 2115 dec(req);
  2123. 2116 char(' ');
  2124. 2117 MemStat;
  2125. 2118 (*%E*)
  2126. 2119 IF ssize>=wants THEN
  2127. 2120 EXIT;
  2128. 2121 END;
  2129. 2122 DEC(wants,ssize);
  2130. 2123 END; (*WITH*)
  2131. 2124 ELSE
  2132. 2125 IF ssize=0 THEN
  2133. 2126 OutOfMem(req);
  2134. 2127 END;
  2135. 2128 EXIT;
  2136. 2129 END; (*IF*)
  2137. 2130 END; (*LOOP*)
  2138. 2131 END FlushLRU;
  2139. 2132
  2140. 2133
  2141. 2134
  2142. 2135 PROCEDURE Relocate(old,new:CARDINAL);
  2143. 2136 BEGIN
  2144. 2137 IF RelocateTrace THEN
  2145. 2138 string('Relocate ');
  2146. 2139 hex(old+H);
  2147. 2140 string(' to ');
  2148. 2141 hex(new+H);
  2149. 2142 eol;
  2150. 2143 END; (*IF*)
  2151. 2144 INC(new, H);
  2152. 2145 WITH [old:0 T]^ DO
  2153. 2146 CASE Kind OF
  2154. 2147 StaticSeg : (*%T VidSupport*)
  2155. 2148 TellVid(Id1,Id2,VID_UNLOAD_SEG);
  2156. 2149 (*%E*)
  2157. 2150 RelocStatic(SegPtr(HeapAdr(g.module_list[Id1]^.seg_info^[Id2])),new);
  2158. 2151 (*%T VidSupport*)
  2159. 2152 g.vid_delayed := TRUE;
  2160. 2153 g.vid_id1 := Id1;
  2161. 2154 g.vid_id2 := Id2;
  2162. 2155 (*%E*) |
  2163. 2156 MoveSeg,SwapSeg : [Id2:Id1 WP]^ := new; |
  2164. 2157 ELSE
  2165. 2158 abort(ErrInternal);
  2166. 2159 END; (*CASE*)
  2167. 2160 END; (*WITH*)
  2168. 2161 END Relocate;
  2169. 2162
  2170. 2163 (* Used to move relocatable block, No overlap *)
  2171. 2164 PROCEDURE SimpleMove(old,new:CARDINAL);
  2172. 2165 CONST
  2173. 2166 K = VSIZE(ParaRec.Prev);
  2174. 2167 VAR
  2175. 2168 size : CARDINAL;
  2176. 2169 BEGIN
  2177. 2170 Relocate(old,new);
  2178. 2171 size := [old:0 T]^.Used;
  2179. 2172 Move([old:K],[new:K],size*16-K);
  2180. 2173 (*%T VidSupport*)
  2181. 2174 TellVidMove;
  2182. 2175 (*%E*)
  2183. 2176 (*%T MemoryTrace*)
  2184. 2177 g.internal := TRUE;
  2185. 2178 (*%E*)
  2186. 2179 Free(old+H);
  2187. 2180 (*%T MemoryTrace*)
  2188. 2181 g.internal := FALSE;
  2189. 2182 (*%E*)
  2190. 2183 (*%T CHECK*)
  2191. 2184 CheckAlloc(new+H,0);
  2192. 2185 (*%E*)
  2193. 2186 END SimpleMove;
  2194. 2187
  2195. 2188 (* move segments in area (s..e) down *)
  2196. 2189 PROCEDURE Shuffle(s,e:CARDINAL);
  2197. 2190 VAR
  2198. 2191 old,new,diff,size : CARDINAL;
  2199. 2192 BEGIN
  2200. 2193 LOOP
  2201. 2194 WITH [s:0 T]^ DO
  2202. 2195 old := s + Size;
  2203. 2196 IF old = e THEN
  2204. 2197 EXIT;
  2205. 2198 END; (*IF*)
  2206. 2199 diff := Size - Used;
  2207. 2200 new := old - diff;
  2208. 2201 IF diff > 0 THEN
  2209. 2202 size := [old:0 T]^.Used;
  2210. 2203 Relocate(old,new);
  2211. 2204 (*%T MoveTrace *)
  2212. 2205 INC(g.move_total,LONGCARD(size*16));
  2213. 2206 (*%E*)
  2214. 2207 Move([old:0],[new:0],size*16);
  2215. 2208 (*%T VidSupport*)
  2216. 2209 TellVidMove;
  2217. 2210 (*%E*)
  2218. 2211 DEC(Size,diff);
  2219. 2212 WITH [new:0 T]^ DO
  2220. 2213 INC(Size,diff);
  2221. 2214 [new+Size:0 T]^.Prev := new;
  2222. 2215 END; (*WITH*)
  2223. 2216 (*%T CHECK*)
  2224. 2217 CheckAlloc(new+H,0);
  2225. 2218 (*%E*)
  2226. 2219 END; (*IF*)
  2227. 2220 s := new;
  2228. 2221 END; (*WITH*)
  2229. 2222 END; (*LOOP*)
  2230. 2223 END Shuffle;
  2231. 2224
  2232. 2225 PROCEDURE Get(req:CARDINAL):CARDINAL; FORWARD;
  2233. 2226
  2234. 2227 (* Choose a block of size < max to evacuate. We choose largest up to *)
  2235. 2228 (* aim, then smallest. Thus we search the range (res,max) until *)
  2236. 2229 (* size(res) >= aim then we search the range (aim,size(res)). *)
  2237. 2230 PROCEDURE Choose(s,e,aim,max:CARDINAL):CARDINAL;
  2238. 2231 VAR
  2239. 2232 res,min,size,poss : CARDINAL;
  2240. 2233 BEGIN
  2241. 2234 INC(s,[s:0 T]^.Size);
  2242. 2235 min := 0;
  2243. 2236 res := 0;
  2244. 2237 poss := 0;
  2245. 2238 WHILE s # e DO
  2246. 2239 WITH [s:0 T]^ DO
  2247. 2240 size := Used;
  2248. 2241 IF size < max THEN
  2249. 2242 INC(poss,size);
  2250. 2243 IF size > min THEN
  2251. 2244 res := s;
  2252. 2245 IF size >= aim THEN
  2253. 2246 min := aim;
  2254. 2247 max := size;
  2255. 2248 ELSE
  2256. 2249 min := size;
  2257. 2250 END; (*IF*)
  2258. 2251 END; (*IF*)
  2259. 2252 END; (*IF*)
  2260. 2253 INC(s,Size);
  2261. 2254 END; (*WITH*)
  2262. 2255 END; (*WHILE*)
  2263. 2256 IF poss < aim THEN
  2264. 2257 res := 0;
  2265. 2258 END; (*IF*)
  2266. 2259 RETURN res;
  2267. 2260 END Choose;
  2268. 2261
  2269. 2262 (* In decreasing size, evacuate segs in area s satisfying Used < lim, *)
  2270. 2263 (* until free space for s..e >= need *)
  2271. 2264 PROCEDURE Evac(s,e:CARDINAL;lim:CARDINAL;need:CARDINAL):BOOLEAN;
  2272. 2265 VAR
  2273. 2266 got,old,new,poss : CARDINAL;
  2274. 2267 res : BOOLEAN;
  2275. 2268 BEGIN
  2276. 2269 got := Got(s,e);
  2277. 2270 [s:0 T]^.Active := TRUE;
  2278. 2271 LOOP
  2279. 2272 IF got >= need THEN
  2280. 2273 res := TRUE;
  2281. 2274 EXIT;
  2282. 2275 ELSE
  2283. 2276 old := Choose(s,e,need-got,lim);
  2284. 2277 IF old = 0 THEN
  2285. 2278 res := FALSE;
  2286. 2279 EXIT;
  2287. 2280 END; (*IF*)
  2288. 2281 WITH [old:0 T]^ DO
  2289. 2282 lim := Used;
  2290. 2283 new := Get(lim);
  2291. 2284 IF new # 0 THEN
  2292. 2285 new := SplitLow(lim,new);
  2293. 2286 SimpleMove(old,new);
  2294. 2287 INC(got,lim);
  2295. 2288 INC(lim); (* others of same size are acceptable *)
  2296. 2289 END; (*IF*)
  2297. 2290 END; (*WITH*)
  2298. 2291 END; (*IF*)
  2299. 2292 END; (*LOOP*)
  2300. 2293 [s:0 T]^.Active := FALSE;
  2301. 2294 RETURN res;
  2302. 2295 END Evac;
  2303. 2296
  2304. 2297 PROCEDURE Get(req:CARDINAL):CARDINAL;
  2305. 2298 VAR
  2306. 2299 max,s,e,res : CARDINAL;
  2307. 2300 BEGIN
  2308. 2301 max := MaxPoss(req,s,e);
  2309. 2302 IF (max >= req) & Evac(s,e,req,req) THEN
  2310. 2303 Shuffle(s, e);
  2311. 2304 res := Try(req,s,e);
  2312. 2305 (*%T CHECK*)
  2313. 2306 IF res = 0 THEN
  2314. 2307 abort(ErrInternal);
  2315. 2308 END; (*IF*)
  2316. 2309 (*%E*)
  2317. 2310 ELSE
  2318. 2311 res := 0;
  2319. 2312 END; (*IF*)
  2320. 2313 RETURN res;
  2321. 2314 END Get;
  2322. 2315
  2323. 2316 (* Moves relocatable segments in range (s..e) up, thus increasing *)
  2324. 2317 (* s^.Size. *)
  2325. 2318 PROCEDURE ShuffleUp(s,e:CARDINAL);
  2326. 2319 VAR
  2327. 2320 w,p,new,diff : CARDINAL;
  2328. 2321 BEGIN
  2329. 2322 w := [e:0 T]^.Prev;
  2330. 2323 LOOP
  2331. 2324 IF w = s THEN
  2332. 2325 EXIT;
  2333. 2326 END; (*IF*)
  2334. 2327 WITH [w:0 T]^ DO
  2335. 2328 p := Prev;
  2336. 2329 diff := Size - Used;
  2337. 2330 new := w + diff;
  2338. 2331 IF (diff > 0) THEN
  2339. 2332 Relocate(w,new);
  2340. 2333 DEC(Size,diff);
  2341. 2334 [e:0 T]^.Prev := new;
  2342. 2335 INC([p:0 T]^.Size,diff);
  2343. 2336 (*%T MoveTrace *)
  2344. 2337 INC(g.move_total,LONGCARD(Used*16));
  2345. 2338 (*%E*)
  2346. 2339 MoveUp([w:0],[new:0],Used*16);
  2347. 2340 (*%T VidSupport*)
  2348. 2341 TellVidMove;
  2349. 2342 (*%E*)
  2350. 2343 END; (*IF*)
  2351. 2344 END; (*WITH*)
  2352. 2345 e := new;
  2353. 2346 w := p;
  2354. 2347 END; (*LOOP*)
  2355. 2348 (*%T CHECK*)
  2356. 2349 CheckMem;
  2357. 2350 (*%E*)
  2358. 2351 END ShuffleUp;
  2359. 2352
  2360. 2353 PROCEDURE IAlloc(size:CARDINAL;id1,id2:CARDINAL;kind:SegKind;high:BOOLEAN):CARDINAL;
  2361. 2354 VAR
  2362. 2355 s,e,sm,em,
  2363. 2356 use,res : CARDINAL;
  2364. 2357 BEGIN
  2365. 2358 (*%T CHECK*)
  2366. 2359 CheckMem;
  2367. 2360 (*%E*)
  2368. 2361 g.allockind := kind;
  2369. 2362 INC(size,H);
  2370. 2363 IF high THEN
  2371. 2364 LOOP (* decide area: last such that Poss(a) >= size *)
  2372. 2365 sm := 0;
  2373. 2366 s := g.start;
  2374. 2367 REPEAT
  2375. 2368 e := NextArea(s);
  2376. 2369 IF Poss(s,e,MAX(CARDINAL)) >= size THEN
  2377. 2370 sm := s;
  2378. 2371 em := e;
  2379. 2372 END; (*IF*)
  2380. 2373 s := e;
  2381. 2374 UNTIL s = g.start;
  2382. 2375 IF sm # 0 THEN
  2383. 2376 IF (TotalAvail() >= size) & Evac(sm,em,MAX(CARDINAL),size) THEN
  2384. 2377 Shuffle(sm,em);
  2385. 2378 use := Try(size,sm,em);
  2386. 2379 (*%T CHECK*)
  2387. 2380 IF use = 0 THEN
  2388. 2381 abort(ErrInternal);
  2389. 2382 END; (*IF*)
  2390. 2383 (*%E*)
  2391. 2384 EXIT;
  2392. 2385 END; (*IF*)
  2393. 2386 END; (*IF*)
  2394. 2387 FlushLRU(size);
  2395. 2388 END; (*LOOP*)
  2396. 2389 WITH [use:0 T]^ DO
  2397. 2390 DEC(Size,size);
  2398. 2391 res := use + Size;
  2399. 2392 END; (*WITH*)
  2400. 2393 WITH [res:0 T]^ DO
  2401. 2394 Size := size;
  2402. 2395 Used := size;
  2403. 2396 IF res # use THEN
  2404. 2397 Prev := use;
  2405. 2398 END; (*IF*)
  2406. 2399 [res+size:0 T]^.Prev := res;
  2407. 2400 END; (*WITH*)
  2408. 2401 DEC(g.freemem,size);
  2409. 2402 ELSE
  2410. 2403 LOOP
  2411. 2404 (*%T DEBUG*)
  2412. 2405 use := 0;
  2413. 2406 (*%E*)
  2414. 2407 (*%F DEBUG*)
  2415. 2408 use := Try(size,g.start,g.start);
  2416. 2409 (*%E*)
  2417. 2410 IF (use = 0) & (TotalAvail() >= size) THEN
  2418. 2411 use := Get(size);
  2419. 2412 END; (*IF*)
  2420. 2413 IF use # 0 THEN
  2421. 2414 EXIT;
  2422. 2415 END; (*IF*)
  2423. 2416 FlushLRU(size);
  2424. 2417 END; (*IF*)
  2425. 2418 res := SplitLow(size,use);
  2426. 2419 END; (*IF*)
  2427. 2420 WITH [res:0 T]^ DO
  2428. 2421 Id1 := id1;
  2429. 2422 Id2 := id2;
  2430. 2423 Kind := kind;
  2431. 2424 Active := FALSE;
  2432. 2425 Lock := 1;
  2433. 2426 Tick := IncTick();
  2434. 2427 END; (*WITH*)
  2435. 2428 INC(res,H);
  2436. 2429 DEC(size,H);
  2437. 2430 (*%T MemoryTrace*)
  2438. 2431 IF (kind IN MemTraceSet) THEN
  2439. 2432 TraceSeg('IAlloc',res);
  2440. 2433 END; (*IF*)
  2441. 2434 (*%E*)
  2442. 2435 (*%T Debuging*)
  2443. 2436 IF res = g.trap_alloc THEN
  2444. 2437 P;
  2445. 2438 END; (*IF*)
  2446. 2439 (*%E*)
  2447. 2440 (*%T CHECK*)
  2448. 2441 CheckAlloc(res,0);
  2449. 2442 CheckMem;
  2450. 2443 (*%E*)
  2451. 2444 RETURN res;
  2452. 2445 END IAlloc;
  2453. 2446
  2454. 2447 PROCEDURE AllocFixed(size:CARDINAL):CARDINAL;
  2455. 2448 BEGIN
  2456. 2449 RETURN IAlloc(size, 0, 0, FixedSeg, TRUE);
  2457. 2450 END AllocFixed;
  2458. 2451
  2459. 2452
  2460. 2453 PROCEDURE AllocMove(VAR seg:CARDINAL;size:CARDINAL);
  2461. 2454 VAR
  2462. 2455 a:ADDRESS;
  2463. 2456 res:CARDINAL;
  2464. 2457 BEGIN
  2465. 2458 a := ADR(seg);
  2466. 2459 res := IAlloc(size, Ofs(a^), Seg(a^), MoveSeg, FALSE);
  2467. 2460 UnLock(res);
  2468. 2461 seg := res;
  2469. 2462 END AllocMove;
  2470. 2463
  2471. 2464 PROCEDURE ReSize(VAR seg:CARDINAL;newsize:CARDINAL);
  2472. 2465 VAR
  2473. 2466 old,use,s,e:CARDINAL;
  2474. 2467 (*%T MemoryTrace*) easy:BOOLEAN; (*%E*)
  2475. 2468 BEGIN
  2476. 2469 (*%T MemoryTrace*) easy := TRUE; (*%E*)
  2477. 2470 g.allockind := MoveSeg;
  2478. 2471 INC(newsize,H);
  2479. 2472 LOOP
  2480. 2473 old := seg-H;
  2481. 2474 WITH [old:0 T]^ DO
  2482. 2475 IF Size >= newsize THEN
  2483. 2476 INC(g.freemem, Used);
  2484. 2477 DEC(g.freemem, newsize);
  2485. 2478 Used := newsize;
  2486. 2479 EXIT;
  2487. 2480 END;
  2488. 2481 (*%T MemoryTrace*) easy := FALSE; (*%E*)
  2489. 2482 use := Try(newsize, g.start, g.start);
  2490. 2483 IF use = 0 THEN
  2491. 2484 s := Find(old);
  2492. 2485 e := NextArea(s);
  2493. 2486 IF (newsize>1000H) &
  2494. 2487 (TotalAvail()>newsize-Used) &
  2495. 2488 Evac(s, e, Used, newsize-Used)
  2496. 2489 THEN
  2497. 2490 ShuffleUp(old, e);
  2498. 2491 Shuffle(s, old+Size);
  2499. 2492 (*%T CHECK*) IF [seg-H:0 T]^.Size < newsize THEN abort(ErrInternal); END; (*%E*)
  2500. 2493 ELSE
  2501. 2494 IF TotalAvail() >= newsize THEN
  2502. 2495 use := Get(newsize);
  2503. 2496 END;
  2504. 2497 IF use = 0 THEN
  2505. 2498 FlushLRU(newsize);
  2506. 2499 END;
  2507. 2500 END;
  2508. 2501 END;
  2509. 2502 IF use # 0 THEN
  2510. 2503 use := SplitLow(newsize, use);
  2511. 2504 SimpleMove(seg-H, use);
  2512. 2505 EXIT;
  2513. 2506 END;
  2514. 2507 END;
  2515. 2508 END;
  2516. 2509 (*%T MemoryTrace*)
  2517. 2510 IF (MoveSeg IN MemTraceSet) & (~easy) THEN
  2518. 2511 TraceSeg('ReSize',seg);
  2519. 2512 END;
  2520. 2513 (*%E*)
  2521. 2514 END ReSize;
  2522. 2515
  2523. 2516 PROCEDURE LoadMove(VAR seg:CARDINAL;size:CARDINAL);
  2524. 2517 VAR
  2525. 2518 tmp:CARDINAL;
  2526. 2519 BEGIN
  2527. 2520 tmp := seg;
  2528. 2521 IF ~ is_mem(tmp) THEN
  2529. 2522 AllocMove(seg, size);
  2530. 2523 TempXfer(Load, tmp, seg, 0, size*16);
  2531. 2524 ELSE
  2532. 2525 (*%T CHECK*) CheckAlloc(tmp,ErrInvalidVFix); (*%E*)
  2533. 2526 WITH [tmp-H:0 T]^ DO
  2534. 2527 (*%T CHECK*) IF (Kind # MoveSeg)
  2535. 2528 & (Kind # SwapSeg)
  2536. 2529 THEN abort(ErrInvalidVFix);
  2537. 2530 END;
  2538. 2531 (*%E*)
  2539. 2532 Kind := MoveSeg;
  2540. 2533 END;
  2541. 2534 END;
  2542. 2535 END LoadMove;
  2543. 2536
  2544. 2537
  2545. 2538 PROCEDURE LoadCode(seghdr:SegPtr):CARDINAL;
  2546. 2539 VAR
  2547. 2540 segment:CARDINAL;
  2548. 2541 modnum:ModNum;
  2549. 2542 module:Module;
  2550. 2543 segnum:SegNum;
  2551. 2544 BEGIN
  2552. 2545 segment := seghdr^.seg_val;
  2553. 2546 IF ~ is_mem(segment) THEN
  2554. 2547 modnum := 0;
  2555. 2548 LOOP
  2556. 2549 INC(modnum);
  2557. 2550 (*%T CHECK*) IF modnum > g.module_count THEN abort(ErrInternal); END; (*%E*)
  2558. 2551 module := g.module_list[modnum];
  2559. 2552 segnum := 1+(CARDINAL(seghdr)-CARDINAL(module^.seg_info)) DIV SIZE(SegRec);
  2560. 2553 IF segnum-1 < module^.seg_count THEN
  2561. 2554 EXIT;
  2562. 2555 END;
  2563. 2556 END;
  2564. 2557 segment := DoSeg(modnum, segnum, Load);
  2565. 2558 UnLock(segment);
  2566. 2559 ELSE
  2567. 2560 [segment-H:0 T]^.Tick := IncTick();
  2568. 2561 END;
  2569. 2562 RETURN segment;
  2570. 2563 END LoadCode;
  2571. 2564
  2572. 2565 PROCEDURE CallTrap(sd:CARDINAL;gd:CARDINAL):CARDINAL;
  2573. 2566 VAR
  2574. 2567 seghdr:SegPtr;
  2575. 2568 gate:GatePtr;
  2576. 2569 segment:CARDINAL;
  2577. 2570 BEGIN
  2578. 2571 gate := GatePtr(gd);
  2579. 2572 seghdr := SegPtr(sd);
  2580. 2573 segment := LoadCode(seghdr);
  2581. 2574 gate^.next_direct := seghdr^.direct_list;
  2582. 2575 seghdr^.direct_list := gate;
  2583. 2576 gate^.state := DirectGate;
  2584. 2577 gate^.w1 := gate^.w2;
  2585. 2578 gate^.w2 := segment;
  2586. 2579 RETURN CARDINAL(gate);
  2587. 2580 END CallTrap;
  2588. 2581
  2589. 2582 PROCEDURE ReturnTrap(sd:CARDINAL):CARDINAL;
  2590. 2583 VAR
  2591. 2584 seghdr : SegPtr;
  2592. 2585 BEGIN
  2593. 2586 seghdr := SegPtr(sd);
  2594. 2587 RETURN LoadCode(seghdr);
  2595. 2588 END ReturnTrap;
  2596. 2589
  2597. 2590 PROCEDURE DoSeg(modnum:ModNum;segnum:SegNum;op:DoSegOp):CARDINAL;
  2598. 2591 CONST
  2599. 2592 (* values for Fixup.lockind *)
  2600. 2593 FixOfs = 5;
  2601. 2594 FixBase = 2;
  2602. 2595 FixPtr = 3;
  2603. 2596 VAR
  2604. 2597 segment : CARDINAL;
  2605. 2598 TYPE
  2606. 2599 LocPtr = POINTER segment TO RECORD
  2607. 2600 lo,hi : CARDINAL;
  2608. 2601 END; (*LocPtr*)
  2609. 2602 set = SET OF [0..7];
  2610. 2603 Fixup = RECORD
  2611. 2604 lockind : SHORTCARD;
  2612. 2605 flags : SHORTCARD;
  2613. 2606 off : CARDINAL;
  2614. 2607 CASE :SHORTCARD OF
  2615. 2608 0 : target_mod : CARDINAL;
  2616. 2609 target_ent : CARDINAL; |
  2617. 2610 1 : target_seg : SegNum;
  2618. 2611 target_off : CARDINAL; |
  2619. 2612 END; (*CASE*)
  2620. 2613 END; (*Fixup*)
  2621. 2614 VAR
  2622. 2615 loc,next : LocPtr;
  2623. 2616 fixbuf : POINTER TO ARRAY [1..999] OF Fixup;
  2624. 2617 fix : Fixup;
  2625. 2618 fi : CARDINAL;
  2626. 2619 segsize : CARDINAL;
  2627. 2620 target_modnum : ModNum;
  2628. 2621 target_module : Module;
  2629. 2622 target_segment : CARDINAL;
  2630. 2623 target_attr : SegSet;
  2631. 2624 chain : BOOLEAN;
  2632. 2625 pos : LONGCARD;
  2633. 2626 fillcount : CARDINAL;
  2634. 2627 tempsize : CARDINAL;
  2635. 2628 gate : GatePtr;
  2636. 2629 target_seghdr : SegPtr;
  2637. 2630 module : Module;
  2638. 2631 seghdr : SegPtr;
  2639. 2632 (*%T VidSupport*)
  2640. 2633 vid_op : VidAction;
  2641. 2634 (*%E*)
  2642. 2635 LABEL
  2643. 2636 ordinal;
  2644. 2637
  2645. 2638 BEGIN
  2646. 2639 module := g.module_list[modnum];
  2647. 2640 (*%T VidSupport*)
  2648. 2641 IF op # Load THEN
  2649. 2642 TellVid(modnum,segnum,VID_UNLOAD_SEG);
  2650. 2643 END; (*IF*)
  2651. 2644 (*%E*)
  2652. 2645 seghdr := SegPtr(HeapAdr(module^.seg_info^[segnum]));
  2653. 2646 (*%T CHECK*)
  2654. 2647 IF (modnum > g.module_count)OR
  2655. 2648 (segnum > module^.seg_count) THEN
  2656. 2649 abort(ErrInternal);
  2657. 2650 END; (*IF*)
  2658. 2651 (*%E*)
  2659. 2652 (*%T LoadTrace *)
  2660. 2653 (*%F MemoryTrace*)
  2661. 2654 hex(g.freemem);
  2662. 2655 (*%E*)
  2663. 2656 (*%T MemoryTrace*)
  2664. 2657 string(' ');
  2665. 2658 (*%E*)
  2666. 2659 string(' ');
  2667. 2660 CASE op OF
  2668. 2661 |Load: string('Load: ');
  2669. 2662 |Swap: string('Swap: ');
  2670. 2663 |Discard: string('Discard: ');
  2671. 2664 END;
  2672. 2665 string(g.module_list[modnum]^.name^);
  2673. 2666 char('.');
  2674. 2667 hex(segnum);
  2675. 2668 string(' mem=');hex(seghdr^.membyte);
  2676. 2669 string(' dsk=');hex(seghdr^.filebyte);
  2677. 2670 string(' flags= ');
  2678. 2671 IF IsData IN seghdr^.flags THEN string('Data ') END;
  2679. 2672 IF IsIter IN seghdr^.flags THEN string('Iter ') END;
  2680. 2673 IF IsMove IN seghdr^.flags THEN string('Move ') END;
  2681. 2674 IF IsPure IN seghdr^.flags THEN string('Pure ') END;
  2682. 2675 IF IsPreLoad IN seghdr^.flags THEN string('PreLoad ') END;
  2683. 2676 IF IsExRd IN seghdr^.flags THEN string('ExRd ') END;
  2684. 2677 IF HasReloc IN seghdr^.flags THEN string('HasReloc ') END;
  2685. 2678 IF IsDiscard IN seghdr^.flags THEN string('Discard ') END;
  2686. 2679 IF DataActive IN seghdr^.flags THEN string('DataActive ') END;
  2687. 2680 eol;
  2688. 2681 (*%E*)
  2689. 2682 IF seghdr^.membyte=1 THEN (* zero length segment *)
  2690. 2683 IF op = Load THEN
  2691. 2684 [Seg(DoSeg)-1:0 T]^.Lock := 7FFFH;
  2692. 2685 RETURN Seg(DoSeg);
  2693. 2686 END;
  2694. 2687 RETURN 0;
  2695. 2688 END;
  2696. 2689 pos := LONGCARD(seghdr^.sector) << LONGCARD(module^.log_sector_size);
  2697. 2690 segsize := Para(seghdr^.membyte);
  2698. 2691 IF op = Load THEN
  2699. 2692 seghdr^.fix_count := 0;
  2700. 2693 IF (HasReloc IN seghdr^.flags) THEN
  2701. 2694 IF ModuleRead(module,pos+LONGCARD(seghdr^.filebyte),
  2702. 2695 ADR(seghdr^.fix_count),2) THEN
  2703. 2696 (*%T CHECK*)
  2704. 2697 abort(ErrOpenFail);
  2705. 2698 (*%E*)
  2706. 2699 END; (*IF*)
  2707. 2700 END;
  2708. 2701 segment := IAlloc(segsize+Para(seghdr^.fix_count*SIZE(fix)),modnum,segnum,StaticSeg,
  2709. 2702 seghdr^.flags * SegSet{IsData,IsPreLoad} # SegSet{});
  2710. 2703 IF ModuleRead(module,pos,[segment:0],seghdr^.filebyte) THEN
  2711. 2704 (*%T CHECK*)
  2712. 2705 abort(ErrOpenFail);
  2713. 2706 (*%E*)
  2714. 2707 END; (*IF*)
  2715. 2708 fixbuf := [segment+segsize:0];
  2716. 2709 IF seghdr^.fix_count>0 THEN (* read fixups *)
  2717. 2710 IF ModuleRead(module,pos+LONGCARD(seghdr^.filebyte)+2,
  2718. 2711 fixbuf,seghdr^.fix_count*SIZE(fix)) THEN
  2719. 2712 (*%T CHECK*)
  2720. 2713 abort(ErrOpenFail);
  2721. 2714 (*%E*)
  2722. 2715 END; (*IF*)
  2723. 2716 END;
  2724. 2717 (*%T GraphUseTrace*)
  2725. 2718 IF seghdr^.flags*SegSet{IsData,IsPreLoad}=SegSet{} THEN
  2726. 2719 GraphTrace(segnum+modnum*256,segment,GTadd);
  2727. 2720 END;
  2728. 2721 (*%E*)
  2729. 2722 ELSE
  2730. 2723 segment := seghdr^.seg_val;
  2731. 2724 fixbuf := [segment+segsize:0];
  2732. 2725 (*%T GraphUseTrace*)
  2733. 2726 IF seghdr^.flags*SegSet{IsData,IsPreLoad}=SegSet{} THEN
  2734. 2727 GraphTrace(segnum+modnum*256,segment,GTdel);
  2735. 2728 END;
  2736. 2729 (*%E*)
  2737. 2730 IF op = Swap THEN
  2738. 2731 IF (~(IsData IN seghdr^.flags)) & IsActive(seghdr) THEN
  2739. 2732 INCL(seghdr^.flags,DataActive);
  2740. 2733 END; (*IF*)
  2741. 2734 IF (SegSet{IsDiscard,IsExRd} * seghdr^.flags # SegSet{}) OR (modnum=g.delay) THEN
  2742. 2735 op := Discard;
  2743. 2736 END; (*IF*)
  2744. 2737 END; (*IF*)
  2745. 2738 END; (*IF*)
  2746. 2739 fillcount := seghdr^.membyte-seghdr^.filebyte;
  2747. 2740 IF ODD(fillcount) THEN
  2748. 2741 DEC(fillcount)
  2749. 2742 END; (*IF*) (* OK as always an extra byte! *)
  2750. 2743 TempXfer(op,seghdr^.seg_val,segment,seghdr^.filebyte,fillcount);
  2751. 2744 IF is_mem(segment) & (op # Load) THEN
  2752. 2745 SetIndirect(seghdr);
  2753. 2746 END; (*IF*)
  2754. 2747 IF (op = Swap) & (DataActive IN seghdr^.flags) THEN
  2755. 2748 (* do nothing *)
  2756. 2749 ELSIF seghdr^.fix_count=0 THEN
  2757. 2750 (* do nothing *)
  2758. 2751 ELSIF is_mem(segment) OR ((DataActive IN seghdr^.flags) & (op = Discard)) THEN
  2759. 2752 fi := 0;
  2760. 2753 WHILE fi<seghdr^.fix_count DO
  2761. 2754 INC(fi);
  2762. 2755 fix := fixbuf^[fi];
  2763. 2756 chain := ~(2 IN set(fix.flags));
  2764. 2757 fix.flags := fix.flags MOD 4;
  2765. 2758 IF fix.flags = 0 THEN (* internal fixup *)
  2766. 2759 target_modnum := modnum;
  2767. 2760 target_module := module;
  2768. 2761 IF fix.target_seg = 0FFH THEN
  2769. 2762 GOTO ordinal;
  2770. 2763 END; (*IF*)
  2771. 2764 ELSIF fix.flags = 1 THEN (* ordinal import *)
  2772. 2765 target_modnum := ModNum(module^.module_table^[fix.target_mod]);
  2773. 2766 target_module := g.module_list[target_modnum];
  2774. 2767 ordinal:
  2775. 2768 fix.target_seg := CARDINAL(target_module^.entry_table^[fix.target_ent].seg);
  2776. 2769 fix.target_off := target_module^.entry_table^[fix.target_ent].ofs;
  2777. 2770 ELSE
  2778. 2771 (*%T CHECK*)
  2779. 2772 abort(ErrNamedImport); (* named import not supported *)
  2780. 2773 (*%E*)
  2781. 2774 END; (*IF*)
  2782. 2775 target_seghdr := GetSeg(target_module, fix.target_seg);
  2783. 2776 target_attr := target_seghdr^.flags;
  2784. 2777 IF op = Load THEN
  2785. 2778 loc := LocPtr(fix.off);
  2786. 2779 IF ~chain THEN
  2787. 2780 INC(fix.target_off,loc^.lo);
  2788. 2781 END; (*IF*)
  2789. 2782 IF (fix.lockind = FixPtr) & (target_attr * SegSet{IsData,IsPreLoad} = SegSet{}) THEN
  2790. 2783 fix.target_off := Gate(fix.target_off,target_seghdr,TRUE);
  2791. 2784 target_segment := Seg(g);
  2792. 2785 ELSE
  2793. 2786 target_segment := target_seghdr^.seg_val;
  2794. 2787 IF ~is_mem(target_segment) THEN
  2795. 2788 target_segment := DoSeg(target_modnum,fix.target_seg,Load);
  2796. 2789 ELSIF (~(IsPreLoad IN target_seghdr^.flags)) & ~(DataActive IN seghdr^.flags) THEN
  2797. 2790 Lock(target_segment);
  2798. 2791 END; (*IF*)
  2799. 2792 END; (*IF*)
  2800. 2793 IF fix.lockind = FixOfs THEN
  2801. 2794 IF chain THEN
  2802. 2795 REPEAT
  2803. 2796 next := LocPtr(loc^.lo);
  2804. 2797 loc^.lo := fix.target_off;
  2805. 2798 loc := next;
  2806. 2799 UNTIL loc = LocPtr(0FFFFH);
  2807. 2800 ELSE
  2808. 2801 loc^.lo := fix.target_off;
  2809. 2802 END; (*IF*)
  2810. 2803 ELSIF fix.lockind = FixBase THEN
  2811. 2804 IF chain THEN
  2812. 2805 REPEAT
  2813. 2806 next := LocPtr(loc^.lo);
  2814. 2807 loc^.lo := target_segment;
  2815. 2808 loc := next;
  2816. 2809 UNTIL loc = LocPtr(0FFFFH);
  2817. 2810 ELSE
  2818. 2811 loc^.lo := target_segment;
  2819. 2812 END; (*IF*)
  2820. 2813 ELSE
  2821. 2814 IF chain THEN
  2822. 2815 REPEAT
  2823. 2816 next := LocPtr(loc^.lo);
  2824. 2817 loc^.lo := fix.target_off;
  2825. 2818 loc^.hi := target_segment;
  2826. 2819 loc := next;
  2827. 2820 UNTIL loc = LocPtr(0FFFFH);
  2828. 2821 ELSE
  2829. 2822 loc^.lo := fix.target_off;
  2830. 2823 loc^.hi := target_segment;
  2831. 2824 END; (*IF*)
  2832. 2825 END; (*IF*)
  2833. 2826 ELSE (* unloading *)
  2834. 2827 IF (fix.lockind = FixPtr) & (target_attr * SegSet{IsData,IsPreLoad} = SegSet{}) THEN
  2835. 2828 (* do nothing *)
  2836. 2829 ELSIF IsPreLoad IN target_attr THEN
  2837. 2830 (* do nothing *)
  2838. 2831 ELSE
  2839. 2832 target_segment := target_seghdr^.seg_val;
  2840. 2833 IF is_mem(target_segment) THEN
  2841. 2834 UnLock(target_segment);
  2842. 2835 END; (*IF*)
  2843. 2836 END; (*IF*)
  2844. 2837 END; (*IF*)
  2845. 2838 END; (*WHILE*)
  2846. 2839 EXCL(seghdr^.flags,DataActive);
  2847. 2840 END; (*IF*)
  2848. 2841 (*%T VidSupport*)
  2849. 2842 IF op = Load THEN
  2850. 2843 TellVid(modnum,segnum,VID_LOAD_SEG);
  2851. 2844 END; (*IF*)
  2852. 2845 (*%E*)
  2853. 2846 IF op = Load THEN
  2854. 2847 RETURN segment;
  2855. 2848 ELSE
  2856. 2849 Free(segment);
  2857. 2850 RETURN 0;
  2858. 2851 END; (*IF*)
  2859. 2852 END DoSeg;
  2860. 2853
  2861. 2854
  2862. 2855 (* Virtual Segments - dynamically allocated segments that can be unlocked *)
  2863. 2856
  2864. 2857 PROCEDURE VAlloc(VAR addr : FarADDRESS; size : CARDINAL);
  2865. 2858 (* Allocates Virtual memory block of specified size (in bytes).
  2866. 2859 returns result in addr.
  2867. 2860 Block is initially fixed so VUnfix must be called before
  2868. 2861 it can be swapped out.
  2869. 2862 Address of addr is used as handle so only one variable must be used
  2870. 2863 to hold pointer.
  2871. 2864 *)
  2872. 2865 VAR ptr : POINTER TO ARRAY[0..1] OF CARDINAL;
  2873. 2866 BEGIN
  2874. 2867 ptr := ADR(addr);
  2875. 2868 AllocMove(ptr^[1],Para(size));
  2876. 2869 Lock(ptr^[1]);
  2877. 2870 ptr^[0] := 0;
  2878. 2871 END VAlloc;
  2879. 2872
  2880. 2873 PROCEDURE VUnfix(VAR addr : FarADDRESS);
  2881. 2874 (*
  2882. 2875 Unfixes memory allowing it to be moved or swapped to EMS or disk if
  2883. 2876 memory runs low. The address should not be used to reference memory
  2884. 2877 when unfixed.
  2885. 2878 *)
  2886. 2879 VAR ptr : POINTER TO ARRAY[0..1] OF CARDINAL;
  2887. 2880 BEGIN
  2888. 2881 ptr := ADR(addr);
  2889. 2882 (*%T CHECK*)
  2890. 2883 IF (ptr^[0]<>0)OR(~is_mem(ptr^[1]))OR([ptr^[1]-H:0 T]^.Kind<>MoveSeg) OR
  2891. 2884 (NOT Locked(ptr^[1])) THEN
  2892. 2885 abort(ErrInvalidVUnfix);
  2893. 2886 END;
  2894. 2887 (*%E*)
  2895. 2888 [ptr^[1]-H:0 T]^.Tick := IncTick(); (* LRU now, otherwise could get old while fixed *)
  2896. 2889 UnLock(ptr^[1]);
  2897. 2890 IF NOT Locked(ptr^[1]) THEN
  2898. 2891 ptr^[0] := [ptr^[1]-H:0 T]^.Size-H;
  2899. 2892 SwapMove(ptr^[1]);
  2900. 2893 END;
  2901. 2894 END VUnfix;
  2902. 2895
  2903. 2896 PROCEDURE VFix(VAR addr : FarADDRESS);
  2904. 2897 (*
  2905. 2898 Swaps block back into memory if necessary and
  2906. 2899 fixes the address so it can be used.
  2907. 2900 Calls to FixVSeg and UnfixVSeg may be nested.
  2908. 2901 *)
  2909. 2902 VAR ptr : POINTER TO ARRAY[0..1] OF CARDINAL;
  2910. 2903 BEGIN
  2911. 2904 ptr := ADR(addr);
  2912. 2905 IF ptr^[0]=0 THEN
  2913. 2906 (*%T CHECK*)
  2914. 2907 IF (([ptr^[1]-H:0 T]^.Kind<>MoveSeg) AND ([ptr^[1]-H:0 T]^.Kind<>SwapSeg))OR
  2915. 2908 ([ptr^[1]-H:0 T]^.Lock=0) THEN
  2916. 2909 abort(ErrInvalidVFix);
  2917. 2910 END;
  2918. 2911 (*%E*)
  2919. 2912 ELSE
  2920. 2913 (*%T CHECK*)
  2921. 2914 IF is_mem(ptr^[1]) AND ([ptr^[1]-H:0 T]^.Kind<>MoveSeg)
  2922. 2915 AND ([ptr^[1]-H:0 T]^.Kind<>SwapSeg) THEN
  2923. 2916 abort(ErrInvalidVFix);
  2924. 2917 END;
  2925. 2918 (*%E*)
  2926. 2919 LoadMove(ptr^[1],ptr^[0]);
  2927. 2920 ptr^[0] := 0;
  2928. 2921 END;
  2929. 2922 Lock(ptr^[1]);
  2930. 2923 END VFix;
  2931. 2924
  2932. 2925 PROCEDURE VFree(VAR addr : FarADDRESS);
  2933. 2926 (* frees virtual memory block
  2934. 2927 can be called only when segment fixed
  2935. 2928 addr is reset to NIL on exit
  2936. 2929 *)
  2937. 2930 VAR ptr : POINTER TO ARRAY[0..1] OF CARDINAL;
  2938. 2931 BEGIN
  2939. 2932 VFix(addr);
  2940. 2933 ptr := ADR(addr);
  2941. 2934 WHILE Locked(ptr^[1]) DO
  2942. 2935 UnLock(ptr^[1]);
  2943. 2936 END;
  2944. 2937 Free(ptr^[1]);
  2945. 2938 addr := FarNIL;
  2946. 2939 END VFree;
  2947. 2940
  2948. 2941
  2949. 2942 PROCEDURE VUnfixAll();
  2950. 2943 (* Equivalent to calling VUnfix for all Virtual addresses allocated *)
  2951. 2944 VAR s : CARDINAL;
  2952. 2945 TYPE ap = POINTER TO ADDRESS;
  2953. 2946 BEGIN
  2954. 2947 s := g.start;
  2955. 2948 REPEAT
  2956. 2949 IF [s:0 T]^.Kind=MoveSeg THEN
  2957. 2950 WHILE Locked(s+H) DO
  2958. 2951 VUnfix([[s:0 T]^.Id1:[s:0 T]^.Id2 ap]^); (* cannot upset loop *)
  2959. 2952 END;
  2960. 2953 END;
  2961. 2954 INC(s,[s:0 T]^.Size);
  2962. 2955 UNTIL s = g.start;
  2963. 2956 END VUnfixAll;
  2964. 2957
  2965. 2958
  2966. 2959
  2967. 2960 (* Tiny Allocation - (smaller overhead for upto 127 bytes) *)
  2968. 2961
  2969. 2962
  2970. 2963 CONST
  2971. 2964 TinyMax = 16;
  2972. 2965 TinyGranularity = 8;
  2973. 2966 TinyMaxSize = TinyMax*TinyGranularity-1;
  2974. 2967 TinyGranularityLog2 = 3;
  2975. 2968 VAR
  2976. 2969 TinyFreeList : ARRAY[1..TinyMax] OF CARDINAL;
  2977. 2970
  2978. 2971 PROCEDURE TinyAlloc(size : CARDINAL):FarADDRESS;
  2979. 2972 (* only called for allocations of 1 to TinyMaxSize *)
  2980. 2973 VAR
  2981. 2974 csize,i,seg : CARDINAL;
  2982. 2975 BEGIN
  2983. 2976 csize := (size+(TinyGranularity-1))DIV TinyGranularity;
  2984. 2977 seg := TinyFreeList[csize];
  2985. 2978 IF seg=MAX(CARDINAL) THEN
  2986. 2979 seg := AllocFixed(csize*TinyGranularity);
  2987. 2980 IF seg=0 THEN RETURN FarNIL END;
  2988. 2981 DEC(seg);
  2989. 2982 [seg:0 T]^.Id1 := MAX(CARDINAL);
  2990. 2983 [seg:0 T]^.Id2 := TinyFreeList[csize];
  2991. 2984 TinyFreeList[csize] := seg;
  2992. 2985 END;
  2993. 2986 (*%T CHECK*)
  2994. 2987 IF ([seg:0 T]^.Id1=0) THEN
  2995. 2988 END;
  2996. 2989 (*%E*)
  2997. 2990 i := 0;
  2998. 2991 WHILE NOT (i IN BITSET([seg:0 T]^.Id1)) DO INC(i) END;
  2999. 2992 EXCL(BITSET([seg:0 T]^.Id1),i);
  3000. 2993 IF [seg:0 T]^.Id1=0 THEN
  3001. 2994 TinyFreeList[csize] := [seg:0 T]^.Id2;
  3002. 2995 END;
  3003. 2996 RETURN [seg+1:i*csize*TinyGranularity];
  3004. 2997 END TinyAlloc;
  3005. 2998
  3006. 2999 PROCEDURE TinyFree(p:FarADDRESS): BOOLEAN;
  3007. 3000 VAR
  3008. 3001 seg,csize,i : CARDINAL;
  3009. 3002 BEGIN
  3010. 3003 seg := Seg(p^)-1;
  3011. 3004 WITH [seg:0 T]^ DO
  3012. 3005 IF (Kind<>FixedSeg)OR(Id2=0) THEN RETURN FALSE END;
  3013. 3006 csize := (Used-1)DIV TinyGranularity;
  3014. 3007 i := CARDINAL(p)DIV(csize*TinyGranularity);
  3015. 3008 (*%T CHECK*)
  3016. 3009 IF (csize=0)OR(csize>TinyMax)OR(i IN BITSET(Id1))OR
  3017. 3010 (i*csize*TinyGranularity<>CARDINAL(p)) THEN
  3018. 3011 abort(ErrInvalidFree);
  3019. 3012 END;
  3020. 3013 CheckAlloc(seg+1,ErrInvalidFree);
  3021. 3014 (*%E*)
  3022. 3015 IF Id1=0 THEN
  3023. 3016 Id2 := TinyFreeList[csize];
  3024. 3017 TinyFreeList[csize] := seg;
  3025. 3018 END;
  3026. 3019 INCL(BITSET(Id1),i);
  3027. 3020 END;
  3028. 3021 RETURN TRUE;
  3029. 3022 END TinyFree;
  3030. 3023
  3031. 3024
  3032. 3025
  3033. 3026 PROCEDURE TinyFlush;
  3034. 3027 (* called occasionally to clean up tiny chains *)
  3035. 3028 VAR
  3036. 3029 prev,ptr,next,i : CARDINAL;
  3037. 3030 BEGIN
  3038. 3031 FOR i := 1 TO TinyMax DO
  3039. 3032 prev := MAX(CARDINAL);
  3040. 3033 ptr := TinyFreeList[i];
  3041. 3034 WHILE ptr<>MAX(CARDINAL) DO
  3042. 3035 WITH [ptr:0 T]^ DO
  3043. 3036 next := Id2;
  3044. 3037 IF Id1=MAX(CARDINAL) THEN
  3045. 3038 IF prev=MAX(CARDINAL) THEN
  3046. 3039 TinyFreeList[i] := next;
  3047. 3040 ELSE
  3048. 3041 [prev:0 T]^.Id2 := next;
  3049. 3042 END;
  3050. 3043 Id1 := 0;
  3051. 3044 Id2 := 0;
  3052. 3045 Free(ptr+1);
  3053. 3046 ELSE
  3054. 3047 prev := ptr;
  3055. 3048 END;
  3056. 3049 END;
  3057. 3050 ptr := next;
  3058. 3051 END;
  3059. 3052 END;
  3060. 3053 END TinyFlush;
  3061. 3054
  3062. 3055 PROCEDURE TinyInit;
  3063. 3056 VAR i : CARDINAL;
  3064. 3057 BEGIN
  3065. 3058 FOR i := 1 TO TinyMax DO
  3066. 3059 TinyFreeList[i] := MAX(CARDINAL);
  3067. 3060 END;
  3068. 3061 END TinyInit;
  3069. 3062
  3070. 3063 TYPE
  3071. 3064 ExeHeader = RECORD
  3072. 3065 magic1,magic2 : CHAR;
  3073. 3066 link_version : SHORTCARD;
  3074. 3067 link_revision : SHORTCARD;
  3075. 3068 entry_table_off : CARDINAL;
  3076. 3069 entry_table_size : CARDINAL;
  3077. 3070 crc : LONGCARD;
  3078. 3071 flag : CARDINAL;
  3079. 3072 dgroup : CARDINAL;
  3080. 3073 small_heap_size : CARDINAL;
  3081. 3074 small_stack_size : CARDINAL;
  3082. 3075 ip,cs,sp,ss : CARDINAL;
  3083. 3076 seg_count : CARDINAL;
  3084. 3077 lib_count : CARDINAL;
  3085. 3078 non_res_name_size : CARDINAL;
  3086. 3079 seg_off : CARDINAL;
  3087. 3080 resource_off : CARDINAL;
  3088. 3081 res_name_off : CARDINAL;
  3089. 3082 module_ref_off : CARDINAL;
  3090. 3083 imp_name_off : CARDINAL;
  3091. 3084 non_res_name_off : LONGCARD;
  3092. 3085 mov_entry_count : CARDINAL;
  3093. 3086 log_sector_size : CARDINAL;
  3094. 3087 reserved : ARRAY [0..11] OF SHORTCARD;
  3095. 3088 END; (*ExeHeader*)
  3096. 3089
  3097. 3090
  3098. 3091 TYPE InitProc = PROCEDURE():CARDINAL;
  3099. 3092
  3100. 3093 PROCEDURE InternalLoadModule(name:ARRAY OF CHAR;is_exe:BOOLEAN;stage:ModStage):CARDINAL;
  3101. 3094
  3102. 3095 VAR
  3103. 3096 modnum : ModNum;
  3104. 3097 module : Module;
  3105. 3098 len : CARDINAL;
  3106. 3099 hpos : LONGCARD;
  3107. 3100 hdr : ExeHeader;
  3108. 3101 i : CARDINAL;
  3109. 3102 libname : ARRAY [0..255] OF CHAR;
  3110. 3103 bundle : RECORD
  3111. 3104 ne : SHORTCARD;
  3112. 3105 si : SHORTCARD;
  3113. 3106 END; (*bundle*)
  3114. 3107 fs : RECORD
  3115. 3108 flags : SHORTCARD;
  3116. 3109 off : CARDINAL;
  3117. 3110 END; (*fs*)
  3118. 3111 fs6 : RECORD
  3119. 3112 flags : SHORTCARD;
  3120. 3113 int3 : CARDINAL;
  3121. 3114 seg : SHORTCARD;
  3122. 3115 off : CARDINAL;
  3123. 3116 END; (*fs6*)
  3124. 3117 eseg : SHORTCARD;
  3125. 3118 eoff : CARDINAL;
  3126. 3119 SecondPass : BOOLEAN;
  3127. 3120 epass : SHORTCARD[0..1];
  3128. 3121 done : CARDINAL;
  3129. 3122 ord : CARDINAL;
  3130. 3123 cs : CARDINAL;
  3131. 3124 p : InitProc;
  3132. 3125 impnameoff : CARDINAL;
  3133. 3126 dummy : CARDINAL;
  3134. 3127 submod : CARDINAL;
  3135. 3128 substage : ModStage;
  3136. 3129 pss : CARDINAL;
  3137. 3130 buf_index : CARDINAL;
  3138. 3131 buffer : ARRAY [0..511] OF SHORTCARD;
  3139. 3132
  3140. 3133 PROCEDURE Read2(a:ADDRESS;count:CARDINAL);
  3141. 3134 VAR
  3142. 3135 avail : CARDINAL;
  3143. 3136 BEGIN
  3144. 3137 LOOP
  3145. 3138 avail := SIZE(buffer) - buf_index;
  3146. 3139 IF avail > count THEN
  3147. 3140 avail := count;
  3148. 3141 END; (*IF*)
  3149. 3142 Move(ADR(buffer[buf_index]),a,avail);
  3150. 3143 INC(buf_index,avail);
  3151. 3144 DEC(count,avail);
  3152. 3145 IF count = 0 THEN
  3153. 3146 EXIT;
  3154. 3147 END; (*IF*)
  3155. 3148 INC(CARDINAL(a),avail);
  3156. 3149 FileRead(ADR(buffer),SIZE(buffer),module^.file);
  3157. 3150 buf_index := 0;
  3158. 3151 END; (*LOOP*)
  3159. 3152 END Read2;
  3160. 3153
  3161. 3154 PROCEDURE Seek2(pos:LONGCARD);
  3162. 3155 BEGIN
  3163. 3156 buf_index := SIZE(buffer);
  3164. 3157 FileSeek(module^.file,pos);
  3165. 3158 END Seek2;
  3166. 3159
  3167. 3160 PROCEDURE Read(pos:LONGCARD;a:ADDRESS;count:CARDINAL):BOOLEAN;
  3168. 3161 BEGIN
  3169. 3162 buf_index := SIZE(buffer);
  3170. 3163 RETURN ModuleRead(module,pos,a,count);
  3171. 3164 END Read;
  3172. 3165
  3173. 3166 BEGIN
  3174. 3167 modnum := 1;
  3175. 3168 LOOP
  3176. 3169 IF modnum > g.module_count THEN
  3177. 3170 module := New(SIZE(module^));
  3178. 3171 len := Length(name) + 1;
  3179. 3172 module^.name := New(len);
  3180. 3173 Append(module^.name^,name);
  3181. 3174 IF modnum > MaxModule THEN
  3182. 3175 abort(ErrModuleLimit);
  3183. 3176 END; (*IF*)
  3184. 3177 g.module_count := modnum; (* should be check for > MaxModule *)
  3185. 3178 g.module_list[modnum] := module;
  3186. 3179 module^.file := MAX(CARDINAL);
  3187. 3180 module^.is_exe := is_exe;
  3188. 3181 (*%T GraphUseTrace*)
  3189. 3182 string('Module ');hex(modnum);string(' = ');string(name);eol;
  3190. 3183 (*%E*)
  3191. 3184 EXIT;
  3192. 3185 END; (*IF*)
  3193. 3186 module := g.module_list[modnum];
  3194. 3187 IF Compare(module^.name^,name) & (module^.is_exe = is_exe) THEN
  3195. 3188 EXIT;
  3196. 3189 END; (*IF*)
  3197. 3190 INC(modnum);
  3198. 3191 END; (*LOOP*)
  3199. 3192 IF module^.stage < stage THEN
  3200. 3193 (* read header *)
  3201. 3194 IF Read(3CH,ADR(hpos),SIZE(hpos)) OR Read(hpos,ADR(hdr),SIZE(hdr)) OR (hdr.magic1 # 'N') THEN
  3202. 3195 RETURN 0;
  3203. 3196 END; (*IF*)
  3204. 3197 REPEAT
  3205. 3198 INC(module^.stage);
  3206. 3199 CASE module^.stage OF
  3207. 3200 internal_stage (* verify header, build basic tables, allocate module table *)
  3208. 3201 :(* allocate module table *)
  3209. 3202 module^.module_table := New(hdr.lib_count * 2);
  3210. 3203 (* build segment table *)
  3211. 3204 module^.seg_count := hdr.seg_count;
  3212. 3205 module^.log_sector_size := hdr.log_sector_size;
  3213. 3206 module^.seg_info := New(hdr.seg_count * SIZE(SegRec));
  3214. 3207 Seek2(hpos + LONGCARD(hdr.seg_off));
  3215. 3208 buf_index := SIZE(buffer);
  3216. 3209 FOR i := 1 TO hdr.seg_count DO
  3217. 3210 WITH module^.seg_info^[i] DO
  3218. 3211 Read2(ADR(sector),8);
  3219. 3212 no_op := 90H;
  3220. 3213 jump_op := 0E9H;
  3221. 3214 jump_disp := CARDINAL(HeapAdr(LoaderA.GateHandler)) - CARDINAL(HeapAdr(jump_disp)) - 2;
  3222. 3215 END; (*WITH*)
  3223. 3216 END; (*FOR*)
  3224. 3217 (* build entry table *)
  3225. 3218 IF EntryTableTrace THEN
  3226. 3219 string('entry table for ');
  3227. 3220 string(module^.name^);
  3228. 3221 eol;
  3229. 3222 END; (*IF*)
  3230. 3223 FOR SecondPass := FALSE TO TRUE DO
  3231. 3224 Seek2(hpos + LONGCARD(hdr.entry_table_off));
  3232. 3225 ord := 0;
  3233. 3226 done := 0;
  3234. 3227 WHILE done < hdr.entry_table_size DO
  3235. 3228 Read2(ADR(bundle),2);
  3236. 3229 INC(done,2);
  3237. 3230 FOR i := 1 TO CARDINAL(bundle.ne) DO
  3238. 3231 INC(ord);
  3239. 3232 IF bundle.si = 255 THEN
  3240. 3233 Read2(ADR(fs6),SIZE(fs6));
  3241. 3234 INC(done,SIZE(fs6));
  3242. 3235 eseg := fs6.seg;
  3243. 3236 eoff := fs6.off;
  3244. 3237 ELSE
  3245. 3238 Read2(ADR(fs), SIZE(fs));
  3246. 3239 INC(done, SIZE(fs));
  3247. 3240 eseg := bundle.si;
  3248. 3241 eoff := fs.off;
  3249. 3242 END; (*IF*)
  3250. 3243 IF SecondPass THEN
  3251. 3244 module^.entry_table^[ord].seg := eseg;
  3252. 3245 module^.entry_table^[ord].ofs := eoff;
  3253. 3246 IF EntryTableTrace THEN
  3254. 3247 dec(ord);
  3255. 3248 char('=');
  3256. 3249 dec(CARDINAL(module^.entry_table^[ord].seg));
  3257. 3250 char(':');
  3258. 3251 hex(CARDINAL(module^.entry_table^[ord].ofs));
  3259. 3252 eol;
  3260. 3253 END; (*IF*)
  3261. 3254 END; (*IF*)
  3262. 3255 END; (*FOR*)
  3263. 3256 END; (*WHILE*)
  3264. 3257 IF ~SecondPass THEN
  3265. 3258 module^.entry_table := New(ord * SIZE(EntryRec));
  3266. 3259 END; (*IF*)
  3267. 3260 END; (*FOR*) |
  3268. 3261 sub_module_stage (* fill in module table, initialise sub-modules up to stage 2 *)
  3269. 3262 : FOR i := 1 TO hdr.lib_count DO
  3270. 3263 len := 0;
  3271. 3264 IF Read(hpos+LONGCARD(hdr.module_ref_off+(i-1)*2),ADR(impnameoff),SIZE(impnameoff)) OR Read(hpos+LONGCARD(hdr.imp_name_off+impnameoff),ADR(len),1) THEN
  3272. 3265 RETURN 0;
  3273. 3266 END; (*IF*)
  3274. 3267 Read2(ADR(libname),len);
  3275. 3268 libname[len] := 0C;
  3276. 3269 submod := InternalLoadModule(libname,FALSE,sub_module_stage);
  3277. 3270 IF submod = 0 THEN
  3278. 3271 RETURN 0;
  3279. 3272 END;(*IF*)
  3280. 3273 module^.module_table^[i] := SHORTCARD(submod);
  3281. 3274 END; (*FOR*) |
  3282. 3275 execute_stage (* execute sub-module entry points *)
  3283. 3276 :
  3284. 3277 FOR i := 1 TO hdr.lib_count DO
  3285. 3278 submod := CARDINAL(module^.module_table^[i]);
  3286. 3279 IF InternalLoadModule(g.module_list[submod]^.name^,FALSE,execute_stage) = 0 THEN
  3287. 3280 RETURN 0;
  3288. 3281 END; (*IF*)
  3289. 3282 END; (*FOR*)
  3290. 3283 (*%T VidSupport*)
  3291. 3284 TellVid(modnum,0,VID_LOAD_MODULE);
  3292. 3285 (*%E*)
  3293. 3286 (* execute entry-point *)
  3294. 3287 cs := DoSeg(modnum,hdr.cs,Load);
  3295. 3288 (* UnLock(cs); -- only if not packed *)
  3296. 3289 IF is_exe THEN
  3297. 3290 pss := DoSeg(modnum,hdr.ss,Load);
  3298. 3291 WITH [g.stk-1:0 T]^ DO
  3299. 3292 INC([Prev:0 T]^.Size,800H);
  3300. 3293 [g.stk-1+Size:0 T]^.Prev := Prev;
  3301. 3294 INC(g.freemem,800H);
  3302. 3295 END; (*WITH*)
  3303. 3296 Exec(g.psp,pss,hdr.sp,cs,hdr.ip);
  3304. 3297 ELSE
  3305. 3298 p := InitProc([cs:hdr.ip]);
  3306. 3299 dummy := p();
  3307. 3300 END; (*IF*)
  3308. 3301 END; (*CASE*)
  3309. 3302 UNTIL module^.stage = stage;
  3310. 3303 END; (*IF*)
  3311. 3304 RETURN modnum;
  3312. 3305 END InternalLoadModule;
  3313. 3306
  3314. 3307 PROCEDURE LoadModule (name:ARRAY OF CHAR):CARDINAL;
  3315. 3308 VAR
  3316. 3309 modnum:CARDINAL;
  3317. 3310 BEGIN
  3318. 3311 IF (g.delay=0) OR Compare(g.module_list[g.delay]^.name^, name) THEN
  3319. 3312 g.delay := 0;
  3320. 3313 ELSE
  3321. 3314 DoDelay;
  3322. 3315 END;
  3323. 3316 modnum := InternalLoadModule(name,FALSE,execute_stage);
  3324. 3317 IF modnum = 0 THEN
  3325. 3318 modnum := MAX(CARDINAL); (* external convention *)
  3326. 3319 END;
  3327. 3320 RETURN modnum;
  3328. 3321 END LoadModule;
  3329. 3322
  3330. 3323 PROCEDURE GetProcAddr (modnum:CARDINAL;entry: ARRAY OF CHAR):ADDRESS;
  3331. 3324 VAR s : SHORTCARD;
  3332. 3325 str : ARRAY [0..255] OF CHAR;
  3333. 3326 ord : CARDINAL;
  3334. 3327 a :FarADDRESS;
  3335. 3328 Nonres : BOOLEAN;
  3336. 3329 module : Module;
  3337. 3330 hpos : LONGCARD;
  3338. 3331 hdr : ExeHeader;
  3339. 3332 i : CARDINAL;
  3340. 3333 BEGIN
  3341. 3334 module := g.module_list[modnum];
  3342. 3335 IF ModuleRead(module,3CH,ADR(hpos),SIZE(hpos))OR
  3343. 3336 ModuleRead(module,hpos,ADR(hdr),SIZE(hdr)) THEN
  3344. 3337 RETURN FarNIL;
  3345. 3338 END;
  3346. 3339 FileSeek(module^.file,hpos+LONGCARD(hdr.res_name_off));
  3347. 3340 ord := 0;
  3348. 3341 Nonres := FALSE;
  3349. 3342 LOOP
  3350. 3343 FileRead(ADR(s),1,module^.file);
  3351. 3344 IF s=0 THEN
  3352. 3345 IF Nonres THEN
  3353. 3346 EXIT;
  3354. 3347 ELSE
  3355. 3348 Nonres := TRUE;
  3356. 3349 FileSeek(module^.file,hdr.non_res_name_off);
  3357. 3350 END;
  3358. 3351 ELSE
  3359. 3352 FileRead(ADR(str),CARDINAL(s),module^.file);
  3360. 3353 str[CARDINAL(s)]:= 0C;
  3361. 3354 FileRead(ADR(ord),2,module^.file);
  3362. 3355 i := 0;
  3363. 3356 WHILE (str[i]=entry[i]) DO
  3364. 3357 INC(i);
  3365. 3358 IF (i=CARDINAL(s)) THEN
  3366. 3359 IF (entry[i]=0C) THEN EXIT END;
  3367. 3360 str[i] := 0C;
  3368. 3361 END;
  3369. 3362 END;
  3370. 3363 END;
  3371. 3364 END;
  3372. 3365 IF ord=0 THEN RETURN FarNIL END;
  3373. 3366 RETURN GetOrdProcAddr(modnum,ord);
  3374. 3367 END GetProcAddr;
  3375. 3368
  3376. 3369 PROCEDURE FlushAll;
  3377. 3370 BEGIN
  3378. 3371 DoDelay;
  3379. 3372 DoFlushAll;
  3380. 3373 END FlushAll;
  3381. 3374
  3382. 3375
  3383. 3376 PROCEDURE Terminate;
  3384. 3377 BEGIN
  3385. 3378 (*%T ExitTrace*)
  3386. 3379 eol;
  3387. 3380 IF TraceToFile THEN
  3388. 3381 FlushAll;
  3389. 3382 DumpMemory;
  3390. 3383 eol;
  3391. 3384 END; (*IF*)
  3392. 3385 MemStat;
  3393. 3386 string('Gate count = ');
  3394. 3387 dec(g.gate_count);
  3395. 3388 eol;
  3396. 3389 string('Module count = ');
  3397. 3390 dec(g.module_count);
  3398. 3391 eol;
  3399. 3392 (*%T EMS*)
  3400. 3393 string('Ems pages = ');
  3401. 3394 dec(g.ems_count);
  3402. 3395 eol;
  3403. 3396 (*%E*)
  3404. 3397 string('Heap used = ');
  3405. 3398 hex(g.near_alloc-CARDINAL(Ofs(g.heap)));
  3406. 3399 char('H');
  3407. 3400 eol;
  3408. 3401 string('Temp file = ');
  3409. 3402 hex(g.temp_max*(TempPageSize DIV 256));
  3410. 3403 string('00H');
  3411. 3404 eol;
  3412. 3405 (*%E*)
  3413. 3406
  3414. 3407 FileClose(g.temp_file);
  3415. 3408 FileDelete(FullTempFileName);
  3416. 3409 (*%T EMS*)
  3417. 3410 IF g.ems_data_handle # 0 THEN
  3418. 3411 EmsMap(4500H,0,g.ems_data_handle); (* free pages *)
  3419. 3412 END; (*IF*)
  3420. 3413 IF g.ems_temp_handle # 0 THEN
  3421. 3414 EmsMap(4500H,0,g.ems_temp_handle); (* free temp pages *)
  3422. 3415 END; (*IF*)
  3423. 3416 (*%E*)
  3424. 3417 END Terminate;
  3425. 3418
  3426. 3419 PROCEDURE AllocMem(size:CARDINAL):FarADDRESS;
  3427. 3420 BEGIN
  3428. 3421 IF size = 0 THEN
  3429. 3422 RETURN FarNIL;
  3430. 3423 END; (*IF*)
  3431. 3424 IF size<=TinyMaxSize THEN
  3432. 3425 RETURN TinyAlloc(size);
  3433. 3426 END;
  3434. 3427 RETURN [AllocFixed(Para(size)):0];
  3435. 3428 END AllocMem;
  3436. 3429
  3437. 3430 PROCEDURE FreeMem(ofs,seg:CARDINAL);
  3438. 3431 BEGIN
  3439. 3432 IF NOT TinyFree([seg:ofs]) THEN
  3440. 3433 Free(seg);
  3441. 3434 END;
  3442. 3435 END FreeMem;
  3443. 3436
  3444. 3437 PROCEDURE ClearAllocMem(num,size:CARDINAL):FarADDRESS;
  3445. 3438 VAR
  3446. 3439 res : FarADDRESS;
  3447. 3440 BEGIN
  3448. 3441 size := num * size;
  3449. 3442 IF size = 0 THEN
  3450. 3443 RETURN FarNIL;
  3451. 3444 END; (*IF*)
  3452. 3445 IF size<=TinyMaxSize THEN
  3453. 3446 res := TinyAlloc(size);
  3454. 3447 ELSE
  3455. 3448 res := [AllocFixed(Para(size)):0];
  3456. 3449 END;
  3457. 3450 IF res<>FarNIL THEN
  3458. 3451 Fill(res,size,0);
  3459. 3452 END;
  3460. 3453 RETURN res;
  3461. 3454 END ClearAllocMem;
  3462. 3455
  3463. 3456 PROCEDURE HugeAllocMem(size:LONGCARD):FarADDRESS;
  3464. 3457 BEGIN
  3465. 3458 RETURN [AllocFixed(CARDINAL((size+15) DIV 16)):0];
  3466. 3459 END HugeAllocMem;
  3467. 3460
  3468. 3461 PROCEDURE ExpandMem(Buffer:FarADDRESS;newsize:CARDINAL):FarADDRESS;
  3469. 3462 VAR
  3470. 3463 seg,next : CARDINAL;
  3471. 3464 BEGIN
  3472. 3465 seg := Seg(Buffer^) - H;
  3473. 3466 newsize := Para(newsize) + H;
  3474. 3467 LOOP
  3475. 3468 WITH [seg:0 T]^ DO
  3476. 3469 IF Size >= newsize THEN
  3477. 3470 INC(g.freemem,Used);
  3478. 3471 DEC(g.freemem,newsize);
  3479. 3472 Used := newsize;
  3480. 3473 RETURN Buffer;
  3481. 3474 ELSE
  3482. 3475 next := seg + Size;
  3483. 3476 IF [next:0 T]^.Used = 0 THEN
  3484. 3477 INC(Size,[next:0 T]^.Size);
  3485. 3478 next := seg + Size;
  3486. 3479 [next:0 T]^.Prev := seg;
  3487. 3480 ELSE
  3488. 3481 RETURN FarNIL;
  3489. 3482 END; (*IF*)
  3490. 3483 END; (*IF*)
  3491. 3484 END; (*WITH*)
  3492. 3485 END; (*LOOP*)
  3493. 3486 END ExpandMem;
  3494. 3487
  3495. 3488 PROCEDURE HugeExpandMem(Buffer:FarADDRESS;newsize:LONGCARD):FarADDRESS;
  3496. 3489 VAR
  3497. 3490 seg,next,NewCard : CARDINAL;
  3498. 3491 BEGIN
  3499. 3492 seg := Seg(Buffer^) - H;
  3500. 3493 NewCard := CARDINAL((newsize + 15) DIV 16) + H;
  3501. 3494 LOOP
  3502. 3495 WITH [seg:0 T]^ DO
  3503. 3496 IF Size >= NewCard THEN
  3504. 3497 INC(g.freemem,Used);
  3505. 3498 DEC(g.freemem,NewCard);
  3506. 3499 Used := NewCard;
  3507. 3500 RETURN Buffer;
  3508. 3501 ELSE
  3509. 3502 next := seg + Size;
  3510. 3503 IF [next:0 T]^.Used = 0 THEN
  3511. 3504 INC(Size,[next:0 T]^.Size);
  3512. 3505 next := seg + Size;
  3513. 3506 [next:0 T]^.Prev := seg;
  3514. 3507 ELSE
  3515. 3508 RETURN FarNIL;
  3516. 3509 END; (*IF*)
  3517. 3510 END; (*IF*)
  3518. 3511 END; (*WITH*)
  3519. 3512 END; (*LOOP*)
  3520. 3513 END HugeExpandMem;
  3521. 3514
  3522. 3515 PROCEDURE InvalidProc;
  3523. 3516 BEGIN
  3524. 3517 abort(ErrInvalidProcedure);
  3525. 3518 END InvalidProc;
  3526. 3519
  3527. 3520
  3528. 3521 CONST
  3529. 3522 HEAPOK = 0;
  3530. 3523 HEAPEMPTY = -1;
  3531. 3524 HEAPBADBEGIN = -2;
  3532. 3525 HEAPBADNODE = -3;
  3533. 3526 HEAPOVERFLOW = -4;
  3534. 3527 HEAPEND = -5;
  3535. 3528 HEAPBADPTR = -6;
  3536. 3529
  3537. 3530 PROCEDURE HeapCheck(Val:CARDINAL;DoFill:BOOLEAN):INTEGER;
  3538. 3531 VAR
  3539. 3532 TSeg : CARDINAL;
  3540. 3533 BEGIN
  3541. 3534 TSeg := g.start;
  3542. 3535 REPEAT
  3543. 3536 WITH [TSeg:0 T]^ DO
  3544. 3537 IF Size = 0 THEN
  3545. 3538 RETURN HEAPBADNODE;
  3546. 3539 END; (*IF*)
  3547. 3540 IF DoFill & (Used < Size) THEN
  3548. 3541 Fill([TSeg+Used:0],(Size-Used)*16,Val);
  3549. 3542 END; (*IF*)
  3550. 3543 INC(TSeg,Size);
  3551. 3544 END; (*WITH*)
  3552. 3545 UNTIL TSeg = g.start;
  3553. 3546 RETURN HEAPOK;
  3554. 3547 END HeapCheck;
  3555. 3548
  3556. 3549 PROCEDURE HeapWalk(VAR Entry:HeapInfo):INTEGER;
  3557. 3550 BEGIN
  3558. 3551 WITH Entry DO
  3559. 3552 IF pentry = FarNIL THEN
  3560. 3553 pentry := [g.start:0];
  3561. 3554 ELSE
  3562. 3555 pentry := [Seg(pentry^) + T(pentry)^.Size:0];
  3563. 3556 END; (*IF*)
  3564. 3557 WITH T(pentry)^ DO
  3565. 3558 IF Seg(pentry^) = g.start THEN
  3566. 3559 RETURN HEAPEND;
  3567. 3560 END; (*IF*)
  3568. 3561 IF Size = 0 THEN
  3569. 3562 RETURN HEAPBADNODE;
  3570. 3563 ELSE
  3571. 3564 size := Size * 16;
  3572. 3565 END; (*IF*)
  3573. 3566 useflag := Used > 0;
  3574. 3567 END; (*WITH*)
  3575. 3568 END; (*WITH*)
  3576. 3569 RETURN HEAPOK;
  3577. 3570 END HeapWalk;
  3578. 3571
  3579. 3572 (*# save,call(reg_param=>(bx,ax),reg_saved=>(cx,dx,di,si,ds,st1,st2),inline=>on)*)
  3580. 3573 PROCEDURE DOSAllocMem(Para:CARDINAL):CARDINAL = A4(0B4H,048H,0CDH,021H);
  3581. 3574 PROCEDURE DOSResizeMem(Para,Seg:CARDINAL) = A6(08EH,0C0H,0B4H,04AH,0CDH,021H);
  3582. 3575 PROCEDURE DOSFreeMem(Para:CARDINAL) = A6(08EH,0C3H,0B4H,049H,0CDH,021H);
  3583. 3576 (*# call(reg_return=>(bx))*)
  3584. 3577 PROCEDURE DOSMemAvail():CARDINAL = A7(0B4H,048H,0BBH,0FFH,0FFH,0CDH,021H);
  3585. 3578 (*# restore *)
  3586. 3579
  3587. 3580 VAR
  3588. 3581 AvailMem,AvailSeg : CARDINAL;
  3589. 3582 HighMem,HighSeg : CARDINAL;
  3590. 3583
  3591. 3584 PROCEDURE ShrinkHeap():CARDINAL;
  3592. 3585 BEGIN
  3593. 3586 FlushAll;
  3594. 3587 AvailMem := Avail();
  3595. 3588 IF AvailMem>800H THEN DEC(AvailMem,800H); END; (* needed to reload caller *)
  3596. 3589 AvailSeg := AllocFixed(AvailMem);
  3597. 3590 DOSResizeMem((AvailSeg + AvailMem) - g.psp - 1,g.psp);
  3598. 3591 HighMem := DOSMemAvail();
  3599. 3592 HighSeg := DOSAllocMem(HighMem);
  3600. 3593 DOSResizeMem(AvailSeg - g.psp,g.psp);
  3601. 3594 RETURN 0;
  3602. 3595 END ShrinkHeap;
  3603. 3596
  3604. 3597 PROCEDURE GrowHeap;
  3605. 3598 BEGIN
  3606. 3599 DOSFreeMem(HighSeg);
  3607. 3600 DOSResizeMem((AvailSeg + AvailMem + HighMem) - g.psp,g.psp);
  3608. 3601 Free(AvailSeg);
  3609. 3602 END GrowHeap;
  3610. 3603
  3611. 3604 PROCEDURE UserFlush;
  3612. 3605 BEGIN
  3613. 3606 FlushAll;
  3614. 3607 END UserFlush;
  3615. 3608
  3616. 3609 PROCEDURE SetExitHandler(p:ExitHandler);
  3617. 3610 BEGIN
  3618. 3611 g.abort := p;
  3619. 3612 reserve_panic;
  3620. 3613 END SetExitHandler;
  3621. 3614
  3622. 3615 PROCEDURE SetMemHandler(p:MemHandler);
  3623. 3616 BEGIN
  3624. 3617 g.OutOfMem := p;
  3625. 3618 END SetMemHandler;
  3626. 3619
  3627. 3620 PROCEDURE LoadSeg(segno:CARDINAL;ModName:ARRAY OF CHAR):SegReturn;
  3628. 3621 VAR
  3629. 3622 modno : CARDINAL;
  3630. 3623 BEGIN
  3631. 3624 modno := 1;
  3632. 3625 IF ModName[0] # 0C THEN
  3633. 3626 LOOP
  3634. 3627 IF Compare(g.module_list[modno]^.name^,ModName) THEN
  3635. 3628 EXIT;
  3636. 3629 END; (*IF*)
  3637. 3630 INC(modno);
  3638. 3631 IF modno > g.module_count THEN
  3639. 3632 RETURN INVALID_MOD;
  3640. 3633 END; (*IF*)
  3641. 3634 END; (*LOOP*)
  3642. 3635 END; (*IF*)
  3643. 3636 WITH g.module_list[modno]^ DO
  3644. 3637 IF segno > seg_count THEN
  3645. 3638 RETURN INVALID_SEG;
  3646. 3639 ELSIF seg_info^[segno].direct_list # GatePtr(0) THEN
  3647. 3640 RETURN RESIDENT;
  3648. 3641 ELSIF DoSeg(modno,segno,Load) # 0 THEN
  3649. 3642 RETURN SUCCESS;
  3650. 3643 ELSE
  3651. 3644 RETURN FAIL;
  3652. 3645 END; (*IF*)
  3653. 3646 END; (*WITH*)
  3654. 3647 END LoadSeg;
  3655. 3648
  3656. 3649 PROCEDURE UnloadSeg(segno:CARDINAL;ModName:ARRAY OF CHAR):SegReturn;
  3657. 3650 VAR
  3658. 3651 modno : CARDINAL;
  3659. 3652 BEGIN
  3660. 3653 modno := 1;
  3661. 3654 IF ModName[0] # 0C THEN
  3662. 3655 LOOP
  3663. 3656 IF Compare(g.module_list[modno]^.name^,ModName) THEN
  3664. 3657 EXIT;
  3665. 3658 END; (*IF*)
  3666. 3659 INC(modno);
  3667. 3660 IF modno > g.module_count THEN
  3668. 3661 RETURN INVALID_MOD;
  3669. 3662 END; (*IF*)
  3670. 3663 END; (*LOOP*)
  3671. 3664 END; (*IF*)
  3672. 3665 WITH g.module_list[modno]^ DO
  3673. 3666 IF segno > seg_count THEN
  3674. 3667 RETURN INVALID_SEG;
  3675. 3668 ELSIF seg_info^[segno].direct_list = GatePtr(0) THEN
  3676. 3669 RETURN UNLOADED;
  3677. 3670 ELSIF DoSeg(modno,segno,Swap) = 0 THEN
  3678. 3671 RETURN SUCCESS;
  3679. 3672 ELSE
  3680. 3673 RETURN FAIL;
  3681. 3674 END; (*IF*)
  3682. 3675 END; (*WITH*)
  3683. 3676 END UnloadSeg;
  3684. 3677
  3685. 3678 PROCEDURE Getseg(seg:CARDINAL):CARDINAL;
  3686. 3679 VAR
  3687. 3680 i,j : CARDINAL;
  3688. 3681 BEGIN
  3689. 3682 FOR i := 1 TO g.module_count DO
  3690. 3683 WITH g.module_list[i]^ DO
  3691. 3684 FOR j := 1 TO seg_count DO
  3692. 3685 WITH seg_info^[j] DO
  3693. 3686 IF seg_val = seg THEN
  3694. 3687 RETURN j;
  3695. 3688 END; (*IF*)
  3696. 3689 END; (*WITH*)
  3697. 3690 END; (*FOR*)
  3698. 3691 END; (*WITH*)
  3699. 3692 END; (*FOR*)
  3700. 3693 RETURN 0;
  3701. 3694 END Getseg;
  3702. 3695
  3703. 3696
  3704. 3697 (*# save, call(same_ds=>off) *)
  3705. 3698 PROCEDURE default_abort(name:ARRAY OF CHAR;errno:CARDINAL);
  3706. 3699 (*# restore *)
  3707. 3700 BEGIN
  3708. 3701 eol;
  3709. 3702 (*%T CHECK*)
  3710. 3703 string('Loader fatal error : ');
  3711. 3704 dec(errno);
  3712. 3705 string(', ');
  3713. 3706 (*%E*)
  3714. 3707 CASE errno-ErrBase OF (* only startup errors should be possible *)
  3715. 3708 ErrTempCreate : string('Failed to create ');
  3716. 3709 string(FullTempFileName); |
  3717. 3710 ErrLoad : string('DLL load failed. Is your PATH set correctly?');|
  3718. 3711 (* happens when ts.exe in local directory but path not set up *)
  3719. 3712 ErrOutOfMem: string('Out of memory');|
  3720. 3713 ErrTempDiskFull: string('Disk full on swap file');|
  3721. 3714 (*%T CHECK*)
  3722. 3715 ErrTempFileLimit : string('ErrTempFileLimit'); |
  3723. 3716 ErrPoolLimit : string('ErrPoolLimit'); |
  3724. 3717 ErrGateLimit : string('ErrGateLimit'); |
  3725. 3718 ErrDiskFull : string('ErrDiskFull'); |
  3726. 3719 ErrInternal : string('ErrInternal'); |
  3727. 3720 ErrNearHeap : string('ErrNearHeap'); |
  3728. 3721 ErrModuleLimit : string('ErrModuleLimit'); |
  3729. 3722 ErrInvalidProcedure : string('ErrInvalidProcedure'); |
  3730. 3723 ErrMemoryCorruption : string('ErrMemoryCorruption'); |
  3731. 3724 ErrTooManyUnlocks : string('ErrTooManyUnlocks'); |
  3732. 3725 ErrCallChainInvalid : string('ErrCallChainInvalid'); |
  3733. 3726 ErrOpenFail : string('ErrOpenFail'); |
  3734. 3727 ErrNamedImport : string('ErrNamedImport'); |
  3735. 3728 ErrInvalidVUnfix : string('ErrInvalidVUnfix'); |
  3736. 3729 ErrInvalidVFix : string('ErrInvalidVFix'); |
  3737. 3730 ErrInvalidFree : string('ErrInvalidFree'); |
  3738. 3731 END;
  3739. 3732 (*%E*)
  3740. 3733 (*%F CHECK*)
  3741. 3734 ELSE
  3742. 3735 string('Overlay loader fatal error : ');
  3743. 3736 dec(errno);
  3744. 3737 END; (*CASE*)
  3745. 3738 (*%E*)
  3746. 3739 eol;
  3747. 3740 END default_abort;
  3748. 3741
  3749. 3742 (*# save, call(same_ds=>off) *)
  3750. 3743 PROCEDURE default_MemHandler(Size:CARDINAL):BOOLEAN;
  3751. 3744 (*# restore *)
  3752. 3745 BEGIN
  3753. 3746 RETURN FALSE;
  3754. 3747 END default_MemHandler;
  3755. 3748
  3756. 3749 PROCEDURE Init(psp:CARDINAL); FORWARD;
  3757. 3750
  3758. 3751 (* Note this proc is overwritten by memory initialisation !! *)
  3759. 3752 PROCEDURE GetFullTempFileName(s:ARRAY OF CHAR);
  3760. 3753 VAR
  3761. 3754 drive : SHORTCARD;
  3762. 3755 p : ARRAY SHORTCARD OF CHAR;
  3763. 3756 BEGIN
  3764. 3757 drive := GetCurDrive();
  3765. 3758 GetCurDir(0,p);
  3766. 3759 s[0] := CHR(drive + ORD('A'));
  3767. 3760 IF p[0] = 0C THEN
  3768. 3761 s[2] := 0C;
  3769. 3762 ELSE
  3770. 3763 s[3] := 0C;
  3771. 3764 Append(s,p);
  3772. 3765 END; (*IF*)
  3773. 3766 Append(s,TempFileName);
  3774. 3767 END GetFullTempFileName;
  3775. 3768
  3776. 3769 PROCEDURE MakeSys(seg:CARDINAL);
  3777. 3770 VAR next,prev:CARDINAL;
  3778. 3771 BEGIN
  3779. 3772 (* links seg into memory list, initialises it to be a free seg *)
  3780. 3773 next := g.start;
  3781. 3774 LOOP
  3782. 3775 prev := [next:0 T]^.Prev;
  3783. 3776 IF seg <= g.start THEN
  3784. 3777 g.start := seg;
  3785. 3778 EXIT;
  3786. 3779 END;
  3787. 3780 IF prev <= seg THEN
  3788. 3781 EXIT;
  3789. 3782 END;
  3790. 3783 next := prev;
  3791. 3784 END;
  3792. 3785 WITH [next:0 T]^ DO
  3793. 3786 Prev := seg;
  3794. 3787 END;
  3795. 3788 WITH [prev:0 T]^ DO
  3796. 3789 Size := seg-prev;
  3797. 3790 Used := seg-prev;
  3798. 3791 END;
  3799. 3792 WITH [seg:0 T]^ DO
  3800. 3793 Size := next - seg;
  3801. 3794 Used := next - seg;
  3802. 3795 Prev := prev;
  3803. 3796 Active := FALSE;
  3804. 3797 Kind := SystemSeg;
  3805. 3798 Id1 := 0;
  3806. 3799 Id2 := 0;
  3807. 3800 Lock := 1;
  3808. 3801 END;
  3809. 3802 END MakeSys;
  3810. 3803
  3811. 3804 PROCEDURE Init(psp:CARDINAL);
  3812. 3805 VAR
  3813. 3806 m : CARDINAL;
  3814. 3807 code : CARDINAL;
  3815. 3808 cp : POINTER TO ARRAY [0..255] OF CHAR;
  3816. 3809 i : CARDINAL;
  3817. 3810 drive : SHORTCARD;
  3818. 3811 LABEL
  3819. 3812 NoEms;
  3820. 3813 BEGIN
  3821. 3814 Fill(ADR(g),SIZE(g),0);
  3822. 3815 TinyInit;
  3823. 3816 (*%T TraceToFile*)
  3824. 3817 output_file := FileCreate('otrace.txt');
  3825. 3818 (*%E*)
  3826. 3819 (*%T VidSupport*)
  3827. 3820 FindVid;
  3828. 3821 (*%E*)
  3829. 3822 (*%T GraphUseTrace*)
  3830. 3823 Fill(ADR(graphsegs),SIZE(graphsegs),0);
  3831. 3824 (*%E*)
  3832. 3825
  3833. 3826 g.abort := default_abort;
  3834. 3827 g.OutOfMem := default_MemHandler;
  3835. 3828 g.near_alloc := CARDINAL(Ofs(g.heap));
  3836. 3829 GetFullTempFileName(FullTempFileName);
  3837. 3830 (*#save,data(const_assign=>on)*)
  3838. 3831 g.temp_file := FileCreateNew(FullTempFileName);
  3839. 3832 (*#restore*)
  3840. 3833 IF g.temp_file = MAX(CARDINAL) THEN
  3841. 3834 abort(ErrTempCreate);
  3842. 3835 RETURN;
  3843. 3836 END; (*IF*)
  3844. 3837 g.psp := psp;
  3845. 3838 code := Seg(Main) - H;
  3846. 3839 g.stk := Seg(psp) + 2;
  3847. 3840 g.end := CARDINAL([g.psp:2]^) - H;
  3848. 3841 g.start := code - 1;
  3849. 3842 [g.start:0 T]^.Prev := g.start;
  3850. 3843 MakeSys(code-1);
  3851. 3844 MakeSys(code);
  3852. 3845 MakeSys(g.stk-1);
  3853. 3846 MakeSys(g.end);
  3854. 3847 WITH [g.stk-1:0 T]^ DO
  3855. 3848 Used := 0800H;
  3856. 3849 INC(g.freemem,Size-Used);
  3857. 3850 END; (*WITH*)
  3858. 3851 [g.stk:0]^ := 0;
  3859. 3852 WITH loader_module.seg_info^[1] DO
  3860. 3853 membyte := Ofs(Init);
  3861. 3854 jump_disp := CARDINAL(HeapAdr(LoaderA.GateHandler)) - CARDINAL(HeapAdr(jump_disp)) - 2;
  3862. 3855 seg_val := code + H;
  3863. 3856 END; (*WITH*)
  3864. 3857 WITH [code:0 T]^ DO (* will overwrite program entry ! *)
  3865. 3858 Kind := StaticSeg;
  3866. 3859 Id1 := 1;
  3867. 3860 Id2 := 1;
  3868. 3861 END; (*WITH*)
  3869. 3862 g.module_count := 1;
  3870. 3863 g.module_list[1] := Module(HeapAdr(loader_module));
  3871. 3864 (*%T CHECK*)
  3872. 3865 CheckMem;
  3873. 3866 (*%E*)
  3874. 3867 reserve_panic;
  3875. 3868 (* get ems frame *)
  3876. 3869 g.ems_frame := 0E000H; (* dummy value when no ems *)
  3877. 3870 (*%T EMS*)
  3878. 3871 cp := [[0:19CH+2]^:0AH];
  3879. 3872 FOR i := 0 TO 7 DO
  3880. 3873 IF cp^[i] # EmsName[i] THEN
  3881. 3874 GOTO NoEms;
  3882. 3875 END; (*IF*)
  3883. 3876 END; (*FOR*)
  3884. 3877 IF EmsTest(4000H) = 0 THEN
  3885. 3878 g.ems_frame := EmsGet(4100H); (* get frame *)
  3886. 3879 g.ems_present := TRUE;
  3887. 3880 END; (*IF*)
  3888. 3881 (*%E*)
  3889. 3882 NoEms:
  3890. 3883 m := InternalLoadModule(MainName,TRUE,execute_stage);
  3891. 3884 (* returns only if error *)
  3892. 3885 abort(ErrLoad);
  3893. 3886 END Init;
  3894. 3887
  3895. 3888 PROCEDURE Main(psp:CARDINAL);
  3896. 3889 BEGIN
  3897. 3890 Init(psp);
  3898. 3891 END Main;
  3899. 3892
  3900. 3893 END Loader.
  3901. 3894
  3902. 6 errors