|
|
1.1 root 1: -IN80
2: -TITLE TOKUNX: TRANSLATE FROM TOKENS TO UNIX ASSEMBLER
3: -STITL REVISION HISTORY
4: *
5: * 12-AUG-82 (REG):
6: * Read tokenized input and remove EQUATES processing
7: * 09-MAR-82 (SGD):
8: * CHK is back - better than ever...
9: * Copy .INI file to start of .MAR file
10: * 10-SEP-81 (SGD):
11: * Read in problem label table from filename.PLB
12: * 01-AUG-81 (SGD):
13: * Better encoding of CTB,CTW,BTW and WTB
14: * 13-MAY-81 (SGD):
15: * Added logic in XOP to put a longword type displacement on displacement
16: * operands as VMS assembler assumes a word displacement. (Phhhhaaa - ed)
17: * 15-MAR-81 (SGD):
18: * Made CHK a comment, as now handled as exception.
19: * 10-SEP-80 (SGD):
20: * Made revisions to make XFER reflect VAX SBL capabilities. Note that
21: * this version of XFER is no longer capable of running on PDP-11, since
22: * it will be too big. [Major change was to substitute tables for LOOKUP
23: * strings, and corresponding addition of TINIT].
24: * 02-AUG-80 (SGD):
25: * Altered translation of conditional branches to emit conditional
26: * branch directly. Those which cause problems are listed in a
27: * table that inhibits the direct translation.
28: * 18-MAY-80 (SGD):
29: * Fixed translation of vertical tab (CH$VT) from ASCII 011 to ASCII 012
30: * to conform to SOS Editor standard.
31: *
32: -STITL INTRODUCTION
33: *
34: * ________________________________
35: *
36: * Coded by:
37: * Steven G. Duff
38: * 1345-M16 Cabrillo Park Dr.
39: * Santa Ana, California 96701
40: * (714) 541-9619
41: *
42: * This is a Macro Spitbol program for translation of the Macro
43: * Spitbol Minimal Source to Vax 11/780 Macro Source. The program
44: * is fairly simple in order that it be able to run in the limited
45: * address space of a PDP-11. As a consequence, certain of the
46: * Minimal Opcodes are left untranslated, to be expanded as macros
47: * at assembly time. These macros are:
48: *
49: * AOV, BSW, CMC, CVD, CVM, ESW,
50: * IFF, LSX, MCB, MFI, MVC, MVW, MWB, RMI, SEC, TRC.
51: *
52: * There are two principal parts of Minimal that make translation
53: * tricky vis-a-vis VAX MACRO-32:
54: *
55: *
56: * Tricky #1: BSW,IFF and ESW normally require buffering, sorting
57: * etc. These can (and are) handled by macros though. BSW
58: * emits a CASEL and a word table containing the default
59: * value. IFF re-biases the location counter during assembly
60: * and overwrites the default word. ESW resets the location
61: * counter back. XFER is not capable of handling the needed
62: * computation without more working store.
63: *
64: * VVVVVVVVV NOW HANDLED BY TOKENIZER
65: * Tricky #2: Minimal operands of the form DLBL(X) must be translated
66: * to 4*DLBL(X) as called for by the language spec. This
67: * requires that XFER be able to distinguish DLBLs from other
68: * stuff. This in turn means that a record of all EQU labels
69: * must be kept. This eats up a lot of working store, but
70: * can't be helped.
71: *
72: * The other macro-ops are simple enough, and are omitted purely to
73: * avoid using up dynamic unnecessarily.
74: -EJECT
75: * This program works with four files, with the same name, and
76: * different extensions. Name.MIN is used as the source input
77: * file. Name.MAR is created and becomes the source output file.
78: * Name.ERR is created, and is where the ERR and ERB messages and
79: * numbers are written. Name.INI is a prefix (MACRO32) file
80: * that is read as input and copied to Name.MAR before translation
81: * begins.
82: *
83: * The VAX assembler does not permit an equate to a register symbol
84: * for the purpose of creating symbolic register names.
85: * Thus this translator maps registers from Minimal to Vax thusly:
86: *
87: * RA <=> R2
88: * CP <=> R3
89: * IA <=> R5
90: * WA <=> R6
91: * WB <=> R7
92: * WC <=> R8
93: * XR <=> R9
94: * XL <=> R10 (XT ALSO)
95: * XS <=> SP (R14)
96: *
97: * Additionally, there are two other 'phantom' registers assumed
98: * by the translator - a scratch register (SR) which is used by
99: * a few instructions and by some of the character macros for
100: * holding temps, and EXI for returns. For remaindering,
101: * a register (IA2) is presumed to be available immediately below IA.
102: * The mappings of these registers are:
103: *
104: * IA2 <=> R4
105: * SR <=> R11
106: *
107: * Changes to this mapping are ill-advised and difficult.
108: *
109: *
110: * XFER aint got much smarts (it cant afford them). Except for cursory
111: * syntax and opcode checks, almost anything will get through, so it
112: * should be said that it expects valid Minimal Source. Simple errors
113: * are flagged on the listing (with a traceback) and a count given at
114: * the end, so they should not be too hard to find.
115: -STITL INITIALIZATION
116: * WARNING - POST NO LABELS!!!!!
117: * -----------------------------
118: * No labels should appear in this initializing code that would prevent
119: * the code from being garbage-collected by SPITBOL.
120: -SPACE 3
121: * Keyword initialization
122: *
123: &ANCHOR = 1; &TRIM = 1; &STLIMIT = -1
124: *
125: * Useful constants
126: *
127: MINLETS = 'ABCDEFGHIJKLMNOPQRSTUVWXY$'
128: ucase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
129: lcase = 'abcdefghijklmnopqrstuvwxyz'
130: NOS = '0123456789'
131: TAB = SUBSTR( &ALPHABET,10,1 )
132: REGNAME = ('X' ANY('LSTR')) | ('W' ANY('ABC')) | 'IA' | 'RA' | 'CP'
133: *
134: * Zero the counts
135: *
136: LABCNT = NOUTLINES = NLINES = NSTMTS = NTARGET = NERRORS = 0
137: *
138: * Get file name
139: *
140: FILENAMI = INPUT
141: TERMINAL = 'TOKEN file: ' FILENAMI
142: TERMINAL =
143: FILENAMP = INPUT
144: TERMINAL = 'Problem label file: ' FILENAMP
145: TERMINAL =
146: FILENAMO = INPUT
147: TERMINAL = 'ASSEMBLER file: ' FILENAMO
148: TERMINAL =
149:
150: FLCFLAG = REPLACE( INPUT,'y','Y' )
151: TERMINAL = 'Full line comments passed? ' FLCFLAG
152: *
153: * No page ejects without full line comments
154: *
155: TERMINAL = DIFFER(FLCFLAG,'N')
156: EJCFLAG = REPLACE( (DIFFER(FLCFLAG,'N') INPUT, 'N'),'y','Y' )
157: TERMINAL = 'EJCs passed? ' EJCFLAG
158: -STITL XFER FUNCTIONS
159: * TINIT is used during initialization to take a string of the
160: * form "index1[value1]index2[value2]...indexn[valuen]" and
161: * stuff the index/value pairs into a table which it returns.
162: *
163: DEFINE('TINIT(STR)POS,CNT,INDEX,VAL,LASTVAL')
164: * CRACK parses STMT into a STMT data plex and returns it.
165: * It fails if there is a syntax error.
166: *
167: DEFINE('CRACK(LINE)LABEL,OPCODE,OPERANDS,COMMENT,OPERAND,CHAR')
168: *
169: * STMT is the common data plex used to hold the components of
170: * a statement (either Minimal or VAX) during processing.
171: *
172: DATA('STMT(LABEL,OPCODE,OP1,OP2,OP3,COMMENT)')
173: *
174: * MINLABEL is a pattern matching a valid Minimal Source Label.
175: *
176: MINLABEL = ANY(MINLETS) ANY(MINLETS) ANY(MINLETS NOS)
177: + ANY(MINLETS NOS) ANY(MINLETS NOS)
178: *
179: * MINCOND is a pattern that matches Minimal Conditional assembly ops
180: *
181: MINCOND = 'IF' | 'THEN' | 'ELSE' | 'FI' | 'DEF' | 'UNDEF'
182: *
183: -EJECT
184: * DOSTMT is the driver routine that causes processing of the
185: * statement plex in THISSTMT.
186: *
187: DEFINE('DOSTMT()LABEL,OPCODE,OP1,OP2,OP3,COMMENT,T')
188: *
189: * HANDLER is a table providing the name of the processing appendage
190: * for every Minimal Op-Code. The name in this table is prefixed with
191: * "H_" to get the string name of the appendage. Every op must be
192: * in this string, including conditional ops.
193: *
194: HANDLER = TINIT(
195: + 'ADD[H]ADI[ADD2]ADR[ADD2]ANB[ANB]'
196: + 'AOV[AOV]BCT[H]BEQ[BCMP]BGE[BCMP]'
197: + 'BGT[BCMP]BHI[BCMP]BLE[BCMP]BLO[BCMP]'
198: + 'BLT[BCMP]BNE[BCMP]BRN[H]BRI[BRI]'
199: + 'BNZ[BTST]'
200: + 'BSW[BSW]BTW[BTW]BZE[BTST]CEQ[BCMP]'
201: + 'CHK[SBCALL]CMB[CMB]CMC[CMC]CNE[BCMP]'
202: + 'CSC[NOOP]CTB[CTX]CTW[CTX]CVD[CVD]'
203: + 'CVM[CVM]DAC[H]DBC[H]DCA[NEW1]'
204: + 'DCV[H]DEF[ZZZ]DIC[DXC]DRC[DXC]'
205: + 'DTC[DTC]DVI[ADD2]DVR[ADD2]EJC[EJC]'
206: + 'ELSE[ZZZ]END[END]ENP[NOOP]ENT[ENT]'
207: + 'EQU[EQU]ERB[ERX]ERR[ERX]ESW[NOOP]'
208: + 'EXI[EXI]EXP[GBLS]FI[ZZZ]FLC[FLC]ICA[NEW1]'
209: + 'ICP[ICP]ICV[H]IEQ[ATST]IF[ZZZ]'
210: + 'IFF[IFF]IGE[ATST]IGT[ATST]ILE[ATST]'
211: + 'ILT[ATST]INE[ATST]INO[OVF]INP[GBLS]'
212: + 'INR[GBLS]IOV[OVF]ITR[ITR]JSR[H]'
213: + 'LCH[SWP12]LCT[LCT]LCP[ADD2]LCW[NEW1]'
214: + 'LDI[ADD2]LDR[ADD2]LEI[LEI]LSH[XSH]'
215: + 'LSX[H]MCB[SBCALL]MFI[MFI]MLI[ADD2]MLR[ADD2]'
216: + 'MNZ[NEW1]MOV[H]MTI[ADD2]MVC[SBCALL]'
217: + 'MVW[SBCALL]MWB[SBCALL]NGI[NGX]NGR[NGX]'
218: + 'NZB[BTST]ORB[H]PLC[PXC]PPM[PPM]'
219: + 'PRC[PRC]PSC[PXC]REQ[ATST]RGE[ATST]'
220: + 'RGT[ATST]RLE[ATST]RLT[ATST]RMI[RMI]'
221: + 'RNE[ATST]RNO[OVF]ROV[OVF]RSH[XSH]'
222: + 'RSX[H]RTI[RTI]RTN[NOOP]SBI[ADD2]'
223: + 'SBR[ADD2]SCH[H]SCP[NEW1]SEC[SEC]'
224: + 'SSL[NOOP]SSS[NOOP]STI[STX]STR[STX]'
225: + 'SUB[H]THEN[ZZZ]TRC[SBCALL]TTL[TTL]'
226: + 'ZZZ[UNDEF]WTB[WTB]XOB[H]'
227: + 'ZER[H]ZGB[NOOP]ZRB[BTST]')
228: *
229: * H_ADD2.OPS is used by the H_ADD2 appendage to find
230: * the operand it is to insert.
231: *
232: H_ADD2.OPS = TINIT(
233: + 'ADI[R5]ADR[R2]DVI[R5]DVR[R2]LCP[R3]LDI[R5]'
234: + 'LDR[R2]MLI[R5]MLR[R2]MTI[R5]SBI[R5]SBR[R2]')
235: -EJECT
236: * H_BNCH.OPCS provides opcode translations for branch-type
237: * instructions. Branches are emitted directly, unless they are
238: * in the H_BNCH.PLAB problem label table, in which case an inverted
239: * branch/jump combination is emitted.
240: *
241: H_BNCH.OPCS = TINIT('BEQ[BEQLU]BGE[BGEQU]BGT[BGTRU]BHI[BGEQU]'
242: + 'BLE[BLEQU]BLO[BLEQU]BLT[BLSSU]BNE[BNEQU]'
243: + 'BNZ[BNEQU]BZE[BEQLU]CEQ[BEQLU]'
244: + 'CNE[BNEQU]IEQ[BEQL]IGE[BGEQ]IGT[BGTR]'
245: + 'ILE[BLEQ]ILT[BLSS]INE[BNEQ]INO[BVC]'
246: + 'IOV[BVS]NZB[BNEQU]'
247: + 'REQ[BEQL]RGE[BGEQ]RGT[BGTR]RLE[BLEQ]'
248: + 'RLT[BLSS]RNE[BNEQ]RNO[BVC]ROV[BVS]'
249: + 'ZRB[BEQLU]')
250: *
251: * H_BNCH.PLAB is a list of problem labels which for which 'short'
252: * conditional jumps cannot be issued, because one or more instructions
253: * in the code cause range trouble. Inverted branches are emitted
254: * instead.
255: *
256: H_BNCH.PLAB = TABLE(101)
257: *
258: * H_BNCH.IOCS is a translate list for the inverted branches needed
259: * for problem labels.
260: *
261: H_BNCH.IOCS = TINIT('BEQ[BNEQU]BGE[BLSSU]BGT[BLEQU]BHI[BLSSU]'
262: + 'BLE[BGTRU]BLO[BGTRU]BLT[BGEQU]BNE[BEQLU]'
263: + 'BNZ[BEQLU]BZE[BNEQU]CEQ[BNEQU]'
264: + 'CNE[BEQLU]IEQ[BNEQ]IGE[BLSS]IGT[BLEQ]'
265: + 'ILE[BGTR]ILT[BGEQ]INE[BEQL]INO[BVS]'
266: + 'IOV[BVC]NZB[BEQLU]'
267: + 'REQ[BNEQ]RGE[BLSS]RGT[BLEQ]RLE[BGTR]'
268: + 'RLT[BGEQ]RNE[BEQL]RNO[BVS]ROV[BVC]'
269: + 'ZRB[BNEQU]')
270: *
271: * H_EQU.DEFS is used by H_EQU to insert the fluid EQU
272: * definitions (...EQU *).
273: *
274: H_EQU.DEFS = TINIT(
275: + 'CFP$A[256]CFP$B[4]CFP$C[4]CFP$F[8]'
276: + 'CFP$I[1]CFP$M[0X7FFFFFFF]CFP$N[32]'
277: + 'NSTMX[10]CFP$R[1]CFP$S[6]CFP$X[2]'
278: + 'CFP$U[128]'
279: + 'E$SRS[50]E$STS[512]E$CBS[512]E$HNB[253]'
280: + 'E$HNW[3]E$FSP[20]'
281: + 'CH$LA[065]CH$LB[066]CH$LC[067]CH$LD[068]'
282: + 'CH$LE[069]CH$LF[070]CH$LG[071]CH$LH[072]'
283: + 'CH$LI[073]CH$LJ[074]CH$LK[075]CH$LL[076]'
284: + 'CH$LM[077]CH$LN[078]CH$LO[079]CH$LP[080]'
285: + 'CH$LQ[081]CH$LR[082]CH$LS[083]CH$LT[084]'
286: + 'CH$LU[085]CH$LV[086]CH$LW[087]CH$LX[088]'
287: + 'CH$LY[089]CH$L$[090]'
288: + 'CH$D0[048]CH$D1[049]CH$D2[050]CH$D3[051]'
289: + 'CH$D4[052]CH$D5[053]CH$D6[054]CH$D7[055]'
290: + 'CH$D8[056]CH$D9[057]'
291: + 'CH$$A[097]CH$$B[098]CH$$C[099]CH$$D[100]'
292: + 'CH$$E[101]CH$$F[102]CH$$G[103]CH$$H[104]'
293: + 'CH$$I[105]CH$$J[106]CH$$K[107]CH$$L[108]'
294: + 'CH$$M[109]CH$$N[110]CH$$O[111]CH$$P[112]'
295: + 'CH$$Q[113]CH$$R[114]CH$$S[115]CH$$T[116]'
296: + 'CH$$U[117]CH$$V[118]CH$$W[119]CH$$X[120]'
297: + 'CH$$Y[121]CH$$$[122]'
298: + 'CH$AM[038]CH$AS[042]CH$AT[064]CH$BB[060]'
299: + 'CH$BL[032]CH$BR[124]CH$CL[058]CH$CM[044]'
300: + 'CH$DL[036]CH$DT[046]CH$DQ[034]CH$EQ[061]'
301: + 'CH$EX[033]CH$MN[045]CH$NM[035]CH$NT[126]'
302: + 'CH$PC[037]CH$PL[043]CH$PP[040]CH$RB[062]'
303: + 'CH$RP[041]CH$QU[063]CH$SL[047]CH$SM[059]'
304: + 'CH$SQ[039]CH$UN[095]CH$OB[091]CH$CB[093]'
305: + 'CH$HT[009]CH$VT[012]IODEL[000]')
306: -EJECT
307: * H_H.XOPS is a table that encodes opcode translation
308: * for H_H.
309: *
310: H_H.XOPS = TINIT(
311: + 'ADD[ADDL2]ADI[ADDL2]ADR[ADDF2]ANB[BICL2]'
312: + 'BCT[SOBGTR]'
313: + 'BRN[JMP]'
314: + 'CMB[MCOML]'
315: + 'CTB[BICL2]CTW[ASHL]'
316: + 'DAC[.LONG]DBC[.LONG]'
317: + 'DCA[SUBL2]DCV[DECL]DIC[.LONG]DRC[.FLOAT]'
318: + 'DVI[DIVL2]DVR[DIVF2]EJC[#PAGE]'
319: + 'ERB[JMP]'
320: + 'ERR[.LONG]'
321: + 'ICA[ADDL2]ICP[TSTL]ICV[INCL]'
322: + 'ITR[CVTLF]JSR[JSB]'
323: + 'LCH[MOVZBL]LCT[MOVL]LCP[MOVL]LCW[MOVL]'
324: + 'LDI[MOVL]LDR[MOVF]LEI[MOVZWL]LSH[ASHL]'
325: + 'MLI[MULL2]MLR[MULF2]'
326: + 'MNZ[MOVL]MOV[MOVL]MTI[MOVL]'
327: + 'NGI[MNEGL]NGR[MNEGF]'
328: + 'ORB[BISL2]PPM[.LONG]'
329: + 'RSH[ASHL]'
330: + 'SBI[SUBL2]'
331: + 'SBR[SUBF2]SCH[MOVB]SCP[MOVL]'
332: + 'SEC[#SEC]'
333: + 'STI[MOVL]STR[MOVF]'
334: + 'SUB[SUBL2]'
335: + 'TTL[#TITLE]'
336: + 'XOB[XORL2]ZER[CLRL]')
337: *
338: * H_NEW1.OPS is a table used by the H_NEW1 appendage to find
339: * the operand to insert. It is indexed by opcode.
340: *
341: H_NEW1.OPS = TINIT(
342: + 'ICA[$4]DCA[$4]'
343: + 'LCW[(R3)+]MNZ[SP]SCP[R3]')
344: *
345: * Associate file for ERB,ERR messages in H_ERX
346: *
347: OUTPUT(.ERRFILE,4,(IDENT(FILENAMO) '', 'min.err'))
348: -EJECT
349: * Error is used to report an error for THISSTMT
350: *
351: DEFINE('ERROR(TEXT)')
352: -SPACE 3
353: * OUTSTMT is used to send a target statement to the target code
354: * output file (OUTFILE <=> LU2)
355: *
356: DEFINE('OUTSTMT(LABEL,OPCODE,OP1,OP2,OP3,COMMENT)T,STMTOUT')
357: *
358: * Associate output file
359: *
360: OUTPUT(.OUTFILE,2,(IDENT(FILENAMO) '', FILENAMO))
361: *
362: * OS.LLS is used by OUTSTMT to recognise local labels
363: *
364: OS.LLS = SPAN(NOS) '$' RPOS(0)
365: *
366: * READLINE is called to return the next non-comment line from
367: * the Minimal input file (INFILE <=> LU1). Note that it will
368: * not fail on EOF, but it will return a Minimal END statement
369: *
370: DEFINE('READLINE()')
371: *
372: * Associate input file to LU1
373: *
374: INPUT(.INFILE,1,(IDENT(FILENAMI) '', FILENAMI))
375: -EJECT
376: *
377: * XOP.REGS is a pattern to match out register names for translation.
378: *
379: XOP.REGS = (*REGNAME . VAL RPOS(0) . PREFIX) |
380: + (BREAK('(') LEN(1)) . PREFIX LEN(2) . VAL
381: *
382: * XOP.XREGS is a table with register translations
383: *
384: XOP.XREGS = TINIT('IA[R5]RA[R2]CP[R3]WA[R6]WB[R7]WC[R8]XR[R9]'
385: + 'XL[R10]XT[R10]XS[SP]')
386: *
387: * XPINTX is a pattern that will match the INT(X) type operand
388: *
389: XPINTX = SPAN(NOS) . VAL '('
390: *
391: * XPDLBLX is a pattern that will match the DLBL(X) type operand
392: *
393: XPDLBLX = MINLABEL . VAL '('
394: -STITL MAIN PROGRAM
395: * Here follows the driver code for the "main" program.
396: -SPACE 3
397: * Read the problem label table
398: *
399: INPUT(.PLTAB,.PLTAB,DIFFER(FILENAMP) FILENAMP) :F(MN02)
400: MN01 H_BNCH.PLAB[PLTAB] = 1 :S(MN01)
401: ENDFILE(.PLTAB)
402: MN02
403: *
404: * Loop until program exits via H_END
405: *
406: MN04 DOSTMT() :(MN04)
407: -STITL CRACK(LINE)
408: * CRACK is called to create a STMT plex containing the various
409: * entrails of the Minimal Source statement in LINE. For
410: * conditional assembly ops, the opcode is the op, and OP1
411: * is the symbol. Note that DTC is handled as a special case to
412: * assure that the decomposition is correct.
413: *
414: * CRACK will print an error and fail if a syntax error occurs.
415: *
416: CRACK NSTMTS = NSTMTS + 1
417: LINE '{' BREAK( '{' ) . LABEL
418: + '{' BREAK( '{' ) . OPCODE
419: + '{' BREAK( '{' ) . OP1
420: + '{' BREAK( '{' ) . OP2
421: + '{' BREAK( '{' ) . OP3
422: + '{' REM . COMMENT :F(CS03)
423: IDENT(OPCODE,'DTC') :S(CS00)
424: OP1 ANY('@') = '*'
425: OP1 ANY('#') = '$'
426: OP2 ANY('@') = '*'
427: OP2 ANY('#') = '$'
428: CS00 CRACK = STMT(LABEL,OPCODE,OP1,OP2,OP3,COMMENT)
429: *
430: * Operands all parsed out. That's all folks.
431: *
432: CS01 :(RETURN)
433: *
434: * Here on syntax error
435: *
436: CS03 ERROR('SOURCE LINE SYNTAX ERROR') :(FRETURN)
437: -STITL DOSTMT()
438: * DOSTMT is invoked to initiate processing of the next line from
439: * READLINE. For efficient access
440: * DOSTMT puts name values corresponding to the components in
441: * variables with the same names (LABEL, OPCODE, OP1,OP2,OP3 and
442: * COMMENT) which allows the various handlers to $var to store/fetch
443: * the values of the statment.
444: *
445: * After doing this, DOSTMT branches to the handler routine indicated
446: * for this opcode in the HANDLER table (there must be an entry or
447: * an error results). The handlers all have entry points beginning
448: * with "H_", and can be considered a logical extension of the
449: * DOSTMT routine. The handlers have the choice of branching back
450: * to DSGEN to cause the THISSTMT plex to be sent to OUTSTMT, or
451: * of RETURNing themselves, in which case the handler must output
452: * all needed code itself.
453: *
454: * The handlers are listed in a separate section below.
455: *
456: DOSTMT THISLINE = READLINE()
457: THISSTMT = CRACK(THISLINE) :F(DOSTMT)
458: LABEL = .LABEL(THISSTMT)
459: OPCODE = .OPCODE(THISSTMT)
460: MINOP = $OPCODE
461: OP1 = .OP1(THISSTMT)
462: OP2 = .OP2(THISSTMT)
463: OP3 = .OP3(THISSTMT)
464: COMMENT = .COMMENT(THISSTMT)
465: *
466: * Get handler entry point (less "H_" prefix)
467: *
468: DIFFER(T = HANDLER[$OPCODE]) :F(DS01)
469: *
470: * Jump to handler
471: *
472: :($('H_' T))
473: *
474: * Here if bad OpCode
475: *
476: DS01 ERROR('BAD OP-CODE') :(RETURN)
477: *
478: * Handlers can come back here to cause code generation of THISSTMT
479: *
480: DSGEN OUTSTMT($LABEL,$OPCODE,$OP1,$OP2,$OP3,$COMMENT) :(RETURN)
481: -STITL ERROR(TEXT)
482: * This module handles reporting of errors with the offending
483: * statement text in THISLINE. Comments explaining
484: * the error are written to the listing (including error chain), and
485: * the appropriate counts are updated.
486: *
487: ERROR OUTFILE = '# *???* ' THISLINE
488: OUTFILE = '# ' TEXT
489: + (IDENT(LASTERROR),'. LAST ERROR WAS LINE ' LASTERROR)
490: LASTERROR = NOUTLINES
491: NOUTLINES = NOUTLINES + 2
492: NERRORS = NERRORS + 1
493: + :(RETURN)
494: -STITL OUTSTMT(LABEL,OPCODE,OP1,OP2,OP3,COMMENT)
495: * This module writes the components of the VAX MACRO statement
496: * passed in the argument list to the formatted .MAR file
497: *
498: OUTSTMT STMTOUT = (IDENT(LABEL) TAB,
499: + LABEL ':' TAB)
500: + OPCODE (GT(SIZE(OPCODE),7) ' ', TAB)
501: + (IDENT(OP1), OP1
502: + (IDENT(OP2), ',' OP2
503: + (IDENT(OP3), ',' OP3)))
504: + (IDENT(COMMENT),
505: + (GT(T = SIZE(OP1 OP2 OP3), 16) ' ',
506: + DUPL(TAB, (22 - T) / 8))
507: + '# ' COMMENT)
508: *
509: * Translate everything but string constants to lower case.
510: *
511: stmtout = differ( opcode,'.ASCII' )
512: + replace( stmtout,ucase,lcase )
513: stmtout ident( opcode,'.ASCII' )
514: + ( break(*tab) *tab break(*tab) ) $ t =
515: + replace( t,ucase,lcase )
516: *
517: * Send text to OUTFILE
518: *
519: OUTFILE = STMTOUT
520: NTARGET = NTARGET + 1
521: NOUTLINES = NOUTLINES + 1
522: + :(RETURN)
523: -STITL READLINE()
524: * This routine returns the next statement line in the input file
525: * to the caller. It never fails. If there is no more input,
526: * then a Minimal END statement is returned.
527: * Comments are passed through to the output file directly.
528: *
529: *
530: READLINE READLINE = INFILE :F(RL02)
531: NLINES = NLINES + 1
532: READLINE ANY('*') = '#' :F(RL01)
533: *
534: * Only print comment if requested.
535: *
536: OUTFILE = IDENT(FLCFLAG,'Y') READLINE :F(READLINE)
537: NOUTLINES = NOUTLINES + 1 :(READLINE)
538: *
539: * Here if not a comment line
540: *
541: RL01 :(RETURN)
542: *
543: * Here on EOF
544: *
545: RL02 READLINE = ' END'
546: :(RL01)
547: -STITL TINIT(STR)
548: * This routine is called to initialize a table from a string of
549: * index/value pairs.
550: *
551: TINIT POS = 0
552: *
553: * Count the number of "[" symbols to get an assessment of the table
554: * size we need.
555: *
556: TIN01 STR (TAB(*POS) '[' BREAK(']') *?(CNT = CNT + 1) @POS)
557: + :S(TIN01)
558: *
559: * Allocate the table, and then fill it. Note that a small memory
560: * optimisation is attempted here by trying to re-use the previous
561: * value string if it is the same as the present one.
562: *
563: TINIT = TABLE(CNT)
564: TIN02 STR (BREAK('[') $ INDEX LEN(1) BREAK(']') $ VAL LEN(1)) =
565: + :F(RETURN)
566: VAL = CONVERT(VAL,'INTEGER')
567: VAL = IDENT(VAL,LASTVAL) LASTVAL
568: LASTVAL = VAL
569: TINIT[INDEX] = VAL :(TIN02)
570: -STITL OPCODE HANDLER APPENDAGES
571: * Ops that need a second operand (get from table).
572: *
573: H_ADD2 $OP2 = H_ADD2.OPS[$OPCODE] :(H_H)
574: -SPACE 3
575: * Do ANB opcode
576: *
577: H_ANB OUTSTMT($LABEL,'MCOML',$OP1,'R11',,$COMMENT)
578: $OP1 = 'R11'
579: $LABEL = $COMMENT = :(H_H)
580: -SPACE 3
581: * DO AOV
582: *
583: H_AOV OUTSTMT($LABEL,'ADDL2',$OP1,$OP2,,$COMMENT)
584: OUTSTMT(,'BVC','0F')
585: OUTSTMT(,'JMP',$OP3)
586: OUTSTMT('0') :(RETURN)
587: -SPACE 3
588: * Real and Integer Branch tests
589: * CHANGE CALL OF XOP TO XOP.XREGS LOOKUP
590: *
591: H_ATST OUTSTMT($LABEL,'TST' (IDENT(SUBSTR($OPCODE,1,1),'R') 'F', 'L'),
592: + XOP.XREGS[SUBSTR($OPCODE,1,1) 'A'],,,$COMMENT)
593: $OP2 = $OP1 :(H_BNCH)
594: -SPACE 3
595: * Comparison branches - emit a CMPL
596: *
597: H_BCMP OUTSTMT($LABEL,'CMPL',$OP1,$OP2,,$COMMENT)
598: $OP2 = $OP3 :(H_BNCH)
599: -SPACE 3
600: * Entered via various handlers to generate conditional branch code
601: *
602: H_BNCH DIFFER(H_BNCH.PLAB[$OP2]) :S(H_BNCH01)
603: OUTSTMT(,H_BNCH.OPCS[$OPCODE],$OP2) :(RETURN)
604: H_BNCH01 OUTSTMT(,H_BNCH.IOCS[$OPCODE],'0F')
605: OUTSTMT(,'JMP',$OP2)
606: OUTSTMT('0') :(RETURN)
607: -SPACE 3
608: * Handle BRI instruction with indirection
609: *
610: H_BRI OUTSTMT($LABEL,'MOVL',$OP1,'R11',,$COMMENT)
611: OUTSTMT(,'JMP','(R11)') :(RETURN)
612: -EJECT
613: *
614: * BSW generates a CASEL and a label for .WORD references.
615: *
616: h_bsw outstmt( $label,'CASEL',$OP1,'$0','$' $OP2,$COMMENT )
617: outstmt( '5' ) :(return)
618: -SPACE 3
619: * Zero branch comparisons
620: *
621: H_BTST OUTSTMT($LABEL,'TSTL',$OP1,,,$COMMENT)
622: + :(H_BNCH)
623: -EJECT
624: * BTW opcode
625: *
626: H_BTW OUTSTMT($LABEL,'ASHL','$-2',$OP1,$OP1,$COMMENT) :(RETURN)
627: -SPACE 3
628: * Do CMB instruction by duping operand for MCOML
629: *
630: H_CMB $OP2 = $OP1 :(H_H)
631: -SPACE 3
632: * DO CMC INSTRUCTION BY SUBROUTINE CALL
633: *
634: H_CMC OUTSTMT($LABEL,'JSB','SBCMC',,,$COMMENT)
635: OUTSTMT(,'.LONG',$OP1)
636: OUTSTMT(,'.LONG',$OP2) :(RETURN)
637: -SPACE 3
638: * Do CTB and CTW
639: *
640: H_CTX OUTSTMT($LABEL,'MOVAB','3+(4*' $OP2 ')(' $OP1 ')',$OP1,,$COMMENT)
641: $LABEL = $COMMENT =
642: $OP2 = $OP1
643: $OP1 = (IDENT($OPCODE,'CTB') '$3','$-2')
644: $OP3 = IDENT($OPCODE,'CTW') $OP2 :(H_H)
645: -SPACE 3
646: * DO CVD
647: *
648: H_CVD OUTSTMT($LABEL,'ASHQ','$-32','R4','R4',$COMMENT)
649: OUTSTMT(,'EDIV','$10','R4,R5,R6')
650: OUTSTMT(,'MNEGL','R6','R6')
651: OUTSTMT(,'BISB2','$0X30','R6') :(RETURN)
652: -SPACE 3
653: * DO CVM
654: *
655: H_CVM OUTSTMT($LABEL,'MULL2','$10','R5',,$COMMENT)
656: OUTSTMT(,'BVC','0F')
657: OUTSTMT(,'JMP',$OP1)
658: OUTSTMT('0','BICL2','$0XFFFFFFF0','R7')
659: OUTSTMT(,'SUBL2','R7','R5')
660: OUTSTMT(,'BVC','1F')
661: OUTSTMT(,'JMP',$OP1)
662: OUTSTMT('1') :(RETURN)
663: -SPACE 3
664: * Handle DIC and DRC by stripping leading plus (UNIX as does not
665: * support unary plus) and placing "0f" in front of single
666: * precision floating point constants.
667: *
668: h_dxc $op1 '+' =
669: $op1 = ident( $opcode,'DRC' ) '0f' $op1 :(h_h)
670: -SPACE 3
671: * Handle DTC by emitting .ASCII and then alignment order
672: *
673: H_DTC $OP1 = '"' SUBSTR($OP1,2,SIZE($OP1) - 2) '"'
674: OUTSTMT($LABEL,'.ASCII',$OP1,,,$COMMENT)
675: OUTSTMT(,'.ALIGN','2',) :(RETURN)
676: -SPACE 3
677: * EJC checks to see if page feeds are to be passed.
678: *
679: H_EJC IDENT(EJCFLAG,'Y') :S(H_H)F(RETURN)
680: -SPACE 3
681: * END prints statistics on terminal then exits program
682: *
683: H_END OUTSTMT(,'#END',,,,$COMMENT)
684: TERMINAL = '*** TRANSLATION COMPLETE ***'
685: TERMINAL = NLINES ' LINES READ.'
686: TERMINAL = NSTMTS ' STATEMENTS PROCESSED.'
687: TERMINAL = NTARGET ' TARGET CODE LINES PRODUCED.'
688: TERMINAL = NERRORS ' ERRORS OCCURRED.'
689: TERMINAL = DIFFER(LASTERROR) 'THE LAST ERROR WAS IN LINE ' LASTERROR
690: &CODE = NE(NERRORS) 2001
691: :(END)
692: -EJECT
693: * ENT emits the word ID (if needed) and the entry label
694: *
695: H_ENT IDENT($OP1) :S(H_ENT01)
696: OUTSTMT(,'.ALIGN','2')
697: OUTSTMT(,'.WORD',$OP1)
698: *
699: * Merge here to emit label entry point
700: *
701: H_ENT01 OUTSTMT($LABEL,,,,,$COMMENT) :(RETURN)
702: * Handle EQU by substituting '*' operands from definitions table
703: * if necessary
704: *
705: H_EQU $OP2 = $OP1
706: $OPCODE = '.SET'
707: $OP1 = $LABEL
708: $OP2 = IDENT($OP2,'*') H_EQU.DEFS[$LABEL]
709: $LABEL = :(DSGEN)
710: -SPACE 3
711: * Handle ERB and ERR in essentially the same way. First, send
712: * the message to the auxilliary .ERR file. Then make sure to
713: * note if this is the highest error # seen so far, so branch
714: * table can be properly emitted (see SEC). Then set OP1 to
715: * be "ERROR_" concatenated with the error number. This label
716: * refers to a label in the jump table that will load this error
717: * code in WA and jump to ERROR$.
718: *
719: H_ERX ERRFILE = LPAD($OP1,3,0) ($COMMENT = (IDENT($OP2), $OP2 ' ')
720: + $COMMENT)
721: MAXERR = GT($OP1,MAXERR) $OP1
722: $OP1 = 'ER_' LPAD($OP1,3,0)
723: $OP2 = :(H_H)
724: -EJECT
725: * There are 8 cases to EXI, partitioned along 3 binary dimensions.
726: * These are: 1. OP1 given/not given, 2. PTYPE is R/E or N,
727: * 3. OP1=1 (or #Ppms=0 if OP1 not given). Each possibility generates
728: * slightly different code.
729: *
730: H_EXI IDENT($OP1) :S(H_EXI00)
731: T = (IDENT(PTYPE,'N') PNAME '_S','(SP)+')
732: (EQ($OP1,1) OUTSTMT($LABEL,'MOVL',T,'R11',,$COMMENT),
733: + OUTSTMT($LABEL,'ADDL3','$4*' $OP1 - 1,T,'R11',$COMMENT))
734: OUTSTMT(,'JMP','*(R11)+') :(H_EXI04)
735: *
736: * Here if EXI has no OP1 given (normal exit)
737: *
738: H_EXI00 EQ(PPMS,0) :S(H_EXI02)
739: IDENT(PTYPE,'N') :S(H_EXI01)
740: *
741: * No OP1, #PPMs>0 and R/E-type
742: *
743: OUTSTMT($LABEL,'ADDL2','$4*' PPMS,'(SP)',,$COMMENT)
744: OUTSTMT(,'RSB') :(H_EXI04)
745: *
746: * Here if N-type PRC with no OP1 given & #PPMs > 0
747: *
748: H_EXI01 OUTSTMT($LABEL,'ADDL3','$4*' PPMS,PNAME '_S','R11',$COMMENT)
749: OUTSTMT(,'JMP','(R11)') :(H_EXI04)
750: *
751: * Here if no OP1, & #PPMs = 0
752: *
753: H_EXI02 IDENT(PTYPE,'N') :S(H_EXI03)
754: *
755: * No OP1, #PPMs=0 and R/E-type
756: *
757: OUTSTMT($LABEL,'RSB',,,,$COMMENT) :(H_EXI04)
758: *
759: * No OP1, #PPMs=0 and N-type
760: *
761: H_EXI03 OUTSTMT($LABEL,'JMP','*' PNAME '_S',,,$COMMENT)
762: *
763: * Merge to exit
764: *
765: H_EXI04 :(RETURN)
766: -EJECT
767: * FLC folds a lower case character to upper case.
768: *
769: H_FLC OUTSTMT( $LABEL,'BICL2','$CH$BL',$OP1,,$COMMENT ) :(RETURN)
770: *
771: * GBLS is entered to produce global directives for important
772: * routines internal and external to the compiler.
773: *
774: h_gbls outstmt( ,'.GLOBL',$LABEL,,,$COMMENT ) :(return)
775: -SPACE 3
776: * H is entered directly by some opcodes, and eventually by
777: * most others. It performs an opcode translation if an entry exists
778: * for it (non-null) in the H_H.XOPS table and then goes to DSGEN to
779: * dump the statement.
780: *
781: H_H $OPCODE = DIFFER(TEMP = H_H.XOPS[$OPCODE]) TEMP :(DSGEN)
782: -SPACE 3
783: * Handle ICP opcode with a TSTL on (CP)+
784: *
785: H_ICP $OP1 = '(R3)+' :(H_H)
786: -SPACE 3
787: * Handle IFF by generating a word with the proper offset.
788: *
789: h_iff outstmt( ,'.WORD',$OP2 '-5B',,,$COMMENT ) :(return)
790: -SPACE 3
791: * Handle ITR with a MOVLF on IA to RA
792: *
793: H_ITR $OP1 = 'R5'
794: $OP2 = 'R2' :(H_H)
795: -SPACE 3
796: * LCT does not emit if both operands are the same
797: *
798: H_LCT DIFFER($OP1,$OP2) :S(H_SWP12)
799: OUTSTMT($LABEL,,,,,$COMMENT) :(RETURN)
800: -SPACE 3
801: * LEI uses MOVZWL on the word just prior to the entry point
802: *
803: H_LEI $OP2 = $OP1
804: $OP1 = '-2(' $OP1 ')' :(H_H)
805: -EJECT
806: * DO MFI
807: *
808: H_MFI OUTSTMT($LABEL,'MOVL','R5',$OP1,,$COMMENT)
809: IDENT($OP2) :S(RETURN)
810: OUTSTMT(,'BGEQ','0F')
811: OUTSTMT(,'JMP',$OP2)
812: OUTSTMT('0') :(RETURN)
813: * Make operand 1 operand 2, and put in a new operand 1 according
814: * to the table.
815: *
816: H_NEW1 $OP2 = $OP1
817: $OP1 = H_NEW1.OPS[$OPCODE] :(H_H)
818: -SPACE 3
819: * No-op instructions. Comment out the opcode
820: *
821: H_NOOP (IDENT($OPCODE,'INP'), IDENT($OPCODE,'INR'), IDENT($OPCODE,'EXP'))
822: + :S(RETURN)
823: $OPCODE = '#' $OPCODE :(DSGEN)
824: -SPACE 3
825: * Do arithmetic negate ops
826: * CHANGE CALL OF XOP TO LOOKUP IN XOP.XREGS
827: *
828: H_NGX $OP1 = $OP2 = XOP.XREGS[SUBSTR($OPCODE,3,1) 'A']
829: + :(H_H)
830: -SPACE 3
831: * Handle arithmetic overflow tests [IOV,INO,ROV,RNO]
832: *
833: H_OVF $OP2 = $OP1
834: $OP1 = :(H_BNCH)
835: -SPACE 3
836: * Insert dummy PPM branch point if none given
837: *
838: H_PPM $OP1 = IDENT($OP1) 'INVALID$' :(H_H)
839: -SPACE 3
840: * PRC notes the operands for later EXIs in global variables, and
841: * emits save area code if N-type.
842: *
843: H_PRC PTYPE = $OP1
844: PPMS = $OP2
845: PNAME = $LABEL
846: *
847: * If N-type, then we need a save area word
848: *
849: DIFFER(PTYPE,'N') :S(H_PRC01)
850: OUTSTMT(,'.DATA','1')
851: OUTSTMT(PNAME '_S','.LONG','0')
852: OUTSTMT(,'.TEXT','0')
853: OUTSTMT($LABEL,'MOVL','(SP)+',PNAME '_S',,$COMMENT)
854: :(H_PRC02)
855: *
856: * Here if R/E type
857: *
858: H_PRC01 OUTSTMT($LABEL,'#PRC',,,,$COMMENT)
859: *
860: * Merge to exit
861: *
862: H_PRC02 :(RETURN)
863: -EJECT
864: * Do PLC, PSC ops
865: *
866: H_PXC (IDENT($OP2) OUTSTMT($LABEL,'MOVAB','CFP$F(' $OP1 ')',$OP1,,$COMMENT))
867: + :S(RETURN)
868: $OP2 ((('R' ANY(NOS) (ANY(NOS) | '')) | 'SP') RPOS(0)) :S(H_PXC1)
869: OUTSTMT($LABEL,'MOVL',$OP2,'R11',,'[GET IN SCRATCH REGISTER]')
870: $LABEL =
871: $OP2 = 'R11'
872: H_PXC1 OUTSTMT($LABEL,'MOVAB','CFP$F(' $OP1 ')[' $OP2 ']',$OP1,,$COMMENT)
873: + :(RETURN)
874: -SPACE 3
875: * DO RMI
876: *
877: H_RMI OUTSTMT($LABEL,'ASHQ','$-32','R4','R4',$COMMENT)
878: OUTSTMT(,'EDIV',$OP1,'R4,R11,R5') :(RETURN)
879: -SPACE 3
880: * Handle RTI with CVTFL and then BVS if PLBL present
881: *
882: H_RTI OUTSTMT($LABEL,'CVTFL','R2','R5',,$COMMENT)
883: (DIFFER($OP1) OUTSTMT(,'BVS',$OP1)) :(RETURN)
884: -SPACE 3
885: * SBCALL GENERATES A JSB TO THE LABEL 'SB' CONCATENTATED WITH
886: * THE MINIMAL INSTRUCTION NAME.
887: *
888: H_SBCALL
889: $OP1 = 'SB' $OPCODE
890: $OPCODE = 'JSB' :(DSGEN)
891: *
892: * SEC does various things depending on the current section
893: *
894: H_SEC H_SEC.CNT = H_SEC.CNT + 1
895: *
896: * Generate appropriate .text and .data directives:
897: *
898: * all instructions .text 0
899: * all constants .data 0
900: * all working storage .data 1
901: *
902: * procedures sec -------
903: * definitions sec -------
904: * constants sec .data 0
905: * working storage sec .data 1
906: * program sec .text 0
907: * stack overflow sec -------
908: * error section -------
909: *
910: ( eq( h_sec.cnt,3 ) outstmt( ,'.DATA','0' ),
911: + eq( h_sec.cnt,4 ) outstmt( ,'.DATA','1' ),
912: + eq( h_sec.cnt,5 ) outstmt( ,'.TEXT','0' ),
913: + )
914: *
915: * Get rid of the extrinsic defs. if past defs. section (saves space)
916: *
917: H_EQU.DEFS = EQ(H_SEC.CNT,3)
918: *
919: * Be sure to generate label for program sec.
920: *
921: eq( h_sec.cnt,5 ) :f(h_sec00)
922: outstmt( ,'.GLOBL','SEC04' )
923: outstmt( 'SEC04' ) :(h_sec02)
924: *
925: * If we have reached the Stack Ovfl. sect. then dump the ERR list
926: *
927: H_SEC00 NE(H_SEC.CNT,6) :S(H_SEC02)
928: T = 0
929: *
930: * Loop here to emit code for saved up ERR objects.
931: *
932: H_SEC01 T = LT(T,MAXERR) T + 1 :F(H_SEC01X)
933: OUTSTMT('ER_' LPAD(T,3,'0'), 'MOVZWL', '$' T, 'R6')
934: OUTSTMT(,'JMP','ERROR') :(H_SEC01)
935: *
936: H_SEC01X
937: outstmt( ,'.GLOBL','SEC05' )
938: outstmt( 'SEC05' )
939: *
940: * Merged when finished with ERRs list.
941: *
942: H_SEC02 :(H_H)
943: -EJECT
944: * Arithmetic store ops (STI,STR)
945: * CHANGE CALL OF XOP TO LOOKUP OF XOP.XREGS
946: *
947: H_STX $OP2 = $OP1
948: $OP1 = XOP.XREGS[SUBSTR($OPCODE,3,1) 'A'] :(H_H)
949: -SPACE 3
950: * Ops that need to have op1 and op2 switched.
951: *
952: H_SWP12 T = $OP1
953: $OP1 = $OP2
954: $OP2 = T :(H_H)
955: -SPACE 3
956: *
957: * TTL restores the title text from OP1 and COMMENT
958: *
959: H_TTL $OP1 = (IDENT($OP1), $OP1 ' ') $COMMENT
960: $COMMENT = :(H_H)
961: -SPACE 3
962: * Immediate mode shifts
963: *
964: H_XSH $OP3 = $OP1
965: $OP1 = '$' (IDENT($OPCODE,'LSH'),'-') $OP2
966: $OP2 = $OP3 :(H_H)
967: -SPACE 3
968: * WTB opcode
969: H_WTB OUTSTMT($LABEL,'MOVAL','0[' $OP1 ']',$OP1,,$COMMENT) :(RETURN)
970: -SPACE 3
971: * come here if an opcode is found that should have been procesed
972: * by a previous preprocessor.
973: *
974: h_zzz terminal = 'Invalid opcode detected in line '
975: + lpad( nlines,5 ) ': ' $opcode :(error)
976: -EJECT
977: END
978: spitv35.tok
979: spitv35.plb
980: spitv35.src
981: y
982: y
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.