implementation-guide.mss 131 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165
  1. @make(article)
  2. @Case(Draft, 1 <@device(Omnitech)>,
  3. else <@device(LPT)>
  4. )
  5. @Comment{ For use with the final versions }
  6. @Style(WidowAction=warn)
  7. @Style(Hyphenation Off) @comment(on)
  8. @Style(DoubleSided no) @comment(yes)
  9. @style(Spacing 1, LeftMargin 1.2 Inch)
  10. @comment[See G:MSS-junk.MSS]
  11. @use(Bibliography "<griss.docs>mtlisp.bib")
  12. @comment{ Font related stuff }
  13. @Define(OP,FaceCode Y,TabExport)@comment{ used for indicating opcodes in
  14. C-macros }
  15. @modify(enumerate,numbered=<@a. @,@i. >, spread 1)
  16. @modify(itemize,spread 1)
  17. @modify(description,leftmargin +2.0 inch,indent -2.0 inch)
  18. @LibraryFile(PSLMacrosNames)
  19. @LibraryFile(SpecialCharacters)
  20. @comment{ The logos and other fancy macros }
  21. @PageHeading(Left "Utah Symbolic Computation Group",
  22. Right "May 1982",
  23. Line "Operating Note No. xx"
  24. )
  25. @set(page=1)
  26. @newpage()
  27. @Begin(TitlePage)
  28. @begin(TitleBox)
  29. @MajorHeading(@PSL Implementation Guide)
  30. @Heading(M. L. Griss, E. Benson, R. Kessler, S. Lowder,
  31. G. Q. Maguire, Jr. and J. W. Peterson)
  32. Utah Symbolic Computation Group
  33. Computer Science Department
  34. University of Utah
  35. Salt Lake City, Utah 84112
  36. (801)-581-5017
  37. Last Update: @value(date)
  38. @end(TitleBox)
  39. @begin(abstract)
  40. This note describes the steps involved in bringing PSL up on a new
  41. machine. It combines information from the previous BOOTSTRAP, LAP,
  42. CMACRO and TEST guides.
  43. @end(abstract)
  44. @center[
  45. File: @Value(SourceFile)
  46. Printed: @value(date)]
  47. @copyrightnotice(Griss, Benson, Lowder, Maguire and Peterson)
  48. @begin(ResearchCredit)
  49. Work supported in part by the National Science Foundation under Grant
  50. No. MCS80-07034, and by Livermore Lawrence Laboratories under
  51. Subcontract No. 7752601, IBM and HP.
  52. @end(ResearchCredit)
  53. @end(TitlePage)
  54. @pageheading(Left "Implementation Guide", Center "@value(date)",
  55. Right "Page @Value(Page)"
  56. ) @comment{@pageheading(Even,Left "Page @Value(Page)",
  57. Right "Operating Note No. xx"
  58. )} @set(page=1) @newpage()
  59. @section(Introduction)
  60. This document describes the techniques used to implement PSL on a new
  61. machine. This note assumes that the reader has some familiarity with
  62. the basic strategy of @PSL implementation (see the 1982 LISP Conference
  63. Paper on PSL, UCP-83), and has also read the papers on the @PSL Portable
  64. @xlisp compiler (Griss and Hearn, "Software Practice and Experience",
  65. and Griss, Hearn and Benson, 1982 Compiler Conference). Also see the
  66. compiler chapter (19) of the @PSL manual@cite[Griss81]. Finally, a
  67. basic understanding of how to use PSL and LISP is required@cite[Griss81].
  68. In order to explain a new PSL implementation, we will first describe the
  69. PSL compilation model, hopefully providing some insight into the various
  70. steps involved in the transformation of PSL sources into code executable
  71. on the target machine. @comment{May want to add a description of each
  72. section to follow}
  73. The initial level of transformation takes the RLISP format and
  74. translates it into LISP for those source files that are written in RLISP
  75. format; those files already in LISP may be directly input into the
  76. system (see the figure below). The LISP code is then compiled into
  77. instructions for an Abstract Lisp Machine (ALM). The ALM is a
  78. general-purpose register machine designed for its ease as a target for
  79. compilation@cite(Griss81b) in which temporary variables are allocated in
  80. a block of locations on a @ei[stack]. The ALM instructions are
  81. expressed in LAP format (LISP Assembly Program) which
  82. consists of a list whose first element is the ALM opecode
  83. followed by zero or more ALM operands which are ALM addressing
  84. modes. The ALM format is (ALMopcode ALMoperand ... ALMoperand).
  85. The ALMopcode is a macro referred to as a CMACRO and the
  86. addressing modes of the ALMoperands are referred to as ANYRegs.
  87. The ALM instructions are macro expanded into instructions for the Target Lisp
  88. Machine (TLM). TLM instructions have the same LAP format, except the
  89. operators are now TLM operators and the operands are TLM addressing modes.
  90. From here, a number of alternate routes are possible for the final code
  91. generation. So far the LISP or RLISP has transformed into
  92. into a set of TLM instructions that can take one of three paths.
  93. @begin(enumerate)
  94. Fist, the TLM instructions can be printed out as Target Machine Assembly
  95. code (ASM) for assembly on the
  96. target machine. This route is followed in the initial phases of the PSL
  97. implementation process to produce code for the target machine.
  98. Secondly, a file of the target machine code can be produced in a
  99. format that can be loaded directly into a running PSL system. This
  100. process is called FASLing, producing a FASt Load format file.
  101. Finally, the TLM code can be assembled and deposited directly into memopry
  102. of the running PSL system.
  103. This is basically analogous to the process used to load in a FASL file
  104. produced above except the code is not written to or read from a FASL file.
  105. @end(enumerate)
  106. This process is illustrated below:
  107. @begin(verbatim,leftmargin 0,group)
  108. .-----------------. Rlisp: Procedure SelectOne x;
  109. | RLISP input code| x := car x;
  110. `-----------------'
  111. v
  112. .------.
  113. | LISP | Lisp: (de selectone (x)
  114. `------' (setq x (car x)))
  115. v
  116. .----------.
  117. | Compiler |
  118. `----------'
  119. v
  120. .------------------------. ALM: (!*entry selectone expr 1)
  121. |ALM instructions in LAP | (!*alloc 0)
  122. | format | (!*move (car (reg 1))
  123. `------------------------' (reg 1))
  124. v (!*exit 0)
  125. .----------.
  126. | Pass1Lap |
  127. `----------'
  128. |
  129. v
  130. .---------------------. TLM: [68000 code]
  131. | TLM instructions in | (Fullword 1) Count of Args
  132. | LAP format. | (!*Entry selectone expr 1)
  133. `---------------------' (movea!.l (indirect
  134. | | (reg 1)) (reg 1))
  135. | v (rts)
  136. | .------------.
  137. | | TLM to ASM |
  138. | | converter |
  139. | `------------'
  140. | v
  141. | .-------------------. ASM: dc.l 1
  142. | | | movea.l (a1),a1
  143. | | Asm code suitable | rts
  144. | | for TM assembler |
  145. | `-------------------'
  146. v
  147. .--------------. .-----------------.
  148. | LAP resident |----->| Resident binary |
  149. | assembler | | `-----------------'
  150. +--------------+ | .------------.
  151. `-->| FASL files |
  152. `------------'
  153. @end(verbatim)
  154. In summary, here is an overview of the steps necessary to implement
  155. PSLon your target machine. More details will be given in the
  156. following sections.
  157. @begin(enumerate)
  158. Prelimaries:
  159. @begin(enumerate)
  160. Believe in yourself.
  161. Choose the host machine.
  162. Test file transfer.
  163. @end(enumerate)
  164. Decide how to map the ALM architecture to the TLM.
  165. Implement the TLM to ASM.
  166. Implement the ALM to TLM.
  167. Build the Cross Compiler and test.
  168. Run Cmacro Tests.
  169. Build Bare PSL.
  170. Implement a resident TLM assembler.
  171. Implement FASL.
  172. Bootstrap the compiler.
  173. @end(enumerate)
  174. @section(Overview of the Abstract LISP Machine)
  175. The abstract machine is really a class of related machines rather than a
  176. single fixed machine (such as PASCAL P-code, or some true @xlisp machines).
  177. The exact set of @CMACRO@XS, the number of registers, etc@. are under the
  178. control of parameters, flags and compiler code-generator patterns defined
  179. for the specific machine. This flexibility permits the match between the
  180. compilation model and the target machine to be better set, producing better
  181. code. Therefore, the exact set and meaning of @CMACRO@XS are not
  182. fixed by this definition; rather, they form an adjustable @dq[convention]
  183. between the compilation and @CMACRO/Assembly phase. The compiler itself is
  184. defined in PC:COMPILER.RED@Foot[dir: represents a logical directory name,
  185. in this PC: stands for <PSL.Comp> under Tops-20 or /psl/comp under UNIX.]
  186. and is augmented by machine-specific files, described later.
  187. The ABSTRACT LISP MACHINE (ALM) used by our compiler has the following
  188. characteristics.
  189. @begin(enumerate)
  190. There are 15 general purpose registers, 1 ..@. 15;
  191. and a stack for call/return addresses.
  192. Locals and temporaries variables are allocated on the stack by
  193. allocating a frame of temporaries large enough to hold them all, not
  194. by the use of push and pop instructions.
  195. The function calling mechanism loads N args into 1 ..@. N, and
  196. then transfers to the function entry point, pushing the return
  197. address onto the stack if necessary.
  198. The functions result is returned in register 1.
  199. Each procedure is responsible to save any values it needs on stack;
  200. small procedures often do not use the stack at all.
  201. The following is a brief lisp of all the ALM opcodes (CMACROS).
  202. @begin(verbatim)
  203. (!*ALLOC nframe:integer)
  204. (!*ASHIFT dest:any-alterable source:any)
  205. (!*CALL name:id)
  206. (!*DEALLOC nframe:integer)
  207. (!*EXIT nframe:integer)
  208. (!*FIELD operand:any-alterable starting-bit:integer
  209. bit-length:integer)
  210. (!*FOREIGNLINK name:id type:id
  211. number-of-arguments:integer)
  212. (!*FREERSTR l:nonlocalvars-list)
  213. (!*JCALL name:id)
  214. (!*JUMP label:any)
  215. (!*JUMPEQ label:any source1:any source2:any)
  216. (!*JUMPINTYPE label:any source1:any type-name:id)
  217. (!*JUMPNOTEQ label:any source1:any source2:any)
  218. (!*JUMPNOTINTYPE label:any source1:any type-name:id)
  219. (!*JUMPNOTTYPE label:any source1:any type-name:id)
  220. (!*JUMPON source:any lower-bound:integer
  221. upper-bound:integer l:label-list)
  222. (!*JUMPTYPE label:any source1:any type-name:id)
  223. (!*JUMPWGEQ label:any source1:any source2:any)
  224. (!*JUMPWGREATERP label:any source1:any source2:any)
  225. (!*JUMPWITHIN label:any lower-bound:integer
  226. upper-bound:integer)
  227. (!*JUMPWLEQ label:any source1:any source2:any)
  228. (!*JUMPWLESSP label:any source1:any source2:any)
  229. (!*LAMBIND r:registers-list l:nonlocalvars-list)
  230. (!*LBL label:tagged-label)
  231. (!*LINK name:id type:id number-of-arguments:integer)
  232. (!*LINKE nframe:integer name:id type:id
  233. number-of-arguments:integer)
  234. (!*LOC dest:any-alterable source:any)
  235. (!*MKITEM inf:any-alterable tag:any)
  236. (!*MOVE source:any dest:any-alterable)
  237. (!*POP dest:any-alterable)
  238. (!*PROGBIND l:nonlocalvars-list)
  239. (!*PUSH source:any)
  240. (!*PUTFIELD source:any dest:any-alterable
  241. starting-bit:integer bit-length:integer)
  242. (!*SIGNEDFIELD operand:any-alterable
  243. starting-bit:integer
  244. bit-length:integer)
  245. (!*WAND dest:any-alterable source:any)
  246. (!*WDIFFERENCE dest:any-alterable source:any)
  247. (!*WMINUS dest:any-alterable source:any)
  248. (!*WNOT dest:any-alterable source:any)
  249. (!*WOR dest:any-alterable source:any)
  250. (!*WPLUS2 dest:any-alterable source:any)
  251. (!*WSHIFT dest:any-alterable source:any)
  252. (!*WTIMES2 dest:any-alterable source:any)
  253. (!*WXOR dest:any-alterable source:any)
  254. (LABELGEN tag:id)
  255. (LABELREF tag:id)
  256. (!*CERROR message:any)
  257. (FULLWORD [exp:wconst-expression])
  258. (HALFWORD [exp:wconst-expression])
  259. (BYTE [exp:wconst-expression])
  260. (STRING s:string)
  261. (FLOAT f:float)
  262. @end(verbatim)
  263. ALM operand forms ("addressing" modes)
  264. @begin(verbatim)
  265. (FLUID name:id)
  266. (!$FLUID name:id)
  267. (GLOBAL name:id)
  268. (!$GLOBAL name:id)
  269. (WVAR name:id)
  270. (WARRAY name:id)
  271. (WSTRING name:id)
  272. (WCONST expr:wconst-expression)
  273. (IMMEDIATE wconst-expression:any)
  274. (QUOTE s-exp:s-expression)
  275. (LABEL l:id)
  276. (MEMORY base:any offset:wconst-expression)
  277. (CAR base:any)
  278. (CDR base:any)
  279. (FRAME n:integer)
  280. (REG reg-descriptor:{integer,id})
  281. (LIT [any-instruction-or-label:{list,id}])
  282. (LABELGEN tag:id)
  283. (LABELREF tag:id)
  284. (IDLOC symbol:id)
  285. @end(verbatim)
  286. @end(enumerate)
  287. @Section(System Overview for Bootstrapping)
  288. Currently PSL is half bootstrapped from a complete PSL system on a
  289. host machine. At the moment only the Decsystem 20 and the VAX 750
  290. can be used as hosts; shortly we expect the Apollo and HP9836 to
  291. be also usuable.
  292. If you have a choice for your host machine, one important consideration
  293. will be the ease in shipping code between the host and target. It is worth
  294. taking the time initially to be sure this pathway is as smooth and troublefree
  295. as possible. The need for easy file transfers is derived from the half
  296. bootstrap method and the iterative nature of developing and debugging the
  297. tables used in the ALM to TLM transformation. The size of the transferred
  298. files will be in the range of 1 to 70 KBytes.
  299. Having a fast network or a tape transfer from host to target is worth
  300. considering in the beginning of a PSL implementation.
  301. The first major step in the implementation will be to modify the host PSL
  302. to become a cross compiler, turning lisp or rlisp into the target machines
  303. assembly language.
  304. @SubSection(Overview of the Cross Compiler)
  305. Three modules are created, compiled and loaded into a host PSL to transform
  306. it into a cross compiler.
  307. @begin(enumerate)
  308. The first module will be xxx-comp.red (we will use XXX to represent
  309. the name of the target machine, like DEC20, VAX, etc.); a file
  310. containing patterns used by the compiler to control which ALM
  311. instructions are emitted for certain instructions. Basically it is
  312. used in LISP to ALM transformations and initially will only require
  313. you to copy the same file used on your host machine.
  314. The second module will be xxx-cmac.sl. This file contains the
  315. tables(CMacroPatternTables) used to convert ALM opcodes to TLM opcodes,
  316. the tables used to convert ALM addressingmodes into TLM addressingmodes
  317. (ANYREGS), and some miscellaneous required opencoded functions.
  318. The last module, xxx-asm, consists of two files, xxx-asm.red and
  319. xxx-data-machine.red. The first file, xxx-asm.red, specifies the necessary
  320. formats, costants, and procedures for converting TLM instructions into the
  321. host's actual assembly language. The file, xxx-data-machine.red, provides
  322. constants for describing to the compiler some of the specific choices for
  323. what registers to use and how the lisp item will be used in the machine
  324. words.
  325. @end(enumerate)
  326. All of these modules are compiled and loaded into a host PSL to turn
  327. it into the cross compiler. The next few sections will try to
  328. describe to the reader how these three modules are actually designed
  329. and built from the bottom up. It will be worth getting a listing of
  330. these modules for your host machine and also for a machine most similar
  331. to your target machine, if available.
  332. @Section(Designing the TLM instruction format).
  333. The implementor must decide first the specifics of the TLM instruction
  334. format patterned around the form (TLMopcode TLMoperand ... TLMoperand).
  335. The TLM to ASM translation occurs in a parallel manner.
  336. (TLMopcode TLMoperand TLMoperand) TLM format.
  337. | | |
  338. ASMopcode ASMoperand ASMoperand Some ASM format.
  339. The closer the ASM format approaches the TLM format the better. However in
  340. some cases this will not be possible and the reader must devise a scheme.
  341. Take a look at the case studies for some ideas of ways to handle some of
  342. these issues.
  343. TLM opcodes are usually passed through unchanged to the ASM code.
  344. However the TLM operands will require extensive changes. [Mention
  345. terminal operands!!!]. The TLM operands are of the form
  346. (addressingmode value-expression). The addressingmode is a tag which
  347. will direct what procedures will be used to convert and print the ASM
  348. operands. The reader should pick these addressingmode names to closely
  349. match the addressingmodes of the target machine. Some examples of
  350. these would be (immediate ...), (indirect ...), (displacement ...), or
  351. (indexed ...). Here again the case studies will give you some
  352. information for proceeding. [Mention CRAY mismatch of TLM].
  353. @Section(Implementing the TLM to ASM conversion)
  354. You can begin by creating the xxx-data-machine.red file and begin to add
  355. some definitions. First pick a name for your system, anything
  356. representative will do like the name of its operating system or its
  357. manufacturers identifier. Some examples are dec20, vax, apollo, or m68000.
  358. @begin[verbatim]
  359. fluid '(system_list!*);
  360. system_list!* := '(MC68000 Chipmunk HP9836);
  361. @end[verbatim]
  362. The next step is quite important. You must decide how you are going to
  363. implement the LISP item on the target machine.
  364. The LISP item consists of 2 or three fields; each field
  365. having a position and size in the machines item picked by the
  366. implementor. All LISP items must have a tag field and an INFormation
  367. field and some implementations have a garbage collector field. The
  368. tag field must be at least 5 bits long@Foot[Nineteen (19) different tags are
  369. presently used.] and the inf field should be large
  370. enough to hold a target machine address. Some implementations, such
  371. as the Vax, will choose an inf smaller than the largest address
  372. possible on the machine and will have to mask tag bits out when using
  373. the inf field as an address. This does cause problems and should be
  374. avoided if possible. If space allows it the INF
  375. field may be larger to allow larger numeric operands to be stored in
  376. registers.
  377. Currently PSL provides two different garbage collection methods, one
  378. of which should be chosen (or a new one developed if needed). One is
  379. a two-space copying collector, which requires no extra garbage
  380. collection bits, but is very wasteful of space and is best for a
  381. virtual memory machine (in fact, there are two copies of the heap).
  382. The other is a one space compacting collector, and requires at least
  383. one bit for marking, and ideally additional bits for relocation
  384. (sometimes, these extra bits can be stored in a separate bit table).
  385. Naturally these fields may be larger to make their accessing easier,
  386. like aligning on a byte boundary.
  387. Once you have decided upon how the LISP item will be implemented on the
  388. machine you can begin filling in the constant definitions for the
  389. xxx-data-machine.red file. When numbering bits in a machine word, we have
  390. settled upon the convention that the most significant bit is zero and
  391. counts up to the max-1 bit.
  392. The current constants are
  393. @begin(verbatim)
  394. TagStartingBit
  395. TagBitLength
  396. InfStartingBit
  397. InfBitLength
  398. AddressingUnitsPerItem
  399. CharactersPerWord
  400. BitsPerWord
  401. AddressingUnitsPerFunctionCell
  402. StackDirection
  403. and optionally
  404. GCStartingBit
  405. GCBitLength
  406. @end(verbatim)
  407. The following figure illustrates the positions of these constants:
  408. @begin(verbatim)
  409. .-----------------------------------------.
  410. | TAG | [gc] | INF |
  411. `-----------------------------------------'
  412. FILL IN LATER
  413. @end(verbatim)
  414. Some other decisions that must be made include:
  415. @begin(enumerate)
  416. Which and how many registers to dedicate as the compiler-allocated
  417. @ei[Registers];
  418. How large an integer will be supported in the @xlisp item;
  419. How many tags are to be supported
  420. How to implement the recursion stack and check for stack overflow
  421. (either using an explicit test, or some machine-interrupt);
  422. How to pack and unpack strings;
  423. @Comment{PSL must have explicitly tagged items, and the current allocator
  424. is a simple linear model, so this is not relevant.
  425. Whether to have a heterogeneous heap, multiple heaps, a @ei[page] per type,
  426. or whatever;}
  427. @Comment{This is also not relevant. Pairs are the same on all machines.
  428. How pairs are referenced, i.e. does the pointer to a pair point to the
  429. first element, to the second element, are the pairs allocated
  430. separately in parallel areas, or is there some type of CDR coding being
  431. done.}
  432. @end(enumerate)
  433. The next step is to implement the tables that accept the ALM
  434. form and emits assembly code for the target machine.
  435. Most of the program is machine-independent (using
  436. PC:LAP-TO-ASM.RED), and an @dq[xxxx-ASM.RED] file is to be
  437. written. We have the following already written as a guide: @DEC20
  438. @dq[MACRO], @VAX750 @UNIX @dq[as], @68000 for @apollo and WICAT, and CRAY
  439. CTSS CIVIC. The main problem is to emit the correct format, such as:
  440. placement of tabs, commas, spaces, parentheses; renaming symbols (certain
  441. legal @xlisp IDs are not legal in some assemblers); and determining how and
  442. where to place EXTERNAL, ENTRY and GLOBAL declarations, how to declare and
  443. reserve blocks of storage, and how to overcome certain problems involved
  444. with large files and restrictions on addressing modes and relocation.
  445. Finally, the ALM to ASM needs to be tested. This is usually
  446. accomplished by Hand-coding some small test routines, and
  447. then convert from ALM to machine X assembly code, assemble, and run. This
  448. checks the final details of required Prologues and
  449. Epilogues@Foot[Prologues and Epilogues contain operating system-specific
  450. standard module headers and trailers.], understanding of the instruction
  451. set, and so on. Suggested LAP tests are described @ei[generically], but
  452. will have to be translated by the implementor into machine-dependent LAP
  453. for machine X, and depending on the flavor of assembler and LAP, other
  454. tests will have to be devised by the implementor. This is a good time to
  455. investigate how Assembly coded routine can call (and be called) by the
  456. most common language used on machine X (such as FORTRAN, PASCAL, C, etc.).
  457. This "Foreign" language can be used for initial operating system support.
  458. @section(Implementing the ALM instructions)
  459. The ALM instructions consists of a set of operations and their
  460. addressing mode operands. These ALM instructions are commonly
  461. referred to as CMACRO's and the addressing modes are ANYREG's. The
  462. purpose of this part of the PSL implementation is to implement the
  463. functionality of each ALM instruction in terms of other ALM
  464. instructions and TLM instructions. The ability to recursively define
  465. the ALM instructions in terms of other ALM instructions is a benefit
  466. because it greatly decreases the amount of code required to implement
  467. a particular instruction. For example, a good technique in designing
  468. the ALM instructions is to carefully implement the !*MOVE instruction
  469. (to distinguish ALM instructions, they generally have a !* in the front
  470. of their name) to
  471. efficiently handle transfer between any possible locations (memory to
  472. register, stack frame to memory, etc.). Then when implementing
  473. another instruction, the code for moving the actual operands to
  474. locations necessary for the TLM instruction can be accomplished using
  475. a recursive call to the !*MOVE ALM instruction.
  476. The important tasks of the implementor are to
  477. @begin(enumerate)
  478. Carefully examine the instruction set and architecture of the TLM to
  479. see which instruction (instructions) correspond to each ALM CMACRO;
  480. Decide how to map the ALM registers and addressing modes onto the
  481. TLM registers and addressing modes (some will map one-to-one, others
  482. will take some thought, and a sequence of actions);
  483. Decide on a set of classifications of the TLM modes that distinguish
  484. which of a related set of TLM opcodes should be used to implement
  485. a particular ALM opcode, and write predicates that examine ALM and TLM
  486. modes to decide which class they are in;
  487. Write tables to map ALM modes into TLM modes, using these predicates,
  488. and then ALM opcodes into a (sequence of) TLM opcodes with the correct
  489. TLM modes.
  490. @end(enumerate)
  491. @subsection(Mechanics of ALM Instruction Definition)
  492. Before we get into the description of the ALM instructions, we must first
  493. define the table-driven pattern matching approach used to implement
  494. them. This approach allows definition of
  495. an ALM instruction in terms of a pattern predicate which is used to match
  496. the operands of the ALM instruction and a body that may consist of a
  497. mixture of ALM instructions (for recursive decomposition) and TLM
  498. instructions (for direct code generation). This is exactly analogous to
  499. the COND construct in LISP. Just like COND, any number of predicate/body
  500. pairs may be included in the expansion of an ALM instruction. Also, the
  501. order of the pairs is quite important (since they are compared in order
  502. from first to last). Typically, the most specific predicates are described
  503. first followed by gradually more and more general ones. The table
  504. definition for a specific ALM instruction is compiled into a single
  505. procedure. The instruction name must then be flagged with 'MC to
  506. indicate that it is a legal ALM instruction. The pattern table itself
  507. must then be stored under the indicator 'CMACROPATTERNTABLE on the ALM
  508. instruction property list. To simplify this process, the DefCmacro
  509. Macro has been defined:
  510. @begin(verbatim)
  511. (DefCMacro ALMInstructionName
  512. (pred1 body1)
  513. (pred2 body2)
  514. ...
  515. lastbody)
  516. @end(verbatim)
  517. Each ALM instruction is defined with a set number of arguments and the
  518. predicates are used to compare the types and/or values of the arguments. A
  519. predicate need not test all arguments, with non-tested arguments defaulting
  520. to T for a value. For example, one could define the following patterns:
  521. @begin(verbatim)
  522. Predicate Body
  523. (DefCMacro ALMInst
  524. ((FOOP) (Body1))
  525. ((FEEP BARP) (Body2))
  526. ((ANYP) (Body3))
  527. (Body4))
  528. @end(verbatim)
  529. Note that this looks almost exactly like the LISP operation COND. The
  530. one difference lies with the Body4 in the above example, which has no
  531. predicate and will always be evaluated if all others fail (Similar to
  532. the final 'T case in a Cond without the T). This last predicate/body
  533. pair may NOT have a predicate. If it doesn't, it will be evaluted just
  534. like the body. [!!Future change - CERROR on the default case, and make
  535. the defined use ANYP for his default case]
  536. The predicate
  537. functions are automatically passed one argument which is the ALM operand in
  538. the position of the test. So, in the above example, FOOP is passed the
  539. first operand and BARP is passed the second, after failure in the FOOP
  540. test.
  541. The body can be thought of as an implicit PROGN that contains a set of ALM
  542. and TLM instructions. These instructions then reference the various
  543. operands as ARGONE, ARGTWO, ARGTHREE, etc. using lexical ordering in the
  544. instruction. For example, if an ALM instruction mapped directly to a TLM
  545. one, it may be defined as:
  546. @begin(verbatim)
  547. ((FOOP BARP) (TLMOperator ARGONE ARGTWO))
  548. @end(verbatim)
  549. Or, it may map into a number of ALM and TLM instructions:
  550. @begin(verbatim)
  551. ((FEEP) (ALMOperator ARGONE Something)
  552. (TLMOperator Something ARGTWO)
  553. (ALMOperator Something ARGONE))
  554. @end(verbatim)
  555. Notice that even though the predicates only test the first operand ARGONE,
  556. the other operands may be referenced in the body. Also, "Something" can be
  557. thought of as a kind of constant operand (like a particular register, an
  558. integer constant, a memory location or whatever).
  559. In order to facilitate more complicated instructions within the body, we
  560. must now introduce a number of other features. First, suppose that you
  561. wish to include code generation time constants within the body. This can
  562. be accomplished by placing on the property of a variable name, 'WCONST with
  563. its value being the desired constant. Then when the variable is
  564. encountered in the instruction expansion, it will be replaced by the value
  565. on its property list under the 'WCONST indicator. A useful function to
  566. perform this operation would be:
  567. @begin(verbatim)
  568. (DE MakeReferencedConst (ConstName ConstValue)
  569. (Put ConstName 'WCONST ConstValue))
  570. @end(verbatim)
  571. Therefore, if you perform a (MakeReferencedConst 'TAGPOSITION 10) then the
  572. body may reference TAGPOSITION directly:
  573. @begin(verbatim)
  574. ((FOOP) (ALMOperator ARGONE TAGPOSITION))
  575. @end(verbatim)
  576. Now, that we have constants, it is sometimes desirable to have constant
  577. expressions. As long as all of the operands are either direct or
  578. referenced constants, the expression can be evaluated in an ALM or TLM
  579. instruction (the function may also be called if it doesn't have any
  580. operands). For example, the following could be imbedded within an
  581. instruction body:
  582. @begin(verbatim)
  583. (Plus2 (Foo 35 TagPosition) WordWidth)
  584. @end(verbatim)
  585. The system also provides for an alias mechanism, so you can map one name
  586. into another. This is accomplished by placing on the property of the
  587. alias, the name of the acutal function under the property DOFN. Thus, if
  588. you wanted to map FEE into PLUS2, you would simply: (Put 'FEE 'DOFN
  589. 'PLUS2). Therefore, another useful function would be:
  590. @begin(verbatim)
  591. (DE Alias (AliasFunction ActualFunction)
  592. (Put AliasFunction 'DOFN ActualFunction))
  593. @end(verbatim)
  594. Sometimes in the process of generating the TLM instructions, it is
  595. necessary to make use of a temporary label (i.e. to generate a forward
  596. branch). This can be accomplished by referencing TEMPLABEL (just like a
  597. reference to ARGONE), which will create a label name consistent with a
  598. particular body. For example:
  599. @begin(verbatim)
  600. ((FOOP) (Test ARGONE)
  601. (GO (Label TEMPLABEL))
  602. (Operate ARGONE ARGTWO)
  603. (Label TEMPLABEL))
  604. @end(verbatim)
  605. Notice that even if the label references are separated by recursive ALM
  606. instructions, it will still create a unique reference to the label in both
  607. places. There is another mechanism to accomplish the same task in a more
  608. general fashion, that allows referencing of multiple labels. This
  609. mechanism is used with two functions:
  610. @begin(description)
  611. LabelGen@\This function takes one argument and returns a generated label.
  612. The argument and label are stored on an A-List for later reference. The
  613. argument may be any atom.
  614. LabelRef@\Look up the argument on the label's A-List and return the
  615. associated label.
  616. @end(description)
  617. An example of the use of these two functions is:
  618. @begin(verbatim)
  619. ((FOOP) (Label (LabelGen 'L1))
  620. (Test ARGONE)
  621. (Go (LabelGen 'L2))
  622. (Operator ARGTWO))
  623. (Go (LabelRef 'L1))
  624. (Label (LabelRef 'L2)))
  625. @end(verbatim)
  626. Finally, if the need arises to be able to call a function within an ALM
  627. instruction expansion. This can be accomplished by using the ANYREG
  628. mechanism. It is important to know that this technique will not work for a
  629. function call within a TLM instruction, only in the recursive expansion of
  630. an ALM instruction (there is no method for calling a function within
  631. a TLM instruction). (Note: ANYREG's will be explained in detail later, but
  632. the mechanism can be used to call a function). The technique is to first
  633. define the function that you wish to call, with one extra argument (the
  634. first one) that will be ignored. Then define an anyreg function that calls
  635. your function. For example, suppose you want a function that returns an
  636. associated register based upon a register argument (with the association
  637. stored in an A-List). The code would be implemented as follows:
  638. @begin(verbatim)
  639. (De GetOtherRegFunction (DummyArgument RegName)
  640. (Assoc RegName '((A1 S3) (A2 S2) (A3 S1))))
  641. (DefAnyReg GetOtherReg GetOtherRegFunction)
  642. @end(verbatim)
  643. Then the pattern that may use the function would be:
  644. @begin(verbatim)
  645. ((FOOP) (ALMOperator (GetOtherReg ARGONE)
  646. (GetOtherReg ARGTWO)))
  647. @end(Verbatim)
  648. [Future Change - Implement a technique so if it is necessary for a
  649. random function to be called, all one has to do is define it and flag it
  650. as something appropriate - like 'ALMRandomFunction]
  651. @subsection(@ANYREG and @CMACRO patterns)
  652. Certain of the ALM operands are @ei[tagged] with a very
  653. special class of functions thought of as extended addressing modes; these
  654. @ANYREG@xs are essentially Pseudo instructions, indicating computations
  655. often done by the addressing hardware (such as field extract, indexing,
  656. multiple indexing, offset from certain locations, etc.). For example, the
  657. @xlisp operations CAR and CDR often are compiled in one instruction,
  658. accessing a field of a word or item. Using @ANYREG in this case, CAR and
  659. CDR are done as part of some other operations. In most cases, the @ANYREG
  660. feature is reserved for operations/addressing modes usable with most
  661. instructions. In some cases, the @ANYREG is too complicated to be done in
  662. one instruction, so its expansion emits some code to @ei[simplify] the
  663. requested addressing operation and returns a simpler addressing mode. The
  664. main thing is all desired computations are done using 1 or zero registers,
  665. hence the name @dq[@ANYREG].
  666. The @ANYREG@xs have an associated function and possible table, with the
  667. name of the function under the property 'ANYREGRESOLUTIONFUNCTION and
  668. the pattern under 'ANYREGPATTERNTABLE. Just like the DefCMacro macro
  669. has been defined to aid ALM instruction description, the macro DefAnyReg
  670. has been provided to help set up these associations:
  671. @begin(verbatim)
  672. (DEFANYREG anyregname anyregfunction
  673. (pred1 body1)
  674. (pred2 body2)
  675. ...
  676. lastbody)
  677. @end(verbatim)
  678. As you can see, the structure of a DefAnyReg is exactly the same as
  679. DefCMacro, except an additional operand AnyRegFunction must be supplied.
  680. When an AnyReg is found in the instruction expansion, the function is
  681. called with two or more arguments:
  682. @begin(enumerate)
  683. Temp Register - Since the anyreg must perform its operation using zero
  684. or one register, this is the register that it may use to perform its
  685. task. (CAVEAT: The current implementation provides either (Reg T1) or
  686. (Reg T2) as the temporary register in all cases except one. That is
  687. when the anyreg is the source of a move and the destination is a
  688. register. In that case, the destination register is passed as the
  689. temporary. This can cause a problem if any part of the anyreg requires
  690. the destination to first be a source. [Future change - Eliminate this
  691. problem used in move and always pass in T1 or T2]).
  692. Source - This is the actual body of the anyreg. It may be referenced
  693. within the AnyRegPatternTable as SOURCE.
  694. ArgTwo - Only one anyreg (Memory) currently has more than two arguments.
  695. If they are desired, this third argument may be referenced by ARTTWO.
  696. @end(enumerate)
  697. A defect in the current system is that the pattern predicates following
  698. the anyreg function may not test the Temporary Register. This is quite
  699. inconsistent, since the function definition must consider the operand,
  700. while the pattern table must ignore it. [Future change - Fix This
  701. problem]
  702. @subsection(ALM Instruction Expansion)
  703. Now that we understand the mechanics of defining ALM instructions and
  704. anyreg tables we need to explore the order of expansion of the
  705. instructions. The compiler emits ALM instructions, with the operands
  706. being legal ALM "addressing" modes. These instructions are collected in
  707. a list and passed to the Pass1Lap function. Pass1Lap looks at each
  708. instruction and attempts to simplify it. It looks on the property of
  709. the opcode and checks to see if it has been flagged with 'MC. If so, it
  710. calls the function of the same name with the operands unchanged.
  711. Most ALM expansion functions first apply the function
  712. @begin(verbatim)
  713. ResolveOperand(Reg, Source)
  714. @end(verbatim)
  715. to each operand, passing a temporary register as the first argument,
  716. REG. This resolution process converts ALM operand forms into TLM
  717. operand forms i.e, legal addressing modes of the TLM.
  718. After each operand has been "resolved", the CMACRO pattern table
  719. is used, and the resulting LIST of CMACROS processed recursively.
  720. This is what is accomplished in the three functions:
  721. @begin(verbatim)
  722. EXPAND1OPERANDCMACRO(Arg1,Name)
  723. EXPAND2OPERANDCMACRO(Arg1,ARg2,Name)
  724. EXPAND4OPERANDCMACRO(Arg1,ARg2,Arg3,Arg4,Name)
  725. @end(verbatim)
  726. which first resolves the arguments using the available registers and
  727. then calls the routine (CMACROPATTERNEXPAND) which finds the pattern
  728. table of the Name argument (ALM instruction) stored on the property list
  729. under the indicator 'CMACROPATTERNTABLE.
  730. For example,
  731. (de !*WPlus2 (Arg1 Arg2)
  732. (Expand2OperandCMacro Arg1 Arg2 '!*WPlus2))
  733. Only the (!*MOVE s d) ALM opcode tries to be smarter about temporary regs:
  734. d:=RESOLVEOPERAND('(Reg t2),d)
  735. If d is a register, then RESOLVEOPERAND(d,S)
  736. else RESOLVEOPERAND('(REG t1),s);
  737. [Future change - This should be changed in the future]
  738. Recall also that Processing an arugment with RESOLVEOPERAND may
  739. require other CMACRO's to be emitted first, to "simplify" the complex
  740. addressing mode; each Operand is free to destroy/modify its given
  741. register. For example, note how register t1 is reused below to
  742. resolve multiple CAR's and CDR's into MOVE's and simpler CAR's and
  743. CDR's:
  744. (!*MOVE (CAR (CAR x)) d) => (!*MOVE (CAR x) (REG t1))
  745. (!*MOVE (CAR (REG t1)) d)
  746. (!*MOVE (CAR (CAR(reg 1))) (CDR (CDR (reg 2))))
  747. => (!*MOVE (CDR (reg 2)) (REG t2))
  748. (!*MOVE (CAR (REG 1)) (REG t1))
  749. (!*MOVE (CAR (reg t1)) (CDR (reg t2)))
  750. Therefore, typically the operands are first processed before the ALM
  751. instruction table is used.
  752. AnyReg processing works the same way as with the ALM instructions. The
  753. operands are first resolved by calling the ResolveOperand function and
  754. then ExpandOneArgumentAnyReg (or TwoArgument) is called to process the
  755. pattern table. This has also been combined into a single function:
  756. OneOperandAnyReg and TwoOperandAnyReg.
  757. [[WARNING - There is an inconsistency in the naming here. For CMacro
  758. expansion the combined functions are called EXPANDxOPERANDCMACRO where
  759. for anyregs it is ONEOPERANDANYREG. BE CAREFUL!!!!!!! Another
  760. inconsistency is that CMacros are flagged with 'MC, which AnyRegs are
  761. not flagged]]
  762. @paragraph(ResolveOperand)
  763. The ResolveOperand function takes two arguments, a temporary register
  764. and the source to resolve. It performs the following resolution, in the
  765. order given:
  766. @begin(Description)
  767. an ID@\cals ResolveWConst on the ID;
  768. number or string@\returned unchanged;
  769. (OP s)@\If OP is flagged 'TerminalOperand, it is returned as is.
  770. (OP s)@\If OP is an @anyreg (has an 'AnyregResolutionFunction), it is
  771. applied to (Register s).
  772. (OP s)@\Otherwise, it is examined to see if it is a WCONST expression.
  773. @end(description)
  774. The function ResolveWConst tests its operand to see if it is a constant
  775. or constant expression, and returns its value. It performs the
  776. following resolution:
  777. @begin(description)
  778. (WCONST number)@\returns the number
  779. ID@\If WCONST indicator is on the ID's property, the associated number
  780. is returned otherwise the ID is returned.
  781. Expression@\Each operand is tested to determine if it can be resolved as
  782. a WCONST and if so, the function is applied to all of the operands (ANY
  783. FUNCTION CAN BE CALLED)
  784. @end(description)
  785. ?????Insert some SUMMARY USING THE FOLLOWING????????
  786. Most ANYREGS use OneOperandAnyReg, ie recursively process arguments
  787. inside out (CAR anyreg), (CDR anyreg), etc
  788. % (de AnyRegCAR(R S) (OneOperandAnyReg R S 'CAR))
  789. % (defAnyReg CAR AnyRegCar ....)
  790. Those that do not permit anyregs as args, use ExpandOneOperandAnyReg
  791. eg, (QUOTE s), (WCONST w), (WVAR v), (REG r)
  792. or flag name as TERMINALOPERAND to pass direct to ASM
  793. so here is a simple WCONST expression.
  794. As long as args are WCONSTEVALUABEL themselves, any
  795. function can be applied:
  796. @section(Predicates)
  797. Provided in the common machine independent files are a number of
  798. useful predicates. Those include:
  799. [[[[List the predicates provided in common-predicates]]]]
  800. Each of the following predicates expects one argument; call it X:
  801. @begin(Description)
  802. RegisterP@\(EqCAR X 'REG) tests for any register
  803. AnyP@\ Always T, used as filler
  804. EqTP@\ (equal X T)
  805. MinusOneP@\(equal X -1)
  806. InternallyCallableP@\Check if legal to make a fast internal call.
  807. Essentially checks the following:
  808. @begin(format)
  809. [(or !*FastLinks
  810. % all calls Fastlinks?
  811. (and !*R2I (memq X EntryPoints!*))
  812. % or specially declared
  813. (FlagP X 'InternalFunction)
  814. (FlagP X 'FastLink)))]
  815. @end(format)
  816. AddressConstantP@\(or (NumberP X) (EqCar X 'Immediate)))
  817. @end(Description)
  818. @section(Standard ANYREGS)
  819. The following are the basic @ANYREG functions, which in many cases
  820. look for an AnyregTable:
  821. @begin(Description)
  822. @B[ID]@\@B[Flagged]
  823. CAR@\OneOperandAnyreg, 'CAR table@comment{ need to explain all of these
  824. tables - particularly the WVar
  825. table }
  826. CDR@\OneOperandAnyreg, 'CDR table
  827. QUOTE@\ExpandOneArgumentAnyreg, 'QUOTE table
  828. WVAR@\ExpandOneArgumentAnyreg, 'WVar table
  829. REG@\ExpandOneArgumentAnyreg, 'REG table
  830. WCONST@\OneOperandAnyreg, 'WConst table, default normally just SOURCE.
  831. FRAME@\ExpandOneArgumentAnyreg, computes offset from stack pointer,
  832. and passes this (in bytes) to 'FRAME table
  833. FRAMESIZE (Register)@\Computes (NAlloc!* @Value(Times)
  834. AddressingUnitsPerItem) to give size of frame to any special code needing it.
  835. MEMORY (Register Source ArgTwo)@\Used to
  836. compute indexed memory access: TwoOperandAnyreg, Look for 'MEMORY table.
  837. LABEL@\Flags a label, does no processing.
  838. @end(Description)
  839. The implementor of @PSL for any particular machine is free to add additional
  840. @ANYREG@xs (addressing modes), that are emitted as part of @CMACRO@XS by
  841. machine specific compiler patterns or COMPFNs.
  842. IMMEDIATE is a tag used to @ei[suggest] address or immediate constant.
  843. @subsection(Some AUXILLIARY Operand Modes for the TLM)
  844. Each of the following functions expects one argument; call it X:
  845. @begin(Description)
  846. UnImmediate@\If X @Value(Eq)(Immediate Y), removes tag to get Y.
  847. ExtraReg@\Converts argument X into Access to ArgumentBlock[X-LastActualReg]
  848. QUOTE@\Compiles X into a constant. If !*ImmediateQuote is T, returns an
  849. ITEM for object, else emits ITEM into a memory location, returns its address.
  850. @end(Description)
  851. Note @CMACRO@XS (flagged 'MC) are first expanded, then the PASS1PSEUDO@xs.
  852. This means the @CMACRO@XS are able to insert and manage TAGS that are
  853. removed or modified by final PASS1PSEUDO.
  854. @section(more junk)
  855. @i[Implement the Compiler Patterns and Tables]. This requires selecting
  856. certain alternative routes and parameterizations allowed by the compiler,
  857. trying to improve the match between the Abstract @PSL machine used by the
  858. compiler and the target architecture X. Mostly this phase is reserved for
  859. optimization, but the basic tables have to be installed to map @xlisp
  860. function names to corresponding @cmacro names and select the Compiler
  861. functions (COMPFNs and OPENFNs) to be used for each construct. This file,
  862. @dq[xxxx-COMP.RED], is usually copied from one of the existing machines and
  863. modified as needed. Most of the modifications relate to the legality of
  864. certain addressing combinations. These tables are briefly described in the
  865. Compiler chapter of the manual, but currently this task is still somewhat
  866. "arcane".@comment{ There needs to be some mention of what the usual
  867. modifications are! }
  868. @i[Build and Test the CROSS Compiler]. Now compile a series of LAP (mostly
  869. @CMACRO tests), @xlisp and
  870. @syslisp files to X assembly code, link and run. As the tests proceed,
  871. certain small I/O and function calling procedures are written in LAP. A
  872. common way to do I/O is to implement a @ei[Foreign Function]-calling
  873. protocol, used from @xlisp to call functions according to
  874. FORTRAN, PASCAL, C or other useful conventions. Calls in compiled
  875. @xlisp/@syslisp code to function names flagged with the 'FOREIGN-FUNCTION
  876. flag are called with a non-@xlisp protocol. This permits a
  877. standard I/O library to be called and allows simple routines to be
  878. written in another language. The purpose of this separate
  879. function-calling mechanism is to allow the @xlisp system to use the
  880. most efficient calling method possible, compatible with the needs of
  881. @syslisp and @xlisp. This method is not necessarily the most flexible,
  882. general, or safe method and need not be used by other languages.
  883. However, to allow the @xlisp/@syslisp system to call upon existing
  884. routines, particularly system-provided services, this additional
  885. function-calling mechanism should be provided. Some care needs to be taken
  886. to preserve and restore registers appropriately.
  887. @chapter(Test Series)
  888. In order to accomplish the PSL bootstrap with a
  889. minimum of fuss, a carefully graded set of tests is being developed,
  890. to help pinpoint each error as rapidly as possible. This section
  891. describes the current status of the test files. The first phase
  892. requires the coding of an initial machine dependent I/O package and
  893. its testing using a familar system language. Then the code-generator
  894. macros can be succesively tested, making calls on this I/O package as
  895. needed. Following this is a series of graded SYSLISP files, each
  896. relying on the correct working of a large set of SYSLISP constructs.
  897. At the end of this sequence, a fairly complete "mini-LISP" is
  898. obtained. At last the complete PSL interpreter is bootstrapped, and a
  899. variety of PSL functional and timing tests are run.
  900. @section(Basic I/O Support)
  901. The test suite requires a package of I/O routines to read and print
  902. characters, and print integers. These support routines are usually written
  903. in a "foreign" language (call it "F"), such as PASCAL, C or FORTRAN; they
  904. could also be coded in LAP, using CMACROs to call operating system
  905. commands, if simple enough. (E.g., JSYS's on DEC-20, Traps on 68000, etc.).
  906. These routines typically are limited to using the user's terminal/console
  907. for input and output. Later steps in the bootstraping sequence introduce a
  908. more complete stream based I/O module, with file-IO.
  909. On some systems, it is appropriate to have a main routine written in "F"
  910. which initializes various things, and then calls the "LISP" entry point; on
  911. others, it is better to have "LISP" as the main routine, and have it call
  912. the initialization routines itself. In any event, it is best to first write
  913. a MAIN routine in "F", have it call a subroutine (called, say TEST), which
  914. then calls the basic I/O routines to test them. The documentation for the
  915. operating system should be consulted to determine the subroutine calling
  916. conventions. Often, the "F" compiler has an "ASSEMBLY Listing switch",
  917. which can be turned on to see how the standard "F" to "F" calling sequence
  918. is constructed, and to give some useful guidance to writing correct
  919. assembly code. This can also be misleading, if the assembler switch only
  920. shows part of the assembly code, thus the user is cautioned to examine
  921. both the code and the documentation.
  922. On directory PT: (which stands for /psl/tests or <PSL.TESTS>), or its
  923. subdirectories, we have a number of sample I/O packages, written in various
  924. languages: PASCAL, FORTRAN, C and DEC20 assembly code. Each has been used
  925. successfully with some PSL bootstrap. The primitives provided in these
  926. files are often named XXX-yyyy, where XXX is the machine name, and yyyy is
  927. the primitive, provided that these are legal symbols. Of course, the name
  928. XXX-yyyy may have to be changed to conform to "F" and the associated linker
  929. symbol conventions. Each name XXX-yyyy will be flagged as a
  930. "ForeignFunction", and called by a non-LISP convention.
  931. The following is a brief description of each primitive, and its use. For
  932. uniformity we assume each "foreign" primitive gets a single integer
  933. argument, which it may use, ignore, or change (VAR c:integer in PASCAL).
  934. @Comment{Is this assumed to be a WORD size quantity, i.e. on the 68000 a 32
  935. bit quantity or can it be a small integer???}
  936. The following routines ("yyyy") in LISP, will be associated with the
  937. corresponding "foreign" routine "XXX-yyyy" in an appropriate way:
  938. @begin(description)
  939. init()@\Called once to set up I/O channels, open devices, print welcome
  940. message, initialize timer.
  941. Quit()@\Called to terminate execution; may close all open files.
  942. PutC(C)@\C is the ASCII equivalent of a character, and is printed out
  943. without line termination (I/O buffering may be needed). C=EOL=10 (ASCII LF)
  944. @Comment{does this mean that the character should appear right away, or can
  945. it wait till the EOL is sent???}
  946. will be used to signal end-of-line, C=EOF=26 (ASCII SUB) will be used to
  947. signal end of file.
  948. GetC()@\Returns the ASCII equivalent of the next input character;
  949. C=EOL=10 for end of line, and C=EOF=26 for end of file. Note it is
  950. assumed that GetC does not echo the character.
  951. TimC()@\Returns the runtime since the start of this program, in
  952. milli-seconds, unless micro-seconds is more appropriate. For testing
  953. purposes this routine could also print out the time since last called.
  954. PutINT(C)@\Print C as an integer, until a SYSLISP based Integer printer that
  955. calls XXX-PutC works. This function is used to print integers in the
  956. initial tests before the full I/O implementation is ready.
  957. @comment{Err(C)@\Called in test code if an error occurs, and prints C as an
  958. error number. It should then call Quit() .}
  959. @end(description)
  960. The following functions will probably need to be defined in LAP, using
  961. either the ALM (cmacro level ) or machine specific (TLM) level:
  962. @begin(description)
  963. !%Store!-Jcall(Code-Address,Storage-Address)@\The Storage-Address is
  964. the address of the slot in the SYMFNC table where a jump instruction
  965. to the Code-Address must be stored. This implements a compiled call
  966. to a compiled function. You may have to insert padding or legal code
  967. to make the code match the call to the compiled code. The LAP for the
  968. Dec20 is:
  969. @begin(verbatim)
  970. LAP
  971. '((!*entry !%Store!-Jcall Expr 2)
  972. % CodeAddress, Storage Address
  973. (!*alloc 0)
  974. (!*WOR (reg 1) 8#254000000000)
  975. % Load a JRST in higher-bits
  976. (!*MOVE (reg 1) (memory (reg 2)
  977. (wconst 0)))
  978. (!*EXIT 0));
  979. @end(verbatim)
  980. !%Copy!-Function!-Cell(From-Address,To-Address)@\Copies the SYMFNC
  981. cell located at the From-Address to the SYMFNC cell located at the
  982. To-Address. If your machine has the SYMFNC cell the same width as
  983. that of MEMORY, the following code used on the Dec-20 will work:
  984. @begin(verbatim)
  985. LAP
  986. '((!*entry !%copy!-function!-cell
  987. Expr 2) % from to
  988. (!*alloc 0)
  989. (!*move (memory (reg 1)
  990. (Wconst 0))
  991. (memory (reg 2)
  992. (wconst 0)))
  993. (!*exit 0));
  994. @end(verbatim)
  995. UndefinedFunction()@\In general, we think of the storage of the number
  996. of arguments in a register (Reg NargReg) and the index of the called
  997. function in a register (Reg LinkReg). This function must store the
  998. linkage register in the fluid UndefnCode!* and the Narg register in
  999. the fluid UndefnNarg!*. Finally, it must !*JCALL to the
  1000. UndefinedFunctionAux. The following code implements this function in
  1001. a manner that is portable across all machines that use the LinkReg and
  1002. NargReg as real register:
  1003. @begin(verbatim)
  1004. FLUID '(UndefnCode!* UndefnNarg!*);
  1005. LAP
  1006. '((!*ENTRY UndefinedFunction expr 0)
  1007. % No alloc 0 ? and no LINKE
  1008. % because we don't want to
  1009. % change LinkReg.
  1010. (!*Move (reg LinkReg)
  1011. (Fluid UndefnCode!*))
  1012. (!*Move (reg NargReg)
  1013. (Fluid UndefnNarg!*))
  1014. (!*JCALL UndefinedFunctionAux)
  1015. );
  1016. @end(verbatim)
  1017. Flag(Dummy1,Dummy2)@\A call to this function is automatically
  1018. generated by the compiler, but is never used. So, you must implement
  1019. this function to call your error routine if it is actually called
  1020. (This function will be redefined in a later test). The code for the
  1021. Dec-20 is portable except the linkage to the Machine Dependent Error
  1022. routine Err20:
  1023. @begin(verbatim)
  1024. LAP '((!*ENTRY FLAG expr 2)
  1025. (!*alloc 0)
  1026. (!*MOVE 2 (REG 1))
  1027. (!*LINKE 0 Err20 Expr 1)
  1028. );
  1029. @end(verbatim)
  1030. @end(description)
  1031. Finally, the following three functions must be implemented to allow
  1032. arithmetic operations of sufficient length.
  1033. @begin(description)
  1034. LongTimes(Arg1,Arg2)@\Compute the product of Arg1 and Arg2 and return:
  1035. @begin(verbatim)
  1036. procedure LongTimes(x,y);
  1037. x*y;
  1038. @end(verbatim)
  1039. LongDiv(Arg1,Arg2)@\Compute the quotient of Arg1 and Arg2 and return
  1040. the value:
  1041. @begin(verbatim)
  1042. procedure LongDiv(x,y);
  1043. x/y;
  1044. @end(verbatim)
  1045. LongRemainder(Arg1,Arg2)@\Compute the Remainder of Arg1 with respect
  1046. to Arg2:
  1047. @begin(verbatim)
  1048. procedure LongRemainder(x,y);
  1049. Remainder(x,y);
  1050. @end(verbatim)
  1051. @end(description)
  1052. As a simple test of these routines implement in "F" the following.
  1053. Based on the "MainEntryPointName!*" set in XXX-ASM.RED, and the
  1054. decision as to whether the Main routine is in "F" or in "LISP",
  1055. XXX-MAIN() is the main routine or first subroutine called:
  1056. @begin(verbatim)
  1057. % MAIN-ROUTINE:
  1058. CALL XXX-INIT(0);
  1059. CALL XXX-MAIN(0);
  1060. CALL XXX-QUIT(0);
  1061. % XXX-MAIN(DUMMY):
  1062. INTEGER DUMMY,C;
  1063. CALL XXX-PUTI(1); % Print a 1 for first test
  1064. CALL XXX-PUTC(10); % EOL to flush line
  1065. CALL XXX-PUTI(2); % Second test
  1066. CALL XXX-PUTC(65); % A capital "A"
  1067. CALL XXX-PUTC(66); % A capital "B"
  1068. CALL XXX-PUTC(97); % A lowercase "a"
  1069. CALL XXX-PUTC(98); % A lowercase "b"
  1070. CALL XXX-PUTC(10); % EOL to flush line
  1071. CALL XXX-PUTI(3); % Third test, type "AB<cr>"
  1072. CALL XXX-GETC(C);
  1073. CALL XXX-PUTC(C); % Should print A65
  1074. CALL XXX-PUTI(C);
  1075. CALL XXX-GETC(C);
  1076. CALL XXX-PUTC(C); % Should print B66
  1077. CALL XXX-PUTI(C);
  1078. CALL XXX-GETC(C);
  1079. CALL XXX-PUTI(C); % should print 10 and EOL
  1080. CALL XXX-PUTC(C);
  1081. CALL XXX-PUTI(4); % Last Test
  1082. CALL XXX-ERR(100);
  1083. CALL XXX-PUTC(26); % EOF to flush buffer
  1084. CALL XXX-QUIT(0);
  1085. % END
  1086. @end(verbatim)
  1087. For examples, see PT20:20IO.MAC for DEC-20 version, PHP:HP.TEXT for HP9836
  1088. PASCAL version, PCR:shell for CRAY fortran version.
  1089. @section(LAP-TO-ASM and CMACRO Tests)
  1090. After the basic XXX-ASM.RED file has been written and the XXX-CROSS.EXE has
  1091. been built, and seems to be working, an exhastive set of CMACRO tests
  1092. should be run. The emitted code should be carefully examined, and the
  1093. XXX-CMAC.SL adjusted as seems necessary. Part of the CMACRO tests are to
  1094. ensure that !*MOVEs in and out of the registers, and the ForeignFunction
  1095. calling mechanism work.
  1096. The goal of this test, and the following few sections is to guide you
  1097. in getting the first piece of ALM code to translate to TLM form,
  1098. correctly assemble, and finally execute on the target machine. There
  1099. are a large number of details to worry about, and one will have to
  1100. come back and refine decisions a number of times. Some of the
  1101. decisions you will have to make are based on incomplete information,
  1102. and are based on an interaction of the ALM model, LISP usage
  1103. statistics and unknown oddities of the target machine. In many cases,
  1104. you will have to make the decision just to proceed to get the skeleton
  1105. together, and then immediately come back to fix the code.
  1106. The first major milestone will be to set up enough of the basic
  1107. cross-compiler to be able to translate and assemble the following
  1108. file, called PT:MAIN0.RED:
  1109. @begin(verbatim)
  1110. % MAIN0.RED - A "trivial" file of ALM level LAP to test
  1111. % basic set of tools: LAP-TO-ASM mostly,
  1112. % and CMACROs
  1113. LAP '((!*ENTRY DummyFunctionDefinition Expr 1)
  1114. (!*ALLOC 0)
  1115. (!*MOVE (REG 1) (REG 2))
  1116. (!*EXIT 0));
  1117. END;
  1118. @end(verbatim)
  1119. It consists of a single procedure, written in LAP using only 4
  1120. CMACROs, each quite simple. Notice the procedure defined has a "long"
  1121. name, which may have to be mapped to a simpler symbol (for your
  1122. assembler) by a routine in your xxx-ASM.RED file. The !*ENTRY cmacro
  1123. is actually handled by LAP itself, so there are 3 CMACROs to be
  1124. written:
  1125. @Begin(description)
  1126. (!*ALLOC n)@\Issues instructions to
  1127. allocate a frame of n items on the stack. May also have to issue
  1128. instructions to check stack overflow if the system hardware does not.
  1129. For some machines, with n=0, no code is emitted, while for others,
  1130. !*ALLOC is a good place to establish certain registers for the code
  1131. body. (On the CRAY, the call instruction puts the return address in
  1132. a register, which get saved on the stack in the !*ALLOC).
  1133. (!*MOVE source dest)@\Issue code to move the contents of source to
  1134. the destination. In the MAIN0 example, a register to register move is
  1135. desired. ALM (REG 1) and (REG 2) are almost always allocated to real
  1136. TLM registers. An "anyreg" for the REG mapping will have to be
  1137. written.
  1138. (!*EXIT n)@\Issues code to clean up the stack, by removing the frame
  1139. that was allocated by a corresponding (!*ALLOC n), and then returns
  1140. to the caller, whose address was saved on the stack (usually) by
  1141. an appropriate TLM instruction. (On CRAY, the return address
  1142. is restored to the special register).
  1143. @end(description)
  1144. Here is an example of the processing of this file on the
  1145. DEC-20. On the DEC20 we produce 2 files, the CODE-FILE and the DATA-FILE:
  1146. @begin(verbatim)
  1147. CODE-FILE, MAIN0.MAC
  1148. DATA-FILE, DMAIN0.MAC
  1149. @end(verbatim)
  1150. In summary, here are the initial steps you will have to follow, with some
  1151. indication of the decisions you will have to make:
  1152. @begin(description)
  1153. Decide on PSL Item layout@\How many bits for the tag; should there be
  1154. a GC field; will the tag have to be masked out when the INF field is
  1155. used as an address; should the fields be aligned to byte, word or
  1156. other boundaries to make TAG and INF access faster;
  1157. Decide on TLM register use@\Some registers will be used for the ALM
  1158. registers (rest simulated by memory locations), some used for CMACRO
  1159. temporaries, some for Target OS interface or addressibility, some for
  1160. Linkage registers and some for the stack.
  1161. Stack Implementation@\Should the LISP stack be same as system stack; can we
  1162. use stack hardware; how about stack overflow; which way should stack
  1163. grow; ALM needs to access elements inside the stack relative to the
  1164. stack pointer; the stack pointer needs to be accessible so that the GC
  1165. and other things can access and examine elements.
  1166. @end(description)
  1167. @section(More details on Arcitecture mapping)
  1168. Need to explain why currently 1 tags used, expect more or less in future.
  1169. Perhaps explain which tests are MOST important so at least those can be done
  1170. efficiently, even if others encoded in a funny wya.
  1171. Mention idea that in future may want to put (say) 3 bits of tag in lower
  1172. word, force double or quadword alignment, and put rest of tag in object.
  1173. Mention how some data-types are immediate, others point into memory,
  1174. and some already have headers. Mention possibel user-defind extension types.
  1175. Need to clarify how ALM registers are used so can be mapped to
  1176. TLM or memory.
  1177. Need to explain Stack registers, CMACRO temporary registers, link
  1178. registers.
  1179. Need to explain relative importance of certain CMACROs and order in
  1180. which they should be written and debugged. Make a CMACRO test file to
  1181. be examined by hand, to be assembled, and maybe even run.
  1182. Need to give more detailed steps on how to get MAIN1 running; seems
  1183. like a BIG step. Perhaps break down into smaller MAIN0, just to get
  1184. off the ground. (Ie, might not execute, but should assemble). Give a
  1185. check list of steps. Explain that at first, just get all pieces
  1186. together, then can fill in details once the skeleton is correct, and
  1187. flesh out stubs.
  1188. Explain data-file versus code-file model.
  1189. @section(SysLisp Tests)
  1190. This set of tests involve the compilation to target assmbly code, the
  1191. linking and execution of a series of increasingly more complex tests. The
  1192. tests are organized as a set of modules, called by a main driver. Two of
  1193. these files are machine dependent, associating convenient LISP names and
  1194. calling conventions with the "Foreign" XXX-yyyy function, define
  1195. basic data-spaces, define external definitions of them for inclusion, and
  1196. also provide the appropriate MAIN routine, if needed. These files
  1197. should probably be put on a separte subdirectory of PT: (e.g., PT20:,
  1198. PT68:, etc.)
  1199. The machine dependent files are:
  1200. @begin(description)
  1201. XXX-HEADER.RED@\Is a machine dependent "main" include file, read into each
  1202. MAINn.RED file, to define the data-spaces needed, and perhaps define a main
  1203. routine in LAP, and have the appropriate XXX-MAIN call the "FirstCall"
  1204. function, used to start the body of the test. Also included are the
  1205. interface routines to the "F" coded I/O package. providing a set of LISP
  1206. entry-points to the XXX-yyy functions. This should be copied and edited
  1207. for the new target machine as needed. Notice that in most cases, it simply
  1208. defines "procedure yyyy(x); XXX-yyyy(x);", relying on "ForeignFunction"
  1209. declaration of XXX-yyyy.
  1210. XXX-TEST-GLOBAL-DATA.RED@\This contains a series of external declarations
  1211. to correspond to the Global Data definitions in the above header file
  1212. file. It is automatically included in all but the MAINn module via the
  1213. "GlobalDataFileName!*" option of XXX-ASM.RED.
  1214. @end(description)
  1215. The machine independent test files and drivers are:
  1216. @begin(description)
  1217. MAIN1.RED@\Is a very simple driver, that calls Getc and Putc, does a few
  1218. tests. It does an 'IN "XXX-HEADER.RED";'. The "FirstCall" procedure
  1219. then calls "init", uses "putc" to print AB on one
  1220. line. It should then print factorial 10, and some timings for 1000 calls
  1221. on Factorial 9 and Tak(18,12,6). Build by itself, and run with IO.
  1222. @Comment{This seems to hide the assumption that 10! can be done in the
  1223. integer size of the test implementation.??? }
  1224. SUB2.RED@\Defines a simple print function, to print ID's, Integer's,
  1225. Strings and Dotted pairs in terms of repeated calls on PutC. Defines
  1226. PRIN1, PRIN2, PRINT, PRIN2T, TERPRI and a few other auxilliary print functions
  1227. used in other tests. Tries to print "nice" list notation.
  1228. MAIN2.RED@\Tests printing and access to strings. It peforms most of the
  1229. useful string operations, printing messages to verify that they
  1230. function properly.
  1231. Uses Prin2String to print a greeting, solicit a sequence of
  1232. characters to be input, terminated by "#". Watch how end-of-line is handled.
  1233. Then Print is called, to check that TAG's are correctly recognized,
  1234. by printing a LISP integer, an ID and 2 dotted pairs. Requires SUB2
  1235. and IO modules. Finally, it tests the undefined function calling
  1236. mechanism to verify that it does print out an error message.
  1237. Therefore, the UndefinedFunction routine must be defined in xxx-header
  1238. by this test 2.
  1239. SUB3.RED@\Defines a mini-allocator, with the functions GtHEAP, GtSTR,
  1240. GtVECT, GtCONS, Cons, XCons, NCons, MkVect and MkString. Requires
  1241. primitives in SUB2 module.
  1242. MAIN3.RED@\First Executes a Casetest, trying a variety of Branches and
  1243. Defaults in the case staement. There are a number of calls on Ctest with an
  1244. integer from -1 to 12; Ctest tries to classify its argument using a case
  1245. statement. ConsTest simply calls the mini-allocator version of CONS to build
  1246. up a list and then prints it. Requires SUB2, SUB3 and IO modules.
  1247. SUB4.RED@\Defines a mini-reader, with InitRead, RATOM and READ. It
  1248. has the facilities to convert case input, using the !*RAISE switch
  1249. (and the SetRaise function). This mini-READ does not yet read vectors.
  1250. Requires SUB3, SUB2, and IO modules.
  1251. MAIN4.RED@\First, this test checks to see that EQSTR works. Then it
  1252. tests FindId to see if it can find Identifiers known to exist. After
  1253. that, it tests to see if new Id's can be found and then found in the
  1254. same place. Then a test loop is created that calls RATOM, printing
  1255. the internal representation of each token. Type in a series of id's,
  1256. integer's, string's etc. Watch that the same ID goes to same place.
  1257. When the user types a Q, it should go into a READ-PRINT loop. You
  1258. should type in a variety of S-Expressions, checking that they are
  1259. correctly printed. Once again, you should finally type a Q to exit.
  1260. Requires SUB3, SUB2 and IO modules.
  1261. SUB5.RED@\Defines a mini-EVAL. Does not permit user defined functions.
  1262. Can eval ID's, numbers, and simple forms. No LAMBDA expressions can be
  1263. applied. FEXPR Functions known are: QUOTE, SETQ, COND, PROGN and
  1264. WHILE. The Nexpr LIST is also known. Can call any compiled EXPR, with
  1265. the standard 15 arguments. Requires SUB4, SUB3, SUB2 and I/O.
  1266. MAIN5.RED@\Starts a mini-READ-EVAL-PRINT loop, to which random simple
  1267. forms may be input and evaluated. When ready, input (TESTSERIES) to
  1268. test PUT, GET and REMPROP. Then an undefined function is called to
  1269. test the UNDEFINED function mechanism. Requires SUB5, SUB4, SUB3,
  1270. SUB2 and IO modules. Note that input ID's are case raised (!*RAISE
  1271. has been set to T by default) so input can be in in lowercase for
  1272. built-in functions. Terminates on Q input.
  1273. SUB6.RED@\Defines a more extensive set of primitives to support the
  1274. EVAL, including LAMBDA expressions, and user defined EXPR, FEXPR,
  1275. NEXPR and MACRO functions. This is a complete model of PSL, but has a
  1276. restriced set of the PSL functions present. Can call any compiled or
  1277. interpreted function. Requires SUB5, SUB4, SUB3, SUB2 and I/O.
  1278. MAIN6.RED@\Tests the full PSL BINDING modules (PI:BINDING.RED and
  1279. PT:P-FAST-BINDER.RED). Call the (TESTSERIES) routine to do a test of
  1280. Binding, the Interpretive LAMBDA expression evaluator, and binding in
  1281. compiled functions. Requires SUB6,SUB5, SUB4,
  1282. SUB3, SUB2 and IO modules. !*RAISE is once again on. Terminates on Q
  1283. input.
  1284. SUB7.RED@\A set of routines to define a minimal file-io package, loading
  1285. the machine independent files: PT:SYSTEM-IO.RED and PT:IO-DATA.RED, and a
  1286. machine dependent file XXX-SYSTEM-IO.RED. The latter file defines
  1287. primitives to OPEN and CLOSE files, and read and write RECORDS of some
  1288. size. The following definitions are used in the routines:
  1289. @begin(verbatim)
  1290. FileDescriptor: A machine dependent
  1291. word to references an open file.
  1292. FileName: A Lisp string
  1293. @end(verbatim)
  1294. @begin(description)
  1295. SYSCLEARIO()@\Called by Cleario to do any machine specific initialization
  1296. needed, such as clearing buffers, initialization tables, setting interrupt
  1297. characters, etc.
  1298. SysOpenRead(Channel,FileName)@\Open FileName for input and return a file
  1299. descriptor used in later references to the file. Channel may be used to
  1300. index a table of "unit" numbers in FORTRAN-like systems.
  1301. SysOpenWrite(Channel,FileName)@\Open FileName for Output and return a file
  1302. descriptor used in later references to the file. Channel may be used to
  1303. index a table of "unit" numbers in FORTRAN-like systems.
  1304. SysReadRec(FileDescriptor,StringBuffer)@\Read from the FileDescriptor, a
  1305. record into the StringBuffer. Return the length of the string read.
  1306. SysWriteRec (FileDescriptor, StringToWrite, StringLength)@\ StringLength
  1307. characters from StringToWrite from the first position.
  1308. SysClose (FileDescriptor)@\Close FileDescriptor, allowing
  1309. it to be reused.
  1310. SysMaxBuffer(FileDesc)@\Return a number to allocate the file-buffer
  1311. as a string; this should be maximum for this descriptor.
  1312. @end(description)
  1313. RDS, WRS, OPEN, CLOSE, DSKIN and TYPEFILE are defined.
  1314. MAIN7.RED@\Starts the LISP READ-EVAL-PRINT loop tested before, and now
  1315. permits the user to test io. Call (IOTEST). Other functions to try are
  1316. (OPEN "foo" 'OUTPUT), (WRS n), (RDS n) etc. [Now the GETC and PUTC IO
  1317. routines in XXX-HEADER will finally call the file-oriented
  1318. IndependentReadChar and IndependentWriteChar]. Also includes the
  1319. standard PSL-TIMER.RED (described below), which can be invoked by
  1320. doing (DSKIN "PT:TIME-PSL.SL"). Since the garbage collector not yet
  1321. present, may run out of space.
  1322. FIELD.RED@\A a set of extensive tests of the Field and Shift functions.
  1323. Needs a WCONST BitsPerWord defined in XXX-HEADER.RED. Build by itself,
  1324. and execute with the IO support.
  1325. @end(description)
  1326. Test set "n" is run by using a set of command files to set up
  1327. a multi-module program. These files are stored on the
  1328. approriate subdirectory (PT20: for the DEC20). Note that each module
  1329. usually produces 2-3 files ("code", "data" and "init")
  1330. @begin(Enumerate)
  1331. First Connect to the Test subdirectory for XXX:
  1332. @verbatim[
  1333. @@CONN PTxxx:]
  1334. Then initialize a fresh symbol table for program MAINn, MAINn.SYM:
  1335. @verbatim[
  1336. @@MIC FRESH MAINn]
  1337. Now successively compile each module, SUB2..SUBn
  1338. @verbatim[
  1339. @@MIC MODULE SUB2,MAINn
  1340. @@MIC MODULE SUB3,MAINn
  1341. @@MIC MODULE SUBn,MAINn]
  1342. Now compile the MAIN program itself
  1343. @verbatim[
  1344. @@MIC PROGRAM MAINn]
  1345. As appropriate, compile or assemble the output "F" language modules
  1346. (after shipping to the remote machine, removing tabs, etc..). Then
  1347. "link" the modules, with the XXX-IO support, and execute. On the
  1348. DEC-20, the
  1349. @verbatim[
  1350. @@EX @@MAINn.CMD]
  1351. command files are provided as a guide]
  1352. Rather than including output from some older test runs, we insist that
  1353. you run the tests yourself on the HOST machine to be absolutley sure
  1354. of what output they produce, and what input is expected. Also, if
  1355. errors occur during testing, the examination of the HOST tests will
  1356. help. This will also help as additonal tests are added by new
  1357. implementors.
  1358. @end(enumerate)
  1359. @section(Mini PSL Tests)
  1360. The next step is to start incorporating portions of the PSL kernel into the
  1361. test series (the "full" Printer, the "full" reader, the "full" Allocator,
  1362. the "full" Eval, etc.), driving each with more comprehensive tests. Most of
  1363. these should just "immediately" run. There some peices of Machine specific
  1364. code that have to be written (in LAP or SYSLISP), to do channel I/O,
  1365. replacing the simple XXX-IO; to do fast APPLY; Fluid Binding and
  1366. Arithmetic. This set of tests will help check these peices out before
  1367. getting involved with large files.
  1368. @section(Full PSL Tests)
  1369. Now that PSL seems to be running, a spectrum of functional tests and timing
  1370. tests should be run to catch any oversights, missing modules or bugs, and as a
  1371. guide to optimization. The following tests exist:
  1372. @Description[
  1373. PSLTEST.SL@\A fairly comprehensive test of the Standard LISP subset of PSL.
  1374. Do (DSKIN "pt:psltest.sl"). There are a few tests of the error mechanism that
  1375. have to be "pushed" through for a full test.
  1376. MATHLIB.TST@\A series of tests of MATHLIB. First LAOD MATHLIB; into RLISP,
  1377. then do IN "MATHLIB.TST"; .
  1378. PSL-TIMER.SL, TIME-PSL.SL@\A standard timimg test covering PSL basics.
  1379. Compile PSL-TIMER.SL into kernel, or with resident compiler, then
  1380. (LAPIN "PT:TIME-PSL.TEST").
  1381. ]
  1382. @section(Stabilize Basic PSL)
  1383. Finally, compile the kernel modules of @PSL, link with the
  1384. additional machine-dependent modules, and @PSL (hopefully) comes right
  1385. up@Foot[Presently an unlikely possibility, as the system may still change
  1386. arbitrarily from under the implementor!]. Additional work is underway to
  1387. develop a much more comprehensive test set, that will not change while the
  1388. implementor is proceeding with the bootstrap; unfortunately, @PSL is still
  1389. undergoing continuous development at Utah, resulting in some "out-of-phase"
  1390. communication problems.
  1391. After the basic interpreter is working, additional modules can also be
  1392. compiled from @xlisp to X and linked with the kernel. The most common of these
  1393. might be the @RLISP parser and even the @REDUCE@cite[Hearn73] computer
  1394. algebra system@Comment{???or should this be symbolic algebra system??? }. As
  1395. more files are compiled to machine X and linked, the task
  1396. becomes more tedious. At this point, we need to consider the bootstrap of
  1397. the @ei[Resident] Compiler, LAP and fast-loader (FASL). The most common way
  1398. to build and maintain large @PSL programs is to build the kernel @PSL with a
  1399. resident FASLIN for loading fast-load files, and then compile required
  1400. modules to FASL (xxxx.b) files. A @PSL-based system is built by loading the
  1401. appropriate FASL files, and then saving the @dq[core] image as an
  1402. executable file. On some machines this is easy; on others it is quite
  1403. hard; see the discussions below.
  1404. These additional steps are:
  1405. @begin(enumerate)
  1406. @i[Implement Resident LAP]. Using an existing LAP.RED as a guide, write a
  1407. table-driven program that does the actual assembly of code written in
  1408. LAP form for machine X, to the appropriate bit-patterns; the details of
  1409. this process are discussed at length in @dq[Reading, Writing and Testing
  1410. LAP]@cite[Griss82h]. @PSL provides many tools to make this task quite
  1411. easy, but the process is still very machine dependent. Future work may
  1412. lead to the use of an architectural description language.
  1413. @i[Test LAP]. The depositing of bit-patterns into
  1414. BPS@Foot[BPS is Binary Program Space. The name BPS is a remnant of
  1415. @xlisp 1.6. The desire to have a separate code space is based on the desire
  1416. to @ei<not> relocate compiled code.] needs to be checked. Check also that
  1417. procedures can be constructed with LAP, compile LAP into the kernel,
  1418. and assemble some small files.
  1419. @i[Implement FASLIN]. FASLIN requires some binary I/O and other small
  1420. support procedures described in a separate section below.
  1421. @i[Implement FASLOUT]. Once LAP works, the FASLOUT process seems quite
  1422. simple, requiring only the Binary I/O etc@. used by FASLIN. It should be
  1423. possible to get xxxx-FASLOUT working on an existing @PSL, and cross-FASL
  1424. for machine X. This has not yet been tested. When it works, FASLIN could be
  1425. made part of the @PSL kernel very early on.
  1426. @i[Test FASL files]. Check that FASL files can be easily written and read.
  1427. @Comment{What kind of tests should be done??? This "easily written and
  1428. read" sounds like apple pie, but it would seem that a piece of SYSLISP
  1429. could be written that would give the FASL mechanism a good work out,
  1430. perhaps two pieces with cross references to one another. }
  1431. @i[Implement and test Core saving]. Determine how to save the image of an
  1432. executing program, so that it can be restarted. We only require that it be
  1433. restarted at the beginning, not where it was when it was saved. We usually
  1434. change the MAIN entry function to call an appropriate TopLoop.
  1435. See the more extensive discussion below.
  1436. @foot[Actually, the only part which
  1437. must be saved is the impure data part; the pure data section, the pure code
  1438. section and the control stack need not be preserved - however, if only the
  1439. impure data part is saved, the restart mechanism must map the pure data and
  1440. code back in. For an example of programs which do selective dumping see
  1441. EMACS MKDUMP and @interlisp SYSOUT. @Comment{We probably need to think
  1442. about some way of loading the libraries similar to EMACS, such that it is
  1443. easy to reload the libraries (particularly if they remain pure).}]
  1444. @end(enumerate)
  1445. @chapter(DETAILED REFERENCE MATERIAL)
  1446. @section(Details on the ALM Operand forms)
  1447. The following are references to a variety of memory locations: In the
  1448. current implementation the following 4 reference the same location,
  1449. the SYMVAL cell of the associated ID. This is the contents of the
  1450. location SYMVAL+AddressingUnitsPerItem*IDLOC(id):
  1451. @begin(verbatim)
  1452. (FLUID name:id)
  1453. (!$FLUID name:id)
  1454. (GLOBAL name:id)
  1455. (!$GLOBAL name:id)
  1456. @end(verbatim)
  1457. @begin(description)
  1458. (WVAR name:id)@\This references the contents of the static location
  1459. named by the ID.
  1460. @end(description)
  1461. The following are all constants, either absolute bit-patterns, or
  1462. address expressions.
  1463. @begin(description)
  1464. (WARRAY name:id)@\Address of the base of a static array
  1465. (WSTRING name:id)@\Address of the base of a static string
  1466. (WCONST expr:wconst-expression)@\Any constant expression, either
  1467. numeric, a declared constant, addresses of thinsg that could also be
  1468. passed as WARRAY or WSTRING, or other expressions that can be handled
  1469. by the TLM assembler.
  1470. (IMMEDIATE wconst-expression:any)@\Really only introduced as a "tag"
  1471. to make later processing easier; a constant is either an explict
  1472. constant or (IMMEDIATE expression). This is default TLM mode wrapped
  1473. when RESOLVEOPERAND is "unsure". We are confused about the
  1474. differences between WConsts and Immediates in some cases.
  1475. (QUOTE s-exp:s-expression)@\Is the constant bit-pattern representing a
  1476. tagged PSL item.
  1477. (LABEL l:id)@\Reference to a local location (symbol) in the current
  1478. set of ALM instructions, processed in a single call to LAP, usually a
  1479. single function.
  1480. (MEMORY base:any offset:wconst-expression)@\This is the basic ALM "indexing"
  1481. operation, and represents the contents of the location (base)+offset.
  1482. (CAR base:any)@\Reference the contents of the ITEM pointed at by
  1483. INF(base). It is assumed that base is actually a PAIR (not checked).
  1484. In principle this is sort of like (MEMORY (INF base) (WCONST 0)).
  1485. (CDR base:any)@\Refernce the contents of the ITEM pointed at by
  1486. INF(base). It is assumed that base is actually a PAIR (not checked).
  1487. In principle this is sort of like (MEMORY (INF base) (WCONST
  1488. AddressingUnitsPerItem)).
  1489. (FRAME n:integer)@\Contents of the n'th location in the current stack
  1490. frame. In most versions of the ALM, there is an explicit register,
  1491. (REG ST), which points at the base of the frame. The stack grows in
  1492. some direction determined by features on the TLM, so that this could
  1493. in principle be expressed as (MEMORY (reg ST)
  1494. (WCONST (times StackDirection -1 AddressingUnitsPerItem (SUB1 n))))
  1495. (REG reg-descriptor:{integer,id})@\Reference to an ALM register.
  1496. (LIT [any-instruction-or-label:{list,id}])@\Plants the instruction sequence
  1497. elswhere, and leaves a reference to its start. Essetially equivalent to
  1498. (label g), with g starting a block of the instructions, in "literal"
  1499. space.
  1500. (LABELGEN tag:id)@\A mechnism (with LABELREF) to generate and
  1501. reference a label local to a particular CMACRO pattern. Meant mostly
  1502. for implementing conditional jumps of various kinds.
  1503. (LABELREF tag:id)@\Reference a label that was assigned to the Tag.
  1504. @end(description)
  1505. The following set of ALM instruction forms are used to define constant data
  1506. which is intermixed with instructions.
  1507. @begin(description)
  1508. (FULLWORD [exp:wconst-expression])@\The expressions are deposited in
  1509. successive "words" (item-sized units).
  1510. (HALFWORD [exp:wconst-expression])@)\The expressions are deposited in
  1511. succesive halfwords (two per item-sized unit).
  1512. (BYTE [exp:wconst-expression])@\The expressions are deposited in successive
  1513. "bytes" (character-sized units).
  1514. (STRING s:string)@\The ASCII values of the characters of the string are
  1515. deposited in successive bytes, terminated by a zero byte.
  1516. (FLOAT f:float)@\The 2 word bit pattern for the floating point number is
  1517. deposited.
  1518. @end(description)
  1519. These must be processed by the TLM to ASM translator (and later by the resident
  1520. assmbler).
  1521. @subsection(Standard @CMACRO@xs)
  1522. The following are the basic @CMACRO@XS; additional @CMACRO@XS are of course
  1523. frequently added either to aid in writing the @CMACRO@XS (a @CMACRO
  1524. @ei[subroutine]), or to aid some aspect of the machine-specific details.
  1525. Recall that each @CMACRO returns a list of LAP instructions (which are simpler
  1526. to generate code for, although it may be a more complex list of operations)
  1527. representing the appropriate expansion of this @CMACRO (these may also call
  1528. other @CMACRO@XS). These instructions are then recursively processed by the
  1529. @CMACRO expander (i.e@. LAP). The !*MOVE @CMACRO is very commonly used for
  1530. this purpose, to get a @ei[general] operand into a register, so the
  1531. particular @CMACRO can operate on it.
  1532. The following @CMACRO@XS deal with function ENTRY, EXIT and function call:
  1533. @begin(Description)
  1534. !*Entry((FunctionName FunctionType NumberOfArguments)@\Normally the user
  1535. does not code this @CMACRO, since it is processed completely by LAP
  1536. itself. It is used to indicate the start of a function (or entry point
  1537. within a function). Normally just plants a label corresponding to
  1538. FunctionName.
  1539. !*Exit (N)@\Exits (@dq[returns]) from procedure, deallocating N items, as
  1540. needed. N corresponds to the N items allocated by !*Alloc, see below.
  1541. !*Link (FunctionName FunctionType NumberOfArguments)@\If FunctionName
  1542. is flagged 'FOREIGNFUNCTION, emit a call (!*ForeignLink FunctionName
  1543. FunctionType NumberOfArguments), else emit a (!*Call FunctionName).
  1544. This is the basic function call macro. It assumes the appropriate
  1545. number of arguments are in the registers (previously loaded) in the
  1546. registers, @w[(REG 1) ... (REG n)]. We currently do not check either
  1547. NumberOfArguments or FunctionType, so a simpler @CMACRO, !*CALL is
  1548. provided for basic function call.
  1549. !*Call (FunctionName)@\Basic or @dq[Standard] function call. Checks
  1550. to see if FunctionName has an 'OPENCODE property, and returns the
  1551. stored instruction list if any. Otherwise it looks for an
  1552. appropriate pattern table stored by DEFCMACRO under
  1553. 'CMACROPATTERNTABLE, as described above.
  1554. !*LinkE (DeAllocCount FunctionName FunctionType NumberOfArguments)@\An
  1555. @dq[exit] call. Emitted when the caller does not need to examine the
  1556. result, but returns it directly. The !*LinkE @CMACRO does not save
  1557. the return address, so a return from the called function is not to
  1558. this caller, but to the previous !*LINK. Essentially deallocates the
  1559. frame (if any), does either an ordinary !*ForeignCall and then
  1560. !*Exit(0), or does a !*JCALL which does no return address saving.
  1561. !*JCall (FunctionName)@\First checks for an EXITOPENCODE table, then
  1562. for an OPENCODE table (followed by a normal return, !*EXIT(0)) or
  1563. looks for the general '!*JCALL table. The generated code is supposed
  1564. to call the function without saving a return address, essentially a
  1565. JUMP.
  1566. !*ForeignLink (FunctionName FunctionType NumberOfArguments)@\
  1567. This is the basic linkage to a foreign function. It assumes the appropriate
  1568. number of arguments are in the registers (previously loaded) in the
  1569. registers, @w[(REG 1) ... (REG n)]. It then pushes the arguments on a
  1570. stack, or moves them to a global location, as appropriate and
  1571. transfers to the ForeignFunction in an appropriate manner (REWRITE).
  1572. Some care must be taken in interfacing to the LISP world, with cleanup
  1573. on return.
  1574. @end(description)
  1575. The following @CMACRO@XS handle the allocation and deallocation of a Frame of
  1576. temporary items on the stack, used for argument saving, PROG local
  1577. variables, etc.
  1578. @Begin(description)
  1579. !*Alloc (N)@\Allocates a frame of N @Value(Times)
  1580. AddressingUnitsPerItem units by adjusting the stack (generally
  1581. increasing it) by using a stack operation that invokes an overflow
  1582. signal, if any. Otherwise the stack register should be compared
  1583. against an appropriate UpperBound. It passes N @Value(Times)
  1584. AddressingUnitsPerItem to the pattern, to be used for indexing or
  1585. displacement. Note some stacks grow in the @ei[negative] direction,
  1586. and this is a major source of @CMACRO errors. Currently, there is a
  1587. major problem, that this MACRO may not be called recursively. FIX in
  1588. the future.
  1589. !*DeAlloc (N)@\Decrement stack by N @Value(Times) AddressingUnitsPerItem units,
  1590. deallocating the temporary FRAME. Passes N*AddressingUnitsPerItem to the
  1591. pattern.
  1592. @end(Description)
  1593. The following @CMACRO@XS deal with the binding and unbinding of FLUID
  1594. variables used as Lambda or Prog parameters. They are usually quite
  1595. complex to code. The basic idea is to follow the call on a Lambind or
  1596. Progbind procedure by a compact table of Fluid addresses or offsets. The
  1597. call may have to be special, and @ei[internal], so that the support code
  1598. (usually hand-coded in LAP) can pick up and process each entry in the
  1599. compact table.
  1600. @begin(Description)
  1601. !*LamBind(Registers FluidsList)@\Registers is of the form
  1602. @w[(REGISTERS (REG a) (REG b) ... (REG c))], and FluidsList is of the form
  1603. @w[(NONLOCALVARS (FLUID f) ...)]. The intent of this @CMACRO is to save the
  1604. current value of each
  1605. Fluid in the list on the Binding Stack, paired with the Fluid name. Then
  1606. the value in the corresponding register is stored into the Value cell.
  1607. Later unbinding by !*FreeRstr or the Catch and Throw mechanism, restores
  1608. the saved value.
  1609. !*ProgBind (FluidsList)@\Emitted for Fluid variables in Prog parameter
  1610. lists. Idea is as above, but stores a NIL in the value cell after saving
  1611. the old contents. Usually implemented as
  1612. @w[(!*LamBind '(REGISTERS) FluidsList))], but may be able to use a more compact
  1613. table.
  1614. !*FreeRstr (FluidsList)@\Restores the old values of the fluids. Since we use
  1615. a special binding stack with Fluid names stored on it, we really only need the
  1616. number to unbind. [Perhaps we should use !*UnBind(N) to make this decision
  1617. explicit.]
  1618. @end(Description)
  1619. Data-moving @CMACRO@XS. Most of the work is done by !*MOVE, with some PUSH/POP
  1620. optimizations if the !*MOVE is close to an !*ALLOC or !*DEALLOC. Other data
  1621. moving may be done in conjuction some of the operations, such as !*WAND,
  1622. !*WOR, !*WPLUS2, !*WMINUS, etc.
  1623. @begin(Description)
  1624. !*Move (Source Destination)@\The major work horse. Generates code to move
  1625. SOURCE to DESTINATION. Uses (REG t1) and (REG t2) as temporary
  1626. registers if needed. First simplifies destination (@ei[Anyreg resolution]),
  1627. using (REG t1) as a temporary if needed. It then simplifies the SOURCE,
  1628. using the as temporary either the destination (if a register), or (REG
  1629. t2). Finally, the !*MOVE table is used.
  1630. !*Push (Arg1)@\Emitted during peep hole optimization to
  1631. replace a pair !*ALLOC(1) and !*MOVE(arg1,(FRAME 1)). This is a very common
  1632. optimization.
  1633. !*Pop (Arg1)@\Emitted during the peep hole phase
  1634. to replace the common pair !*MOVE((FRAME 1),Arg1), followed by
  1635. !*DEALLOC(1). This modifies the argument ARG1.
  1636. @end(Description)
  1637. The JUMP @CMACRO@XS are given the label as the first operand, but
  1638. they pass the label as the third (and last) argument to the pattern
  1639. (usually as ARGTHREE) after resolving the other arguments. The label
  1640. is tagged (LABEL Label).
  1641. @begin(Description)
  1642. @begin(group)
  1643. !*Lbl (Label)@\This @CMACRO is emitted when a label is inserted in the
  1644. generated code. Its body is usually trivial, but can be more complex
  1645. if some form of short and long jump optimization is attempted.
  1646. @hinge
  1647. !*Jump (Label)@\Emit code to jump to Label. Label often involves memory.
  1648. @hinge
  1649. !*JumpEQ (Label Arg1 Arg2)@\Generate code to JUMP if Arg1 EQ Arg2.
  1650. Used for @xlisp EQ and @syslisp WEQ.
  1651. @hinge
  1652. !*JumpNotEQ (Label Arg1 Arg2)@\Generate code to JUMP if not(Arg1 EQ Arg2).
  1653. Used for @xlisp EQ and @syslisp WEQ.
  1654. @hinge
  1655. !*JumpWLessP (Label Arg1 Arg2)@\Generate code to JUMP if Arg1 @Value(LT) Arg2.
  1656. Used for @syslisp WLESSP.
  1657. @hinge
  1658. !*JumpWGreaterP (Label Arg1 Arg2)@\Generate code to JUMP if Arg1 @Value(GT) Arg2.
  1659. Used for @syslisp WGREATERP.
  1660. @hinge
  1661. !*JumpWLEQ (Label Arg1 Arg2)@\Generate code to JUMP if Arg1 @Value(LTE) Arg2.
  1662. Used for @syslisp WLEQ.
  1663. !*JumpWGEQ (Label Arg1 Arg2)@\Generate code to JUMP if Arg1 @Value(GTE) Arg2.
  1664. Used for @syslisp WGEQ.
  1665. !*JumpType (Label Arg TypeTag)@\Generate code to JUMP if TAG(Arg)
  1666. @Value(Eq) TypeTag. The TypeTags are small integers, defined in the
  1667. xxxx-Data-Machine file. This @CMACRO is emitted for opencoded Type
  1668. checking, such as IDP(x), etc. It should be implemented very efficiently.
  1669. Instead of extracting the TAG and comparing with the small integer, it may
  1670. be easier just to mask the INF portion of Arg, and compare with a shifted
  1671. version of TypeTag (previously saved, of course).
  1672. @hinge
  1673. !*JumpNotType (Label Arg TypeTag)@\Generate code to JUMP if not(TAG(Arg)
  1674. @Value(Eq) TypeTag). See comments above.
  1675. @hinge
  1676. !*JumpInType (Label Arg TypeTag)@\Generate code to JUMP if Tag(Arg) is in the
  1677. range @w([0 ... TypeTag,NegInt]). This is used to support the numeric
  1678. Types, which are encoded as 0,...M, and -1 for negative Inums. Thus NumberP,
  1679. FixP, etc@. have to test a range. Note that NegInt is tested specially.
  1680. @hinge
  1681. !*JumpNotInType (Label Arg TypeTag)@\Generate code to JUMP if Tag(Arg) is
  1682. not in the range @w([0 ... TypeTag, NegInt]). See above comment.
  1683. @hinge
  1684. !*JumpOn (Register LowerBound UpperBound LabelList)@\Used to support the
  1685. CASE statement. This is usually written by hand and no pattern is used.
  1686. It tests if Register is in range LowerBound @value[Lte] Register
  1687. @value[Lte] UpperBound; if so, it jumps to the appropriate label in
  1688. labellist, using (Register @value[MinusSign] LowerBound) as the index. If
  1689. not in range, it Jumps to a label planted at the end of the label table. In
  1690. some implementations, the label table has to be a jump table.
  1691. @hinge
  1692. !*JumpWithin (Label LowerBound UpperBound)@\This is also used to support
  1693. the CASE statement, in the situation where the overall label range is
  1694. large, and there are many sub-ranges. This generates code to JUMP to Label
  1695. if LowerBound @value(LTE) (REG 1) @value(LTE) UpperBound. A default version
  1696. uses !*JumpWLessP and !*JumpWLeq tests. [Perhaps should be modified to use
  1697. ANY reg].
  1698. @end(group)
  1699. @end(Description)
  1700. The following @CMACRO@XS perform simple computations on their arguments.
  1701. Binary operations take two arguments, (Dest Source), and leave the result
  1702. in DEST.
  1703. @begin(description)
  1704. !*MkItem (Arg1 Arg2)@\Computes Arg1 @Value(Eq) Item(Arg1,Arg2); construct an
  1705. Item into Arg1 from the tag in Arg1 and Information part in ARg2. May have
  1706. to shift and mask both Arg1 and Arg2. Equivalent to
  1707. !*WOR(!*Wshift(Arg1,24),!*Wand(Arg2,16#FFFFFF)) on the 68000 [This may
  1708. actually use a stored preshifted version of the tag].
  1709. [[[[[Check the ORDER!!!! and use parameters rather than 24 and fffff]]]]]]
  1710. !*WPlus2 (Arg1 Arg2)@\Compute Arg1 @Value(Eq) Arg1 + Arg2. Look for special
  1711. cases of 1, -1, 0, etc. Note on the 68000 it checks for a small integer, i.e.
  1712. -8..8 since these are done with a @dq[QUICK] instruction. [Ignore overflow?]
  1713. !*WDifference (Arg1 Arg2)@\Compute Arg1 @Value(Eq) Arg1-Arg2. Look for special
  1714. cases of 1, -1, 0, etc.
  1715. !*WTimes2 (Arg1 Arg2)@\Compute Arg1 @Value(Eq) Arg1*Arg2. It first looks to
  1716. see if Arg2 is constant and a power of 2. If so, it emits a corresponding
  1717. !*Ashift(Arg1,PowerOfTwo Arg2). This check for special cases is in the
  1718. pattern.
  1719. !*AShift (Arg1 Arg2)@\Shift Arg1 by Arg2, using Arithmetic shift. Used to
  1720. support !*WTIMES2. Should do appropriate Sign Extend.
  1721. !*WShift (Arg1 Arg2)@\Shift Arg1 by Arg2, logically, doing 0 fill.
  1722. !*WAnd (Arg1 Arg2)@\Arg1 @Value(Eq) Arg1 AND Arg2. BitWise AND, each bit of
  1723. Arg1 is 1 only if BOTH corresponding bits of Arg1 and Arg2 are 1.
  1724. !*WOr (Arg1 Arg2)@\Arg1 @Value(Eq) Arg1 OR Arg2. BitWise OR.
  1725. !*WXOr (Arg1 Arg2)@\Arg1 @Value(Eq) Arg1 Xor Arg2.
  1726. !*WMinus (Arg1 Arg2)@\Arg1 @Value(Eq) @Value(MinusSign) Arg2.
  1727. !*WNot (Arg1 Arg2)@\Arg1 @Value(Eq) Logical NOT Arg2.
  1728. !*Loc (Arg1 Arg2)@\Arg1 @Value(Eq) Address (Arg2).
  1729. @end(description)
  1730. The following are important optimizations, that may be initially
  1731. implemented as procedures:
  1732. @begin(description)
  1733. !*Field (Arg1 Arg2 Arg3 Arg4)@\Arg1 @Value(Eq) Extract Field of Arg2
  1734. starting at Bit Arg3, of Length Arg4. Bits are numbered
  1735. 0...Size(Word)@Value(MinusSign)1. The most significant bit is numbered 0 in
  1736. our model. There is an assumption that Arg3 Arg4 are constants.
  1737. !*SignedField (Arg1 Arg2 Arg3 Arg4)@\Arg1 @Value(Eq) Extract Field of Arg2
  1738. starting at Bit Arg3, or Length Arg4. Bits are numbered
  1739. 0...Size(Word)@Value(MinusSign)1. The field is to be sign extended into
  1740. Arg1.
  1741. !*PutField (Arg1 Arg2 Arg3 Arg4)@\Deposit into Arg1 a field of Arg2
  1742. starting at Bit Arg3, or Length Arg4. Bits are numbered
  1743. 0...Size(Word)@Value(MinusSign)1. @end(Description)
  1744. @section(Organization of the Compiler and Assembler Source Files)
  1745. The code is organized as a set of common files kept on the PC:
  1746. directory, augmented by machine-specific files kept on other
  1747. directories@Foot[These generally have logical names of the form
  1748. PxxxC: where xxx is the root name of the directories for a given machine/OS
  1749. implementation.]. The @dq[skeletal] common files and machine-specific
  1750. files (mostly kept as compiled FASL files) make up the CROSS compiler
  1751. and assembler. The machine-specific files customize the compiler for
  1752. the specific target machine and assembler (currently we compile for
  1753. @DEC20, @VAX750, @Apollo, @WICAT, and Cray-1).
  1754. @subsection(Common Files)
  1755. The machine-independent part of compiler is kept as
  1756. PL:COMPILER.B@Foot[PL: is <PSL.LAP> or ~psl/lap.],
  1757. built by PC:COMPILER.CTL. It consists of the files:
  1758. @begin(description)
  1759. PC:COMPILER.RED@\The basic compiler
  1760. PC:COMP-DECLS.RED@\Common declarations configuring the compiler:
  1761. installing the compiler specific functions, such as PA1FNs, COMPFNs,
  1762. OPENFNS etc. These are described in the compiler chapter.
  1763. PC:PASS-1-LAP.SL@\Basic PASS1 of @CMACRO/LAP process.
  1764. PC:ANYREG-CMACRO.SL@\The @CMACRO and @anyreg pattern matcher and support
  1765. functions.
  1766. PC:COMMON-CMACROS.SL@\Standard or default @CMACRO@xs and @anyreg@xs used by
  1767. most implementations.
  1768. PC:COMMON-PREDICATES.SL@\Useful predicates to aid in writing the @CMACRO@xs.
  1769. @end(Description)
  1770. In addition, the following file is needed:
  1771. @Begin(Description)
  1772. PC:LAP-TO-ASM.RED@\Standard functions to convert LAP into machine-dependent
  1773. assembly code.
  1774. @end(Description)
  1775. @subsection(Machine-Specific Files)
  1776. For machine xxxx, the files:
  1777. @begin(description)
  1778. xxxx-COMP.RED@\Machine-Specific Compiler Patterns and Function installations.
  1779. This file may have some special @CMACRO support in it@Foot{This is the case
  1780. of extending the abstract machine for a particular implementation.}.
  1781. xxxx-CMAC.SL@\Machine-Specific @CMACRO@xs and @anyreg@xs.
  1782. xxxx-ASM.RED@\Definition of FORMATS, and special addressing mode conversion
  1783. functions, declaration Pseudos, etc.
  1784. xxxx-DATA-MACHINE.RED@\Smacros and constants to define @syslisp macros
  1785. needed for the implementation. This file associates @syslisp functions with
  1786. @CMACRO@xs for special cases.
  1787. @end(description)
  1788. Finally, during the compilation of XXXX- user files, the following two files:
  1789. @begin(description)
  1790. xxxx:GLOBAL-DATA.Red@\Describes GLOBAL symbols used everywhere.
  1791. @end(description)
  1792. @subsection(Building the CROSS Compiler)
  1793. [For the moment, see the distribution guide for the Host machine].
  1794. @section(Design of LAP Format)
  1795. The argument to the function LAP is a list of lists and atoms. The
  1796. lists are instructions, pseudo-ops and @cmacro@xs, and the atoms are labels
  1797. which are used to refer to positions in the code. Note these need not
  1798. be IDs, but can also be strings, saving on ID space. Instructions
  1799. should be of the form @w[(@i(opcode) . @i(operands))], where @i(opcode) is a
  1800. mnemonic for an opcode, and @i(operands) is a list of operands. Each
  1801. operand should be either an integer, which represents an immediate integer
  1802. operand, a label, or a list of the form @w[(@i(mode) . @i(suboperands))]. A
  1803. @i(mode) is an addressing mode, such as INDEXED or INDIRECT on the PDP-10,
  1804. and DISPLACEMENT, DEFERRED, AUTOINCREMENT, etc@. for the VAX-11. REG must
  1805. exist on all machines; others will be chosen as appropriate for the system.
  1806. Remember that these are mainly used for @cmacro expansions rather than
  1807. for writing code, so choose names for mnemonic value rather than brevity.
  1808. @i(Suboperands) may also be operands, or they may be specific to the mode,
  1809. e.g@. register names.@comment(more on @xlisp specific ones, QUOTE and FLUID)
  1810. See also the READING/WRITING/TESTING of LAP operating note@cite[Griss82h].
  1811. @comment[We have a LOT to write here!]
  1812. @subsection(Addressing Modes)
  1813. @subsection(Register Designators)
  1814. @subsection(Labels)
  1815. @subsection(Storage Pseudos)
  1816. @section(Implement LAP-TO-ASM)
  1817. @SubSection(Needed Values)
  1818. Values must be given for:
  1819. @begin(description)
  1820. MainEntryPointName!*@\An ID which is the main procedure name.
  1821. NumericRegisterNames!*@\A vector of the symbolic names for the compiler
  1822. registers.
  1823. @end(description)
  1824. In addition, each of the registers (as IDs) must be declared, using
  1825. DefList to provide the string name of the register and flagging the
  1826. property list of the ID with 'RegisterName.
  1827. @subsection(Tables)
  1828. The list ForeignExternList!* is used to remember each of the
  1829. foreign functions that has been called in the course of a module so that
  1830. the proper externs can be emitted.
  1831. @SubSection(Printing routines)
  1832. A number of routines which are used to print the
  1833. strings, constants, etc@. are listed as follows:
  1834. @begin(format)
  1835. PrintString(S)
  1836. PrintByte!,(X)
  1837. TruncateString(S,n)
  1838. PrintByteList(L)
  1839. PrintByte(X)
  1840. PrintHalfWordList(L)
  1841. PrintHalfWord(X)
  1842. PrintHalfWords(X)
  1843. PrintOpcode(X)
  1844. SpecialActionForMainEntryPoint()
  1845. PrintNumericOperand(X)
  1846. @end(format)
  1847. @subsection(Symbol Mapping)
  1848. The function ASMSymbolP(X) must be written to check whether a @Xlisp
  1849. ID is also a legal symbol for the target assembler.
  1850. @Subsection(Formats)
  1851. The following formats must be declared to tell the LAP-TO-ASM
  1852. routines how to print objects and the format of file names to use:
  1853. CodeFileNameFormat!*, DataFileNameFormat!*, LabelFormat!*, CommentFormat!*,
  1854. ExportedDeclarationFormat!*, ExternalDeclarationFormat!*, FullWordFormat!*,
  1855. HalfWordFormat!*, ReserveDataBlockFormat!*, ReserveZeroBlockFormat!*,
  1856. DefinedFunctionCellFormat!*, UndefinedFunctionCellInstructions!*, and the
  1857. description for how to construct an item (for MkItem).
  1858. @section(Independent Compilation)
  1859. In order to maintain the PSL kernel as a set of reasonable sized
  1860. modules (about 15) a method to permit (semi-)independent translation
  1861. from LISP (or RLISP) to TLM assembly format was devised. This method
  1862. records information about symbols and structures defined in one module
  1863. and needed in another in a file called the SYM file.
  1864. When a set of modules is to be assembled into a program, a fresh SYM
  1865. file is allocated (usually called XXX-PSL.SYM or "Program-name.SYM").
  1866. Then as each module, MMM.RED is translated, the SYM file is first read
  1867. in to initialize various SYMBOL counters. After the translation is
  1868. complete an updated SYM file is written for the next step. When all
  1869. modules are tranlated, a last (MAIN) module is translated, and some of
  1870. the data information gathered in the SYM file is converted into global
  1871. data declarations in the assembly file.
  1872. Each module, MMM.RED (perhaps described by a MMM.BUILD file), is
  1873. converted
  1874. into 3 files, and updates to the SYM file:
  1875. @begin(description)
  1876. Code-File@\Contains the actual instructions for the procedues in the
  1877. MMM file. May also contain "read-only" data, such as some strings or
  1878. s-expressions. Typically called something like MMM.asm
  1879. Data-file@\Contains data-objects that may get changed, typically
  1880. WVAR and WARRAYs. This file typically called DMMM.asm or MMMd.asm.
  1881. Init-file@\Contains S-expressions that were not compilable procedures
  1882. found in the MMM.red file. Typically FLUID declarations, SETQ's and
  1883. PUT's dominate this sort of code. This file will be read-in by the
  1884. executing PSL after basic INITCODE is executed. Typically called
  1885. MMM.INIT.
  1886. @end(description)
  1887. The .SYM file data structures are updated. These structures are:
  1888. @begin(description)
  1889. Startup-Sexpressions@\Certain s-expressions must be evaluated
  1890. during INITCODE, before the .INIT files can be read. These are
  1891. collected into a single procedure, and compiled as INITCODE in the
  1892. MAIN module. This is the (SAVEFORCOMPILATION (QUOTE ...))
  1893. expression in the SYM file.
  1894. ID list@\New IDs encountered in this file are added to a list
  1895. of IDs in ID# order. IDs are referred to by ID#; list is called
  1896. ORDEREDIDLIST!*.
  1897. NEXTIDNUMBER!*@\The next ID# that will be allocated to the next new
  1898. ID.
  1899. STRINGGENSYM!*@\A string representing the last generated symbol-name.
  1900. Used for internal labels, and external names that are too complex.
  1901. Individual ID descriptors@\Each ID is now "installed" with a set of
  1902. PUT's, indicating its ID#, the assembly symbol that is its entry
  1903. point, if it is a WCONST, WVAR ,WARRAY etc. for example:
  1904. @begin(Verbatim)
  1905. (PUT 'INFBITLENGTH 'SCOPE 'EXTERNAL)
  1906. % An exported WCONST
  1907. (PUT 'INFBITLENGTH 'ASMSYMBOL 'NIL)
  1908. % no symbol allocated
  1909. (PUT 'INFBITLENGTH 'WCONST '18)
  1910. % Its compile time value
  1911. (PUT 'STACKUPPERBOUND 'SCOPE 'EXTERNAL)
  1912. % An exported WVAR
  1913. (PUT 'STACKUPPERBOUND 'ASMSYMBOL '"L2041")
  1914. % The Assembly SYMBOL
  1915. (PUT 'STACKUPPERBOUND 'WVAR 'STACKUPPERBOUND)
  1916. % Type of VAR
  1917. (PUT 'TWOARGDISPATCH 'ENTRYPOINT '"L1319")
  1918. % An internal FUNCTION and its Assembly
  1919. % SYMBOL
  1920. (PUT 'RELOAD 'ENTRYPOINT 'RELOAD)
  1921. % A simple entry point, not renamed
  1922. (PUT 'RELOAD 'IDNUMBER '552)
  1923. % Its ID number. SYMFNC(552)->
  1924. % JUMP RELOAD
  1925. (PUT 'CADR 'ENTRYPOINT 'CADR)
  1926. % Another simple entry point
  1927. (PUT 'CADR 'IDNUMBER '229)
  1928. (PUT 'LIST2STRING 'ENTRYPOINT '"L0059")
  1929. % Entry point, renamed because too long
  1930. % SYMFNC(147)->JUMP L0059
  1931. (PUT 'LIST2STRING 'IDNUMBER '147)
  1932. (PUT 'SPECIALRDSACTION!* 'IDNUMBER '598)
  1933. % A Global variable, INITIALLY NIL
  1934. (FLAG '(SPECIALRDSACTION!*) 'NILINITIALVALUE)
  1935. (PUT 'GLOBALLOOKUP 'ENTRYPOINT '"L3389")
  1936. (PUT 'GLOBALLOOKUP 'IDNUMBER '772)
  1937. (PUT 'CLEARCOMPRESSCHANNEL 'ENTRYPOINT
  1938. '"L2793")
  1939. (PUT 'CLEARCOMPRESSCHANNEL 'IDNUMBER '678)
  1940. @end(Verbatim)
  1941. @end(description)
  1942. The contents of SYMFNC are filled in during the translation of the
  1943. MAIN module, and JUMPs to the entrypoints of symbols that have them
  1944. are filled in. Other symbols get a JUMP to the UndefinedFunction Entry
  1945. point.
  1946. In general, individual modules can be retranslated, since the
  1947. information they generate is initially taken from the SYM file
  1948. (ensuring that ID's and SYMBOLS get the same IDNUMBER and ENTRYPOINT
  1949. as before). The procedure is to translate the desired model (modules)
  1950. again, replacing the CODE-FILE, DATE-FILE and INIT-FILE previously
  1951. produced, and also to retranslate the MAIN module, since additonal
  1952. symbols S-expressions etc may have been produced, and therefor need to
  1953. be converted into INIOTCODE or HEAP or SYMBOL data.
  1954. @subsection(Data Pseudos)
  1955. The following are pseudo operations (from the @68000 version) which
  1956. must have a procedure to implement them in xxxx-ASM.RED:
  1957. HalfWord, Deferred, Displacement, Indexed, Immediate, Iconst,
  1958. AutoIncrement, AutoDecrement, Absolute, and ForeignEntry.
  1959. @section(Configure the Compiler)
  1960. This is still somewhat arcane. Basically, the compiler tables that select the
  1961. COMPFN's and OPENFN's and patterns need to be installed. The most
  1962. common method of doing this is to start from the xxxx-COMP.RED file most
  1963. like the target machine X@Foot[It is still the case that you need a
  1964. compiler wizard to help you with this as the details are still changing and
  1965. often undocumented, with a lot of "You have to do this, to do that, but ..."].
  1966. [Effort is required to describe this more clearly]
  1967. @Section(Write the Additional LAP Modules)
  1968. A variety of small LAP routines are required for I/O, system interface,
  1969. core-saving, efficient function-linkage, variable binding, etc. Some of these
  1970. are described in the following System Dependent Section. Others are:
  1971. @subsection(Apply-LAP)
  1972. These procedures are rather important, and unfortunately tricky to write.
  1973. They are used to enable compiled-code to call interpreted code and
  1974. vice versa. When they are used, the registers R1...Rn have the arguments
  1975. loaded in them, so SYSLISP can't be used.
  1976. The routines are CodeApply(codePtr,Arglst), CodeEvalApply(CodePtr,Arglst),
  1977. BindEval(Formals,Args), CompileCallingInterpreted(IdOfFunction), FastApply(),
  1978. and UndefinedFunction(). These are partially described in SYSLISP, and
  1979. written in LAP with mostly @CMACRO@XS@Foot[See P20:APPLY-LAP.RED and
  1980. PV:APPLY-LAP.RED.].
  1981. Need to discuss tricks in more detail, devise a set of tests.
  1982. @subsection(Fast-Bind)
  1983. This consists of efficient routines written in LAP (using mostly
  1984. @CMACRO@xs) to BIND and UNBIND fluid variables. The specifics depend
  1985. on how the !*LAMBIND, !*PROGBIND and !*FREERESTR @CMACRO@xs are
  1986. implemented. In general, a machine specific "fast-call" is used, rather
  1987. than the more general recursive LISP call, and a list of ID numbers and
  1988. values ( NIL or register numbers) are passed in a block. The FASTBIND
  1989. routine uses the ID number to find the current value of the ID, and saves
  1990. the ID number and this value on the binding stack. Then NIL (for PROGBIND),
  1991. or the register value (for LAMBIND) is installed in SYMVAL(ID#). Note that
  1992. the compiler registers R1...Rn should not be changed, so either they have
  1993. to be saved, or other "hidden" registers have to be used. Since some hidden
  1994. registers may be used in the implementation of certain @CMACRO@xs, care has
  1995. to be exercized.
  1996. FASTUNBIND is usually simpler, since all it needs is a number of
  1997. @W[(ID# . Old-value)] pairs to pop off the Binding stack, and restore
  1998. @Foot[See P20:FAST-BINDER.RED or PV:FAST-BINDER.RED for some ideas.].
  1999. @SECTION(System Dependent Primitives)
  2000. The following set of functions are needed to complete the
  2001. system-dependent part of @PSL:
  2002. @subsection(System-dependent input and output)
  2003. @PSL uses a one-character-at-a-time stream model for I/O. I/O channels are
  2004. just small integers in a range from 0 to 32 (32 was chosen for no
  2005. particular reason and could easily be increased if desired). They are used
  2006. as indices to the WArrays ReadFunction, WriteFunction and CloseFunction,
  2007. which contain the names (as @xlisp items) of the functions to be called.
  2008. Thus a stream is an object with a set of operations, buffer(s), and static
  2009. vaiables associated with it. The current implementation of streams uses
  2010. parallel vectors for each of the operations that can be associated with a
  2011. stream. The Channel Number is used as an index into these vectors.
  2012. For example, the standard input channel is 0@Foot[This corresponds to the
  2013. @UNIX STDIO channel "stdin".] thus ReadFunction[0] contains
  2014. 'TerminalInputHandler, which is a function used to get a character from the
  2015. terminal. The system-dependent file input and output functions are
  2016. responsible for associating these channels with @ei[file pointers] or
  2017. @ei[JFNs] or whatever is appropriate to your system. These functions must
  2018. also perform any buffering required. We have been lucky so far because the
  2019. @UNIX and Tops-20 systems have single character primitives@Foot[Thus the
  2020. operating system hides the buffering.].
  2021. The reading function is responsible for echoing characters if the flag
  2022. !*ECHO is T. It may not be appropriate for a read function to echo
  2023. characters. For example, the "disk" reading function does echoing, while
  2024. the reader used to implement the @b[Compress] function does not. The read
  2025. function should return the ASCII code for a line feed (EOL) character to
  2026. indicate an end of line (or "newline"). This may require that the ASCII
  2027. code for carriage return be ignored when read, not returned.
  2028. The VAX UNIX version of SYSTEM-IO.RED (stored on PV:@Foot[PV: is
  2029. <PSL.VAX-Interp> or ~benson/psl/vax-interp.]) is the simplest,
  2030. since the UNIX STDIO library is so close to this model. This is a good
  2031. starting point for a new version. It also uses the file PSLIO.C, which
  2032. contains the array @w[@Value(UnderScore)FILEPOINTEROFCHANNEL], used for
  2033. channel allocation.
  2034. The function @b(ClearIO) is called at system-startup time and when the
  2035. function RESET is called. It should do all dynamic initialization of the
  2036. system, but should not close any open files. Static initialization of
  2037. slots in the function arrays is done in the system-dependent file
  2038. IO-DATA.RED, and the array used for channel allocation should also have
  2039. initialized slots for the channels used for terminal input (STDIN!* = 0),
  2040. terminal output (STDOUT!* = 1) and channels 2 thru 4, used by BLDMSG,
  2041. COMPRESS/EXPLODE and FLATSIZE. The variable ERROUT!* should have a
  2042. terminal output channel associated with it. This may be shared with
  2043. STDOUT!* as in the @Dec20, or be associated with a separate error
  2044. diagnostic stream, as on the VAX.
  2045. Channel allocation is handled by the system-dependent part of I/O, so when
  2046. the @Xlisp function Open calls the function @b(SystemOpenFileSpecial) for a
  2047. non-file-oriented I/O stream, it should just mark a free channel as being
  2048. in use and return it. @b(SystemMarkAsClosedChannel) does the opposite,
  2049. returning a channel to the pool of available ones.
  2050. @b(SystemOpenFileForInput) and @b(SystemOpenFileForOutput) each takes a
  2051. string as an argument and should return a channel and set appropriate
  2052. functions in the corresponding slots in ReadFunction, WriteFunction and
  2053. CloseFunction. If a file cannot be opened, a continuable error should be
  2054. generated whose error form is (OPEN @dq[file name] 'TYPE), where TYPE is either
  2055. INPUT or OUTPUT.
  2056. Terminal output should be unbuffered if possible. If it must be buffered,
  2057. it should be flushed when terminal input is done and when EOLs are written.
  2058. Terminal input should be line buffered, using line editing facilities
  2059. provided by the operating system if possible. The terminal input routine
  2060. is responsible for the display of the variable PromptString!*, using a @PSL
  2061. channel for output if desired, as the VAX version does. The @Dec20
  2062. terminal input routine uses a line editing facility that redisplays the
  2063. prompt and previously typed characters when a Control-R is typed.
  2064. End of file on input is indicated by returning a character which is CHAR
  2065. EOF, Control-Z (ASCII 26) on the @Dec20 and Control-D (ASCII 4) on UNIX.
  2066. This can be changed to any control character. The file SCAN-TABLE.RED will
  2067. contain the CharConst definition for EOF, and a copy of LispScanTable!*
  2068. with an 11 (delimiter) in that position.
  2069. @subsection(Terminate Execution)
  2070. The function QUIT(); terminates execution. It should probably close open
  2071. files, perhaps restore system state to "standard" if special I/O
  2072. capabilities were enabled. On some systems, execution can continue after
  2073. the QUIT() at the next instruction, using a system command such as
  2074. START or CONTINUE; on others, the core-image cannot be
  2075. continued or restarted (see DUMPLISP(), below). On the DEC-20, the HALTF
  2076. jsys is used, and execution can be continued. On the VAX under UNIX, a Stop
  2077. signal (18) is sent via the "kill(0,18)" call. This also can be continued
  2078. under Berkeley 4.1 UNIX.
  2079. See the file SYSTEM-EXTRAS.RED on PV: and P20:
  2080. @subsection(Date and Time)
  2081. The function TIMC(); is supposed to return the run-time in milliseconds.
  2082. This time should be from the start of this core-image, rather than JOB or
  2083. SYSTEM time. It is used to time execution of functions. Return it as a
  2084. full-word, untagged integer in register 1. On the DEC-20, we use the RUNTM
  2085. jsys, on the VAX the C call on "times" is used, and multipled by 17,
  2086. to get 1/1020'ths of a second. While not yet required, a TIMR() to get REAL,
  2087. or WALL, time may be useful@Foot[See TIMC.RED on P20: and PV:.].
  2088. The DATE(); function is supposed to return a Tagged @XLISP string
  2089. containing the current date. No particular format is currently assumed,
  2090. and the string is used to create welcome messages, etc. Later developments
  2091. may require a standard for TIMESTAMPS on files, and may also require a
  2092. CLOCK-time function. The Allocator function GtSTR(nbytes) may be useful to
  2093. get a fresh string to copy the string returned by a system call into. The
  2094. string should be 0-terminated. The DEC-20 uses ODTIM, and "writes" to the
  2095. string in "6-jun-82" format. On the VAX, the "ctime" call is used, and the
  2096. result "shuffled" into the same format as the DEC-20@Foot[See
  2097. SYSTEM-EXTRAS.RED on PV: and P20:].
  2098. @subsection(ReturnAddressP)
  2099. The function RETURNADDRESSP(x); supports the backtrace mechanism, and is
  2100. supposed to check that the instruction before the supposed address X, is in
  2101. fact a legal CALL instruction. It is used to scan the stack, looking for
  2102. return addresses@Foot[Very TRICKY, see SYSTEM-EXTRAS.RED on PV: and P20:].
  2103. @subsection(Interrupt Handler)
  2104. Also very crude at present; on the DEC-20, written as a loadable module,
  2105. P20:20-INTERRUPT.RED, using the JSYS package. This enables CTRL-G, CTRL-T,
  2106. some stack and arithmetic overflows, binding them to some sort of Throw
  2107. or Error routine.
  2108. On the VAX, the file PV:TRAP.RED defines some signal setup, and
  2109. InitializeInterrupts routine, and is included in the kernel.
  2110. It associates each trap with a STDERROR call with a given message.
  2111. Not yet standardized.
  2112. We really should "bind" all trappable interupts to an
  2113. appropriate THROW('!$SIGNAL!$,n), and indicate whether
  2114. to treat as a Fatal Error, a Continuable Error, or not an
  2115. Error at all.
  2116. @subsection(Core Image Saving)
  2117. A way in which @PSL (and most @XLISP@xs) get used involves the ability to
  2118. load @XLISP and FASL code into an executing @PSL, saving this
  2119. augmented "core-image" in a named file for subsequent restart later. Some
  2120. Operating Systems permit a running program to be saved into an executable
  2121. file, and then restarted from the beginning; others permit the saved
  2122. program to be continued at the instruction following the call to the SAVE
  2123. routine. Some operating systems do not normally permit or encourage the
  2124. saving of a running program into an executable file, and there is a lot of
  2125. work to be done.
  2126. The model currently used in @PSL is that a call on DUMPLISP(); does the
  2127. following (this is based on VAX and DEC-20 experience, and could
  2128. change as Apollo and CRAY are completed):
  2129. @begin(enumerate)
  2130. calls RECLAIM(); to compact the heap, or move the upper heap into
  2131. the lower heap. @Comment{How is it told that this is a cleanup reclaim that
  2132. is to put the results in the "lower" heap???}
  2133. makes some system calls to free unused space, decreasing the executable
  2134. image; space is returned from HEAP, BPS and STACK.
  2135. the core-image is saved in a file, whose name is the string in the
  2136. global variable, DumpFileName!* (this string may have to be passed
  2137. to the system routine, similar to I/O, using a small peice of LAP
  2138. as interface, or using the Foreign function protocol);
  2139. execution continues without leaving the running program; to terminate,
  2140. the QUIT(); function must be called explicitly [this may not be possible
  2141. on some systems, and may require a change in the model, or a
  2142. machine specific restriction].
  2143. the saved executable file will restart "from-the-top", i.e. by calling the
  2144. machine specific "startup" function defined in MAIN-START.RED, which calls
  2145. initialization functions CLEARBINDINGS(), CLEARIO(),
  2146. INITIALIZEINTERRUPTS(), etc. Then the Startup function calls MAIN();,
  2147. which can be redefined by the user before calling DUMPLISP();. MAIN()
  2148. typically calls StandardLISP() or RLISP(), or some other TopLoop. This
  2149. startup function also has a @XLISP accesible name, RESET.
  2150. @end(Enumerate)
  2151. On some machines, the core-image will automatically start "from-the-top",
  2152. unless effort is expended to change the "restart-vector" (e.g@. the TOPS-20
  2153. SSAVE jsys on the DEC-20);
  2154. on others, an explicit LINKE CALL (a JUMP) to RESET should be included
  2155. after the core-save call, to ensure execution of RESET (e.g@. the CTSS
  2156. DROPFILE call on the CRAY-1).
  2157. On the VAX under UNIX, a new function UNEXEC
  2158. was written in C, to convert an executing program back into "a.out" format.
  2159. See the files MAIN-START.RED and DUMPLISP.RED on P20: and PV:, and the
  2160. preliminary documentation on the @apollo MAP_CODE.TXT, on PD:.
  2161. @section(How LAP/TLM assembler works)
  2162. @Section(How the LAP works)
  2163. This discription of how the resident assembler (LAP) works is taken
  2164. from the 68000 implementations. Refer to the diagram below to aid the
  2165. understanding of this description. ALM instructions are passed into the
  2166. procedure called LAP. The first thing LAP does is to pass them through the
  2167. procedure PASS1LAP to transform ALM into TLM. The TLM is handed to
  2168. OptimizeBranches to check to see if long branches are needed.
  2169. OptimizeBranches is responsible for computing the offset of each label from
  2170. the beginning of the function. A list called BranchAndLabelAlist is created
  2171. which stores the labels and their offsets from the start of the code for
  2172. this function.
  2173. Upon the exit from OptimizeBranches the user may turn on the flag "PGWD"
  2174. and will be able to see the current state of the code. If the code is to
  2175. be compiled into memory and not fasled to a file then BPS space is
  2176. allocated.
  2177. Now the code make take one of three parallel paths.
  2178. If the code is a label then it is ignored.
  2179. If the instruction is an instance of !*Entry then the instruction
  2180. is passed to the procedure SaveEntry to establish the address of the
  2181. entry point of the code.
  2182. On all other cases the instruction is passed to the procedure
  2183. deposit instruction. This is often a good procedure to trace when
  2184. debugging lap so that one can see what is actually heading off to be
  2185. depsoited.
  2186. Once the code has passed through one of the above three paths,
  2187. the function defineEntries is called which loads the new code pointer into
  2188. the function cell in the SYMFNC table. Following this the code pointer is
  2189. tagged as code and returned as the result value of the function LAP.
  2190. The following details are provideed as a guide to writing your own
  2191. assembler.
  2192. Consderation should be give to
  2193. @begin(enumerate)
  2194. Regular vs Irregular Machines
  2195. Templates to Assemble Portions of Instruction
  2196. Variable Length Instructions
  2197. Alignment Problems
  2198. Data Psuedos
  2199. @xlisp Specific Pseudos
  2200. @end(enumerate)
  2201. @section(How do opcodes get defined for the LAP assembly process)
  2202. There are three procedures used to define the opcodes.
  2203. The first is DefineOpcode which defines, sets the necessary properties on
  2204. the opcode's property list, for 680000 opcodes that have no ,byte,word, or
  2205. long variants.
  2206. The second function is DefineOpcodes (notice it is simply the plural of the
  2207. first function) which defines an opcode with variants for byte,word, and
  2208. long mode.
  2209. And third is the function DefineCCOpcodes which sets up the properties for
  2210. all the condition codes.
  2211. @Section(Description of DefineOpcode)
  2212. The function DefineOpcode an have three, four, or five arguments.
  2213. They are defined to be:
  2214. @begin(enumerate)
  2215. The opcode name or id.
  2216. The base 2 value of the opcode, only the constant bits in the opcodes
  2217. binary value are given initially, the varible fields of an opcode are
  2218. ORed into the word later. These are all two bytes long. This is tagged
  2219. on a functions property list as its OpcodeValue.
  2220. The function to be used to assemble this opcode, referred to on the
  2221. property list by a functions InstructionDepositFunction.
  2222. The forth field if present represents the mode to be used with this
  2223. instruction: either byte, word, or long mode. The default is always word
  2224. mode. This value is stored on the property list under the tag of Size.
  2225. The fifth field is the number of bytes that the instruction will take up
  2226. in the resulting binary code. Generally, only instructions that take no
  2227. arguments will have this field filled in. This value is stored on the
  2228. property list under the tag of InstructionLength.
  2229. @end(enumerate)
  2230. DefOpcode finally calls the function EvDefopcode which puts all the
  2231. properties on the property list.
  2232. @Section(How the Function DefOpcodes works)
  2233. This function works just like the previous function DefOpcode except that
  2234. it takes one less field, the size field which tells how the opcode will be
  2235. used: byte, word, or long. This procedure will define an opcode for each
  2236. case.
  2237. For example if an opcode name is move then an id with associated property
  2238. list will be created for move.b, move.w, and move.l.
  2239. @Section(How the procedure DefCCOpcodes Works)
  2240. This function was written just to save typing in all the cases of opcodes
  2241. that use the condition codes. It does that same thing as DefOpcode above
  2242. but for each condition code variant of an opcode.
  2243. @section(Ok so what happens in a functions instruction depositfunction??)
  2244. The opcode and oprands are selected out of the list and if the operands are
  2245. not normal then they are passed throught the function effective address
  2246. which classifies then as to the 68000 convention of register and mode.
  2247. Purpose: convert an operand from symbolic to numeric form.
  2248. Returns: Addressing mode in the range 0..7
  2249. --------------------------------------------------
  2250. M68K addressing modes (from appendix B of the M68K User's Manual)
  2251. Addressing Mode Mode Reg Valid Modes* Assembler
  2252. Data MEM Cont Alter Syntax
  2253. Data Register Direct 000 reg no. X - - X Dn
  2254. Address Register Direct 001 reg no. - - - X An
  2255. Addr Reg Indirect 010 reg no. X X X X (An)
  2256. with PostIncrement 011 reg no. X X - X (An)+
  2257. with PreDecrement 100 reg no. X X - X -(An)
  2258. with Displacement 101 reg no. X X X X d(An)
  2259. with Index 110 reg no. X X X X d(An,Ri)
  2260. Absolute Short 111 000 X X X X xxxx
  2261. Absolute Long 111 001 X X X X xxxxxxxx
  2262. PC with Displacement 111 010 X X X - d(PC)
  2263. PC with Index 111 011 X X X - d(PC,Ri)
  2264. Immediate 111 100 X X - - #xxxxxxxx
  2265. * = Valid Addressing modes for each type of Addressing Category
  2266. Data - used to refer to data operands
  2267. Mem = Memory - used to refer to memory operands
  2268. Cont = Control - used to refer to memory operands without an associated
  2269. size
  2270. Alter = Alterable - used to refer to alterable (writeable) operands
  2271. --------------------------------------------------
  2272. Operand is of the form:
  2273. case 1: numeric immediate data
  2274. or (immediate x)
  2275. case 2: non-numeric atom a local label, which uses PC with
  2276. displacement
  2277. case 3: (reg x) x is a number or symbolic register name
  2278. case 4: (deferred (reg x)) address register indirect in Motorola jargon
  2279. case 5: (autoincrement (reg x)) address register indirect with postincrement
  2280. case 6: (autodecrement (reg x)) address register indirect with predecrement
  2281. case 7: (displacement (reg x) n) if (reg x) is an A reg
  2282. then if n is 0
  2283. then (deferred (reg x))
  2284. else address register indirect
  2285. with displacement
  2286. else if (reg x) is a D reg
  2287. then address register indirect
  2288. with index, using A6 (zero)
  2289. case 8: (indexed (reg x) (displacement (reg y) n))
  2290. address register indirect with index
  2291. case 9+: various Lisp addressing modes, all of which are absolute long
  2292. addresses
  2293. The value returned by this function is the mode field of the instruction
  2294. for the operand.
  2295. In addition, the fluid variables OperandRegisterNumber!*
  2296. and OperandExtension!*
  2297. will be set.
  2298. If there are no words to follow, OperandExtension!* will be set to NIL.
  2299. Otherwise, possible values of OperandExtension!* are:
  2300. number or (immediate exp) immediate data
  2301. (number) 16-bit signed displacement
  2302. non-numeric atom pc relative label
  2303. (displacement reg disp) index extension word
  2304. other absolute long, i.e. LISP addressing mode
  2305. LAP is a complete assembly form and can
  2306. be used by @xlisp programmers to write any legal assembly
  2307. code@Foot{There is no real guarantee that the entire set of machine
  2308. opcodes is supported by the LAP. An implementor may have chosen to
  2309. implement only those constructs used by the compiler-produced code or
  2310. explicitly used in hand written LAP. The reason for this partial
  2311. implementation is that many modern processors have included operations
  2312. to facilitate @ei[high level language compilation], which often seem
  2313. to be less than useful.}
  2314. @section(Binary FAST Loader,FASL)
  2315. [Explain FASL in general]
  2316. [Explain essential problem, relocation of machine addresses and LISP
  2317. ids]
  2318. [Give big-picture of FASL]
  2319. [Find MAGUIREs pictures of FASL blocks or regenerate
  2320. ]
  2321. This section is a guide to the internal workings of faslout and then
  2322. faslin.
  2323. The user begins the faslout procedure by calling the procedure faslout with
  2324. a string that does not have the extension (because it will add the
  2325. appropriate binary extension for you). However, when fasling in, the file
  2326. name requires the binary extension [Change this inconsistency].
  2327. Inside the procedure faslout, the file name is assigned to the fluid
  2328. variable ModuleName!*. Depending upon the setting of the flag
  2329. !*Quiet_Faslout, the system will either print out a greeting message or
  2330. not. Next, an output binary file is opened using the argument file name.
  2331. It will return the channel number to a fluid variable CodeOut!*.
  2332. CodeFileHeader is called to put in a header in the output file.
  2333. CodeFileHeader writes out a word consisting of the Fasl Magic Number
  2334. (currently set to 99). This magic word is used to check consistency
  2335. between old and current fasl format files (an error is given upon fasling
  2336. in the file if there is not a 99 as the first word). Therefore, the system
  2337. must consistently modify that number when a new fasl format is produced.
  2338. To continue, we need to understand the allocation that takes place within
  2339. the Binary Program Space (BPS). The BPS is a large, non-collected space
  2340. that contains compiled code, warrays, the string assocaited with interned
  2341. ID's, constant data in fasl files, etc. Space is allocated from both
  2342. ends of the space. Compiled code is allocated from the bottom (using
  2343. NextBPS as a pointer) and warrays are allocated from the top (using LastBPS
  2344. as the pointer). When an allocation is attempted, the desired size is
  2345. checked to see if it will cause LastBPS and NextBPS to cross; if it will,
  2346. an error message will be printed. The next step is to allocate 2/3 or the
  2347. remaining BPS from the top.
  2348. @begin(verbatim,leftmargin 0)
  2349. .----------------------------.
  2350. | |
  2351. | WArrays |
  2352. | |
  2353. | |
  2354. Last_BPS>|----------------------------| <-FaslBlockEnd!* ---.
  2355. | Code | |
  2356. | | |
  2357. | | |
  2358. | | 2/3
  2359. |============================| <-CodeBase!* |
  2360. | Bit Table | |
  2361. |============================| <-BitTableBase!* ---'
  2362. | |
  2363. | |
  2364. Next_BPS>|----------------------------|
  2365. | |
  2366. | |
  2367. | |
  2368. `----------------------------'
  2369. Binary Program Space
  2370. @end(verbatim)
  2371. The procedure AllocateFaslSpaces will setup the following fluid variables.
  2372. FaslBlockEnd!* will be the address to the top of the available space for
  2373. this particular allocation.
  2374. BitTableBase!* points to the beginning of the BitTable.
  2375. CurrentOffset!* keeps a pointer into the codespace of this allocation to
  2376. the next available point to add more code.
  2377. BitTableOffset!* is a running pointer to the current location in the
  2378. BitTable where the next entry will go.
  2379. CodeBase!* is the base pointer to the beginning of the code segment for
  2380. this allocation.
  2381. MaxFaslOffset!* is the max size of the codespace allowed for this
  2382. implementation.
  2383. OrderedIDList!* keeps record of the ID's as they are added.
  2384. NextIDNumber!* is a base number used just in fasl files to indicate which
  2385. IDs are local and which are global. It is assumed that there will never be
  2386. more than 2048 pre-allocated ID's, currently there are 129. The first 128
  2387. preallocated IDs are ASCII codes(0-127) and the last one is NIL(128).
  2388. Everything is now setup to begin fasling PSL code out to the file.
  2389. The remainder of the faslout procedure sets up three more fluid variables.
  2390. !*DEFN is set to T which indicates that you are not going to do normal
  2391. evaluation from the top loop and from files such as using the functions IN
  2392. and DSKIN.
  2393. DFPRINT!* signals that DFPRINT!* is now used as the printing function.
  2394. The procedure used will be DFPRINTFasl!*.
  2395. !*WritingFaslFile is set to T to let the system know that fasling out is
  2396. goping on as opposed to compiling code directly into memory inside the PSL
  2397. system.
  2398. @subsection(Binary I/O and File Format)
  2399. @u[Current FASL file format:]
  2400. Check accuracy, this was PC:fasl-file.Specs
  2401. @begin(description)
  2402. Word@\Magic number (currently 99).@comment{ Why the magic number 99??? }
  2403. Word@\Number of local IDs.
  2404. Block@\Local ID names, in order, in regular @xlisp format
  2405. (string size followed by block of chars).@comment{ need to specify that the
  2406. string size is given as a
  2407. word, and the character
  2408. counts is interms of bytes}
  2409. Word@\Size of code segment in words.
  2410. Word@\Offset in addressing units of initialization procedure.
  2411. Block@\Code segment.
  2412. Word@\Size of bit table in words (redundant, could be eliminated).
  2413. Block@\Bit table.
  2414. @end(description)
  2415. @subsection(Relocation/Bit Table)
  2416. Describes how to adjust addresses and ID numbers in previous Code Segment.
  2417. [Should add GENSYM generator option.] This is a block of 2 bit items, one
  2418. for each \addressing unit/ in the code block.@comment{ Are we committed to
  2419. two bits forever? }
  2420. @begin(description)
  2421. 0@\Don't relocate at this offset.
  2422. 1@\Relocate the word at this offset in the code segment.
  2423. 2@\Relocate the (halfword on VAX, right half on 20) at this offset.
  2424. @comment[Can this be generalized some more????]
  2425. 3@\Relocate the info field of the @xlisp item at this offset.
  2426. @end(description)
  2427. The data referred to by relocation entries in the bit table are split into
  2428. tag and info fields. The tag field specifies the type of relocation to be
  2429. done:@comment{ Where is this data stored??? }
  2430. @begin(description)
  2431. 0@\Add the code base to the info part.
  2432. 1@\Replace the local ID number in the info part by its global ID number.
  2433. 2@\Replace the local ID number in the info part by the location of its
  2434. value cell.
  2435. 3@\Replace the local ID number in the info part by the location of its
  2436. function cell.
  2437. @end(description)
  2438. Local ID numbers begin at 2048@comment{why this magic number???}, to allow
  2439. for statically allocated ID numbers (those which will be the same at
  2440. compile time and load time).
  2441. @subsection(Internal Functions)
  2442. [IS there any special handling of these, or restrictions]
  2443. @subsection(Foreign Functions, Externs, etc)
  2444. [Explain why cant do in FASL now. Need to do run-time look up of
  2445. LOADER symbols, and use in LAP/FASL part of things. Will need to
  2446. add extra RELOC types to FASL].
  2447. @subsection(Init Code)
  2448. [Explain how executable -sexpressions that are not procedure
  2449. definitions
  2450. are gathered into a single LISP procedure, compiled, and given
  2451. name, sort of !*!*FASL-INIRTCODE!*!*, or some such.
  2452. Is called as last action of LOAD.
  2453. Explain current restriction on FASL initcode size, suggest soluitions]
  2454. @subsection(Annotated FASL file example)
  2455. @begin(verbatim)
  2456. *Annotated version of a dump*
  2457. procedure adder(x);
  2458. begin scalar y;
  2459. y:=x;
  2460. return y+1;
  2461. end;
  2462. Dump of "trythis.b"
  2463. 000000: 0020 0001 E7DF FEDF 0000 0080 0000 00A0
  2464. 000010: 1800 0000 0000 0000 0000 0000 0000 0000
  2465. 000020: 0000 0080
  2466. 0000 0063 16#63 is the magic number which
  2467. indicates that is a FASL file
  2468. 0000 0003 Number of local IDs
  2469. 0000 0004 The first ID, in the form Length
  2470. of String, String name
  2471. 000030: 4144 4445 ADDER
  2472. 5200 0000
  2473. 0000 0003 Second ID, 3 (+1) characters "ADD1"
  2474. 4144 4431 ADD1
  2475. 000040: 0000 0000
  2476. 0000 0007 Third ID, 7 (+1) characters of
  2477. "PUTENTRY"
  2478. 5055 5445 PUTENTRY
  2479. 4E54 5259
  2480. 000050: 0000 0000
  2481. 0000 0003 Fourth ID, 3 (+1) characters "EXPR"
  2482. 4558 5052 EXPR
  2483. 0000 0000
  2484. 000060: 0000 000A CodeSize = 10 words
  2485. 0000 000A Offset of INIT function
  2486. -------------------- Code Block
  2487. 2649 MOVEA.L A1,A3
  2488. 2449 MOVEA.L A1,A2
  2489. 4EF9 C000 JMP C000 0801
  2490. ^ Relocate
  2491. Function cell
  2492. (ID.1 call on "ADD1")
  2493. 000070: 0801
  2494. ---------- The init code
  2495. 267C 0000 0000 MOVEA.L #0,A3
  2496. 247A 0010 MOVEA.L 10(pc),A2
  2497. 227A 0008 MOVEA.L 8(pc),A1
  2498. 000080: 4EF9 C000 0802 JMP C000 0802
  2499. ^ Relocate
  2500. Function cell
  2501. (ID.2 = "PUTENTRY")
  2502. FE40 0800 (ID.0 the procedure
  2503. ^ Relocate ID number name "ADDER")
  2504. FE40 0803 (ID.3 the procedure
  2505. ^ Relocate ID number type "EXPR")
  2506. 0000
  2507. -------------------- Bit Table Section
  2508. 000090: 0000 0003 Length of Bit table in words
  2509. -------------------- Bit Table
  2510. 0004 0000 : 0000 0000 0000 0100 0000 0000 0000 0000
  2511. ^ = Relocate Word
  2512. 0000 040C : 0000 0000 0000 0000 0000 0100 0000 1100
  2513. Relocate Word ^ ^
  2514. Relocate Inf------------'
  2515. 0C00 0000 : 0000 1100 0000 0000 0000 0000 0000 0000
  2516. ^ Relocate Inf
  2517. @end(verbatim)
  2518. [Explain how to use a BDUMP routine to examine this]
  2519. @subsection(Binary I/O)
  2520. The following functions are needed for FASLIN and FASLOUT:
  2521. @i(BinaryOpenRead(Filename:string):system-channel)
  2522. This should take a filename and open it so that binary input can be done.
  2523. The value returned is used only by the other functions in this group, and
  2524. so can be whatever is appropriate on your system.
  2525. @i(BinaryOpenWrite(Filename:string):system-channel)
  2526. Similar to BinaryOpenRead, open a file for binary output.
  2527. @i(BinaryClose(SChn:system-channel):none returned)
  2528. SChn is the value returned by BinaryOpenRead or BinaryOpenWrite. The file
  2529. is closed.
  2530. @i(BinaryRead(SChn:system-channel):word)
  2531. One word (i.e. Lisp item sized quantity) is read from the binary file. On
  2532. the Dec-20 this is done using the @i(BIN) jsys with the file opened in
  2533. 36-bit mode using a 36-bit byte pointer. The VAX Unix implementation uses
  2534. @i(getw) from the stdio library.
  2535. @i(BinaryReadBlock(SChn:system-channel, A:word-address, S:integer):none
  2536. returned)
  2537. S words are read from the binary file and deposited starting at the word
  2538. address A. The Dec-20 version uses the @i(SIN) jsys and VAX Unix uses the
  2539. @i(fread) function.
  2540. @i(BinaryWrite(SChn:system-channel, W:word):none returned)
  2541. One word is written to the binary file. On the Dec-20 this is done using
  2542. the @i(BOUT) jsys with the file opened in 36-bit mode using a 36-bit byte
  2543. pointer. The VAX Unix implementation uses @i(putw) from the stdio library.
  2544. @i(BinaryWriteBlock(SChn:system-channel, A:word-address, S:integer):none
  2545. returned)
  2546. S words starting at the word address A are written to the binary file. The
  2547. Dec-20 version uses the @i(SOUT) jsys and VAX Unix uses the @i(fwrite)
  2548. function.
  2549. @i(BitTable(A:word-address, B:bit-table-offset):integer)
  2550. This is similar to @i(Byte) and @i(HalfWord), except that a 2-bit unit is
  2551. being extracted. A is a word address, the base of a table of 2-bit
  2552. entries. The one B entries from the beginning is returned.
  2553. @i(PutBitTable(A:word-address, B:bit-table-offset, I:integer):)
  2554. Analagous to @i(PutByte) and @i(PutHalfWord), except that a 2-bit unit is
  2555. being deposited. A is a word address, the base of a table of 2-bit
  2556. entries. The low-order 2 bits of the integer I are stored at offset B.
  2557. [Explain how to test Binary I/O, in test N]
  2558. @subsection(Miscellaneous)
  2559. To use EMODE/NMODE and PRLISP on some systems, a "raw" I/O mode may be
  2560. required. See the PBIN, PBOUT, CHARSININPUTBUFFER, ECHOON and ECHOOFF
  2561. functions in EMOD2:RAWIO.RED and SYSTEM-EXTRAS.RED.
  2562. Some sort of system-call, fork or similar primitives are useful,
  2563. clearly system dependent. See the JSYS and EXEC package on P20:, the
  2564. SYSTEM call in PV:SYSTEM-EXTRAS.RED (written in C as a Foreign
  2565. Function), or the SYSCALL on the APOLLO.
  2566. This set is not yet standardized.