123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- @section(Examples of various kinds)
- Recall that when compiling code, variables which are used extended in
- one procedure, and bound as LAMBDA or PROG variables in another, must
- be declared fluids.
- Example:
- @begin(verbatim)
- (de foo(X) (PLUS2 X 1)), compiles to:
- (!*entry foo expr 1)
- (!*alloc 0)
- (!*move (quote 1) (reg 2))
- (!*linke 0 plus2 expr 2)
- (de fee(X Y) (Fum (foo X) (foo Y)), compiles to:
- (!*entry fee expr 2)
- (!*alloc 2)
- (!*move (reg 2) (frame 2))
- (!*link foo expr 1)
- (!*move (reg 1) (frame 1))
- (!*move (frame 2) (reg 1))
- (!*link foo expr 1)
- (!*move (reg 1) (reg 2))
- (!*move (frame 1) (reg 1))
- (!*linke 2 fum expr 2)
- Finally, (de fac (N) (cond ((Lessp N 1) 1)
- (T (Times2 N (fac SUB 1 N))
- compiles to:
- (!*entry fac expr 1)
- (!*alloc 1)
- (!*move (reg 1) (frame 1))
- (!*move (quote 1) (reg 2))
- (!*link LessP expr 1)
- (!*jumpeq (label L) (quote nil) (reg 1))
- (!*move (quote 1) (reg 1))
- (!*exit 1)
- (!*lbl (label L))
- (!*move (frame 1) (reg 1))
- (!*link sub1 expr 1)
- (!*link fac expr 1)
- (!*move (reg 1) (reg 2))
- (!*move (frame 1) (reg 1))
- (!*linke 1 times2 expr 2)
- @end(verbatim)
- @section(BUILDING the CROSS Compiler)
- The executable @dq[xxxx-CROSS.EXE] is built as follows:
- @begin(verbatim)
- @@psl:rlisp ! an RLISP
- *mapobl function lambda X;
- *<< RemProp(X, 'OpenCode);
- * RemProp(X, 'ExitOpenCode) >>; % Remove old compiler opts
- * % Load common modules
- *load(zboot, pass!-one!-lap, if!-system, syslisp, lap!-to!-asm);
- * % Load XXXX specific modules
- *load(XXXX!-comp, XXXX!-cmac, XXXX!-asm);
- *off UserMode;
- *DumpFileName!* := "filename.exe"; % Establish the executable name
- *Date!*:=Concat("XXXX Cross Assmbler ", Date()); % Establish greeting
- *DumpLisp(); % Does a Reclaim and save
- *Quit;
- @end(verbatim)
- @subsection(An example of the process)
- The following is a complete example, from @syslisp to @CMACRO@xs:
- @begin(verbatim,leftmargin 0)
- @@PSL:RLISP
- PSL 3.0 Rlisp, 9-May-82
- syslsp procedure Test1(); % Input RLISP syntax code
- begin scalar x;
- x := 5;
- x := x+7;
- L := '(A B C D);
- L1 := (CAR L) . CAR(CDR L);
- print L1;
- end;
- @End(verbatim)
- @begin(verbatim,leftmargin 0)
- % This is the output from the Compiler/LAP system.
- % The lines beginning with "(!* ... " are the Abstract
- % machine CMACRO's output from the compiler.
- % The indented lines following them are the VAX @sq[LAP]
- % assembly code the CMACRO patterns
- % (in the *-CMAC.SL files) produced by the expansion process.
- (!*PUSH '5)
- (@op{PUSHL} 5)
- (!*WPLUS2 (FRAME 1) (WCONST 7)) % WPLUS2 is actually a
- % CMACRO (OpenFunct)
- (@op{ADDL2} 7 (DEFERRED (REG ST))) % Note how the FRAME AnyReg
- % is converted directly to
- % a machine specific
- % addressing mode.
- (!*MOVE '(A B C D) (!$FLUID L))
- (@op{MOVL} '(A B C D) (!$FLUID L))
- (!*MOVE (CAR (CDR (!$FLUID L))) (REG 2))
- % The AnyReg patterns
- (@op{EXTZV} 0 27 (!$FLUID L) (REG 2)) % for CAR and CDR are used
- (@op{EXTZV} 0 27 (DISPLACEMENT (REG 2) 4) (REG 2))
- (@op{MOVL} (DEFERRED (REG 2)) (REG 2))
- (!*MOVE (CAR (!$FLUID L)) (REG 1))
- (@op{EXTZV} 0 27 (!$FLUID L) (REG 1))
- (@op{MOVL} (DEFERRED (REG 1)) (REG 1))
- (!*LINK CONS EXPR 2) % Standard Function Cell
- % call.
- (@op{JSB} (ENTRY CONS))
- (!*MOVE (REG 1) (!$FLUID L1))
- (@op{MOVL} (REG 1) (!$FLUID L1))
- (!*LINK PRINT EXPR 1)
- (@op{JSB} (ENTRY PRINT))
- (!*MOVE 'NIL (REG 1))
- (@op{MOVL} (REG NIL) (REG 1)) % Reg NIL evaluates to an
- (!*EXIT 1) % immediate constant.
- (@op{ADDL2} 4 (REG ST))
- (@op{RSB})
- TEST1
- @end(verbatim)
- @subsection(Prologues and Epilogues)
- An example of Prologues and Epilogues for (@APOLLO version of) the
- @68000 is given below:
- @begin(ProgramExample,leftmargin 0)
- lisp procedure CodeFileHeader(); % Pure Code Segment
- If !*MAIN then
- <<CodePrintF(" program %w,m0001%n",ModName!*);
- CodePrintF " data%n";
- DataProcState!*:='data;
- CodePrintF "* Start of execution of the program%n";
- CodeDeclareExternal 'SYMVAL; %/ Issue EXTERN.D early
- CodeDeclareExternal 'SYMFNC; %/ Issue EXTERN.D early
- CodePrintF "m0001 EQ *%n";
- CodePrintF " move.l db,-(sp) Save caller db%n";
- CodePrintF " clr.l -(sp) Push reserved word%n";
- CodePrintF " move.l a0,-(sp) Push address of ECB%n";
- CodePrintF " move.l SYMVAL+512,d0 Init NIL Reg%n";
- CodePrintF " link sb,#0 Balance unlink%n";
- CodePrintF " movea.l #0,a6 Setup zeroareg%n";
- CodePrintF " lea m0001,db Setup db reg%n";
- CodePrintF(" jsr %w Call Main routine%n",
- MainEntryPointNAme!*);
- CodePrintF "* now return to OS%n";
- CodePrintF " movea.l A_PGM_$EXIT,a6%n";
- CodePrintF " jsr (a6)%n";
- CodePrintF " unlk sb Reload callers SB%n";
- CodePrintF " addq.w #8,sp Pop linkage%n";
- CodePrintF " movea.l (sp)+,db Reload callers db%n";
- CodePrintF " rts Return%n";
- ForeignExternList!*:=NIL;
- CheckForeignExtern 'PGM!_!$EXIT;
- >>
- else
- <<CodePrintF (" module %w,m0000%n",ModName!*);
- %/ Kludge, since ModuleName set in ASMOUT
- CodePrintF " data%n";
- DataProcState!*:='data;
- CodeDeclareExternal 'SYMVAL; %/ Issue EXTERN.D early
- CodeDeclareExternal 'SYMFNC; %/ Issue EXTERN.D early
- CodePrintF "* this is an Independent Module %n";
- ForeignExternList!*:=NIL;
- >>;
- lisp procedure DataFileHeader();
- Begin
- DataPrintF(" module %w_D%n",ModName!*);
- DataPrintF " data%n";
- End;
- lisp procedure DataFileTrailer();
- DataPrintF "end%n";
- lisp procedure CodeFileTrailer();
- <<Foreach Fn in Reverse ForeignExternList!* do
- <<CodePrintF(" extern.p %w%n",Fn);
- CodePrintF("A_%w ac %w%n",Fn,Fn)>>;
- CodePrintF " end%n">>;
- @end(ProgramExample)
- The general use of the headers given above is to declare the module
- name, tell the assembler that this is a data section@Foot[On the @Apollo
- all of the code and data were put in a data section since the operating
- system and assembler had a problem with mixed code and data due to
- expecting a pure code segment with all data references relative to the data
- base register.], and in the
- case of the main routine performing the proper operating system dependent
- linkage for program entry and exit.
- Note that CodePrintF and DataPrintF are used to direct output to
- either the @ei[code] segment or @ei[data] segment. This is to allow
- seperate segements for those machines that allow for pure code segments (on
- the @Apollo a pure code segment is directly maped into the address space
- rather than copied, which results in a large difference in start up speed).
- This could probably be extended to PureCode, PureData, and ImpureData.
- procedure WW(X);
- <<print LIST('WW,x); x+1>>;
- Now a plain resolve function.
- That does not argument processing
- best for register conversion:
- procedure MYREGFN(R,S);
- <<Print LIST('MYREG, R,S);
- List('REG,S+10)>>;
- PUT('MYREG,'ANYREGRESOLUTIONFUNCTION,'MYREGFN);
- procedure MYANYFN(R,S);
- <<Print LIST('MYANY, R,S);
- S:= ResolveOperand('(REG t3),S);
- List('Weird,S)>>;
- FLAG('(WEIRD),'TERMINALOPERAND);
- PUT('MYANY,'ANYREGRESOLUTIONFUNCTION,'MYANYFN);
- (!*MOVE (WW 1) (WW 2))); ARgs must be WCONSTEVALUABEL
- (!*MOVE (WW (WW 1)) (WW 2)));
- (!*MOVE (WW A) (WW 2))); % First WW shouldnt convert
- (!*MOVE (MYREG 1) (MYREG 2))); % OK
- (!*MOVE (MYREG (WW 1)) (WW (MYREG 2)))); % Fails since args not processed
- (!*MOVE (MYREG (MYREG 1)) (MYREG 2)));
- (!*MOVE (MYANY 1) (MYANY 2))); % OK
- (!*MOVE (MYANY (WW 1)) (MYANY (MYREG 2)))); % Args processed
- (!*MOVE (MYANY (MYANY 1)) (MYANY 2)));
- @section(Sample ANYREGs and CMACROs from various machines)
- The following choice pieces from the @VAX750, @DEC20 and @68000
- illustrate a range of addressing modes, predicates and style.
- @subsection(VAX)
- @begin(verbatim,leftmargin 0)
- (DefCMacro !*Move % ARGONE -> ARGTWO
- (Equal) % Don't do anything
- ((ZeroP AnyP) (@op{clrl} ARGTWO)) % 0 -> ARGTWO
- ((NegativeImmediateP AnyP) % -n -> ARGTWO
- (@op{mnegl} (immediate (minus ARGONE)) ARGTWO))
- ((@op{movl} ARGONE ARGTWO))) % General case
- (DefCMacro !*WPlus2 % ARGONE+ARGTWO->ARGONE
- ((AnyP OneP) (@op{incl} ARGONE)) % add 1
- ((AnyP MinusOneP) (@op{decl} ARGONE)) % Subtract 1
- ((AnyP MinusP) (@op{subl2} (immediate (minus ARGTWO)) ARGONE))
- ((@op{addl2} ARGTWO ARGONE)))
- The Predicates used:
- @begin(description,spread 0)
- Equal@\As an atom, rather than in (...), it check both arguments same.
- Zerop@\Check if argument is 0
- AnyP@\Just returns T
- NegativeImmediateP@\Check that a negative, 32 bit constant.
- @end(Description)
- @end(verbatim)
- @subsection(DEC-20)
- @begin(verbatim,leftmargin 0)
- (DefCMacro !*Move % Move ArgOne -> ArgTwo
- (Equal)
- ((ZeroP AnyP) (@op{setzm} ARGTWO))
- ((MinusOneP AnyP) (@op{setom} ARGTWO))
- ((RegisterP AnyP) (@op{movem} ARGONE ARGTWO))
- ((NegativeImmediateP RegisterP)
- (@op{movni} ARGTWO (immediate (minus ARGONE))))
- ((ImmediateP RegisterP) (@op{hrrzi} ARGTWO ARGONE))
- ((AnyP RegisterP) (@op{move} ARGTWO ARGONE))
- ((!*MOVE ARGONE (reg t1)) (@op{movem} (reg t1) ARGTWO)))
- (DefCMacro !*WPlus2
- ((AnyP OneP) (@op{aos} ARGONE))
- ((AnyP MinusOneP) (@op{sos} ARGONE))
- ((AnyP RegisterP) (@op{addm} ARGTWO ARGONE))
- ((RegisterP NegativeImmediateP)
- (@op{subi} ARGTWO (minus ARGONE)))
- ((RegisterP ImmediateP) (@op{addi} ARGTWO ARGONE))
- ((RegisterP AnyP) (@op{add} ARGONE ARGTWO))
- ((!*MOVE ARGTWO (reg t2)) (@op{addm} (reg t2) ARGONE)))
- The Predicates used:
- @begin(description,spread 0)
- Equal@\As an atom, rather than in (...), it check both arguments same.
- Zerop@\Check if argument is 0
- AnyP@\Just returns T
- MinusOneP@\Check that argument is -1.
- ImmediateP@\Check that an address or 18 bit constant. Will
- change for extended addressing.
- NegativeImmediateP@\Check that a negative 18 bit constant.
- RegisterP@\Check that is (REG r), a register.
- @end(Description)
- @end(verbatim)
- @subsection(APOLLO)
- @begin(verbatim,leftmargin 0)
- (DefCMacro !*Move % (!*Move Source Destination)
- (Equal) % if source @Value(Eq) dest then do nothing
- ((ZeroP AregP)(@op{suba!.l} ARGTWO ARGTWO))
- ((ZeroP AnyP) (@op{clr!.l} ARGTWO)) % if source @Value(Eq) 0 then dest := 0
- ((InumP AregP) (@op{movea!.l} (Iconst ARGONE) ARGTWO))
- ((AddressP AregP) (@op{lea} ARGONE ARGTWO))
- ((InumP AnyP) (@op{move!.l} (Iconst ARGONE) ARGTWO))
- ((AddressP AnyP)
- (lea ARGONE (reg a0)) (@op{move!.l} (reg a0) ARGTWO))
- ((AnyP AregP) (@op{movea!.l} ARGONE ARGTWO))
- ((@op{move!.l} ARGONE ARGTWO)))
- (DefCMacro !*WPlus2 % (!*WPlus2 dest source)
- ((AnyP QuickIconstP) (@op{addq!.l} (Iconst ARGTWO) ARGONE))
- ((AnyP NegativeQuickIconstP)
- (@op{subq!.l} (Iconst (minus ARGTWO)) ARGONE))
- ((AregP MinusP) (@op{suba!.l} (Iconst (Minus ARGTWO)) ARGONE))
- ((AnyP MinusP) (@op{subi!.l} (Minus ARGTWO) ARGONE))
- ((AregP InumP) (@op{adda!.l} (Iconst ARGTWO) ARGONE))
- ((AnyP InumP) (@op{addi!.l} (Iconst ARGTWO) ARGONE))
- ((AregP AddressP) (@op{lea} ARGTWO (reg a0))
- (@op{adda!.l} (reg a0) ARGONE))
- ((AnyP AddressP) (@op{lea} ARGTWO (reg a0))
- (@op{add!.l} (reg a0) ARGONE))
- ((AregP AnyP)(@op{adda!.l} ARGTWO ARGONE))
- ((@op{add!.l} ARGTWO ARGONE))) % really need one a DREG
- The Predicates used:
- @begin(description,spread 0)
- Equal@\As an atom, rather than in (...), it check both arguments same.
- Zerop@\Check if argument is 0
- AregP@\Check that is one of the A registers (which can not be used for
- arithmetic), and require modified mnemonics.
- DregP@\Check that is one of the D registers, used for most
- arithmetic.
- InumP@\Check that a small integer.
- AddressP@\Check that an address, not a constant, since we need to use
- different instruction for Address's, e.g@. @op{lea} vs @op{movi}.
- AnyP@\Just returns T.
- NegativeImmediateP@\Check that a negative, 32 bit constant.
- QuickIconstP@\Small integer in range 1 ..@. 8 for the xxxxQ instructions on
- 68000.
- NegativeQuickIconstP@\Small integer in range -8 ..@. -1 for the xxxxQ
- instructions on 68000.
- @end(Description)
- @end(verbatim)
- @begin(verbatim,leftmargin 0)
- For example, on the @VAX750:
- @begin(Group)
- (DefAnyreg CAR % First ITEM of pair
- AnyregCAR % Associated function
- ((@op{extzv} 0 27 SOURCE REGISTER)
- % Code to extract 27 bit
- % address, masking TAG
- (Deferred REGISTER))) % Finally indexed mode used
- @hinge
- (DefAnyreg CDR % Second item
- AnyregCDR
- ((@op{extzv} 0 27 SOURCE REGISTER)
- (Displacement REGISTER 4)))
- % Displace 4 bytes off Register
- % Both CAR and CDR use a single instruction, so do not use a
- % predicate to test SOURCE.
- @hinge
- (DefAnyreg QUOTE % Note a set of different choices
- AnyregQUOTE
- ((Null) (REG NIL))
- ((EqTP) (FLUID T))
- ((InumP) SOURCE)
- ((QUOTE SOURCE)))
- @hinge
- (DefCMACRO !*Move % !*MOVE Usually has the most cases
- (Equal)
- ((ZeroP AnyP) (@op{clrl} ARGTWO))
- ((NegativeImmediateP AnyP)
- (@op{mnegl} (immediate (minus ARGONE)) ARGTWO))
- ((@op{movl} ARGONE ARGTWO)))
- @hinge
- (DefCMACRO !*Alloc
- ((ZeroP)) % No BODY - nothing to allocate
- ((@op{subl2} ARGONE (REG st))))
- @end(group)
- @end(verbatim)
|