|
|
1.1 root 1: #
2: # VAXINTER.S
3: #
4: # This file contains the assembly language routines that interface
5: # the Macro SPITBOL compiler written in VAX assembly language to its
6: # operating system interface functions written in C.
7: #
8: # Contents:
9: #
10: # o Overview
11: # o Global variables accessed by OSINT functions
12: # o Interface routines between compiler and OSINT functions
13: # o C callable function get_sp
14: # o C callable function startup
15: # o Compiler callable function sbchk
16: #
17: #-----------
18: #
19: # Overview
20: #
21: # The Macro SPITBOL compiler relies on a set of operating system
22: # interface functions to provide all interaction with the host
23: # operating system. These functions are referred to as OSINT
24: # functions. A typical call to one of these OSINT functions takes
25: # the following form in the VAX version of the compiler:
26: #
27: # ...code to put arguments in registers...
28: # jsb sysxx ; call osint function
29: # .long exit_1 ; address of exit point 1
30: # .long exit_2 ; address of exit point 2
31: # ... ... ; ...
32: # .long exit_n ; address of exit point n
33: # ...instruction following call...
34: #
35: # The OSINT function 'sysxx' can then return in one of n+1 ways:
36: # to one of the n exit points or to the instruction following the
37: # last exit. This is not really very complicated - the jsb places
38: # the return address on the stack, so all the interface function has
39: # to do is add the appropriate offset to the return address and then
40: # pick up the exit address and jump to it OR do a normal return via
41: # an rsb instruction.
42: #
43: # Unfortunately, a C function cannot handle this scheme. So, an
44: # intermediary set of routines have been established to allow the
45: # interfacing of C functions. The mechanism is as follows:
46: #
47: # (1) The compiler calls OSINT functions as described above.
48: #
49: # (2) A set of assembly language interface routines is established,
50: # one per OSINT function, named accordingly. Each interface
51: # routine ...
52: #
53: # (a) saves all compiler registers in global variables
54: # accessible by C functions
55: # (b) calls the OSINT function written in C
56: # (c) restores all compiler registers from the global variables
57: # (d) inspects the OSINT function's return value to determine
58: # which of the n+1 returns should be taken and does so
59: #
60: # (3) A set of C language OSINT functions is established, one per
61: # OSINT function, named differently than the interface routines.
62: # Each OSINT function can access compiler registers via global
63: # variables. NO arguments are passed via the call.
64: #
65: # When an OSINT function returns, it must return a value indicating
66: # which of the n+1 exits should be taken. These return values are
67: # defined in header file 'inter.h'.
68: #
69: # Note: in the actual implementation below, the saving and restoring
70: # of registers is actually done in one common routine accessed by all
71: # interface routines.
72: #
73: # Other notes:
74: #
75: # The Un*x VAX cC ompilers transform "internal" global names to
76: # "external" global names by adding a leading underscore at the front
77: # of the internal name. Thus, the function name 'osopen' becomes
78: # '_osopen'.
79: #
80: # Acknowledgement:
81: #
82: # This interfacing scheme is based on an idea put forth by Andy Koenig.
83: #
84: #-----------
85: #
86: # Global Variables
87: #
88: # The compiler uses 8 registers as described below.
89: #
90: .data
91: .globl _reg_ra
92: .globl _reg_cp
93: .globl _reg_ia
94: .globl _reg_wa
95: .globl _reg_wb
96: .globl _reg_wc
97: .globl _reg_xr
98: .globl _reg_xl
99: .align 2
100: _reg_ra: .space 4 # Register RA (R2)
101: _reg_cp: .space 4 # Register CP (R3)
102: _reg_ia: .space 4 # Register IA (R5)
103: _reg_wa: .space 4 # Register WA (R6)
104: _reg_wb: .space 4 # Register WB (R7)
105: _reg_wc: .space 4 # Register WC (R8)
106: _reg_xr: .space 4 # Register XR (R9)
107: _reg_xl: .space 4 # Register XL (R10)
108: #
109: .globl _rsboff
110: _rsboff: .space 4 # Normal rsb return offset
111: #
112: # The following pointers address those cells in the compiler
113: # that point into the stack when a load module might be written,
114: # and which must therefore be relocated.
115: .globl _strellst
116: _strellst:
117: .long flptr
118: .long stbas
119: .long gtcef
120: .long 0 # end of list marker
121: #
122: # Setup a number of internal addresses in the compiler that cannot
123: # be directly accessed from within C because of naming difficulties.
124: #
125: .globl _ic_type
126: _ic_type: .long b$icl
127: .globl _sc_type
128: _sc_type: .long b$scl
129: .globl _xn_type
130: _xn_type: .long b$xnt
131: .globl _xr_type
132: _xr_type: .long b$xrt
133: #
134: .globl _id1
135: _id1: .long 0,id1l
136: .ascii "(2.0)"
137: id1e:
138: .set id1l,id1e-_id1-8
139: .align 2
140: #
141: .globl _id2
142: _id2: .long 0,id2l
143: .ascii "VAX/UNIX Version"
144: id2e:
145: .set id2l,id2e-_id2-8
146: .align 2
147: #
148: .globl _tscblk
149: .globl _ticblk
150: _ticblk: .space 8
151: _tscblk: .space 108
152: #
153: #-----------
154: #
155: # Interface routines
156: #
157: # Each interface routine takes the following form:
158: #
159: # sysxx: jsb ccaller # call common interface
160: # .long _sysxx # address of C OSINT function
161: # .long n # offset to instruction after
162: # # last procedure exit
163: #
164: # We take advantage of the "internal" to "external" transformation
165: # of names by the C compiler. Specifically, the assembly language
166: # interface routine names match those directly called by the compiler:
167: # 'sysxx'. The corresponding C OSINT functions are also called 'sysxx',
168: # but the C compiler nicely transforms these names into '_sysxx'.
169: #
170: .text
171: .globl sysax
172: sysax: jsb ccaller
173: .long _sysax
174: .long 0
175: #
176: .globl sysbx
177: sysbx: jsb ccaller
178: .long _sysbx
179: .long 0
180: #
181: .globl sysdc
182: sysdc: jsb ccaller
183: .long _sysdc
184: .long 0
185: #
186: .globl sysdm
187: sysdm: jsb ccaller
188: .long _sysdm
189: .long 0
190: #
191: .globl sysdt
192: sysdt: jsb ccaller
193: .long _sysdt
194: .long 0
195: #
196: .globl sysef
197: sysef: jsb ccaller
198: .long _sysef
199: .long 12
200: #
201: # .globl sysej
202: #sysej: jsb ccaller
203: # .long _sysej
204: # .long 0
205: #
206: .globl sysem
207: sysem: jsb ccaller
208: .long _sysem
209: .long 0
210: #
211: .globl sysen
212: sysen: jsb ccaller
213: .long _sysen
214: .long 12
215: #
216: .globl sysep
217: sysep: jsb ccaller
218: .long _sysep
219: .long 0
220: #
221: .globl sysex
222: sysex: jsb ccaller
223: .long _sysex
224: .long 4
225: #
226: # .globl sysfc
227: #sysfc: jsb ccaller
228: # .long _sysfc
229: # .long 4
230: #
231: .globl syshs
232: syshs: jsb ccaller
233: .long _syshs
234: .long 24
235: #
236: .globl sysid
237: sysid: jsb ccaller
238: .long _sysid
239: .long 0
240: #
241: # .globl sysil
242: #sysil: jsb ccaller
243: # .long _sysil
244: # .long 0
245: #
246: # .globl sysin
247: #sysin: jsb ccaller
248: # .long _sysin
249: # .long 12
250: #
251: # .globl sysio
252: #sysio: jsb ccaller
253: # .long _sysio
254: #
255: .globl sysld
256: sysld: jsb ccaller
257: .long _sysld
258: .long 8
259: #
260: .globl sysmm
261: sysmm: jsb ccaller
262: .long _sysmm
263: .long 0
264: #
265: .globl sysmx
266: sysmx: jsb ccaller
267: .long _sysmx
268: .long 0
269: #
270: .globl sysou
271: sysou: jsb ccaller
272: .long _sysou
273: .long 8
274: #
275: # .globl syspi
276: #syspi: jsb ccaller
277: # .long _syspi
278: # .long 0
279: #
280: .globl syspp
281: syspp: jsb ccaller
282: .long _syspp
283: .long 0
284: #
285: # .globl syspr
286: #syspr: jsb ccaller
287: # .long _syspr
288: # .long 4
289: #
290: # .globl sysrd
291: #sysrd: jsb ccaller
292: # .long _sysrd
293: # .long 4
294: #
295: # .globl sysri
296: #sysri: jsb ccaller
297: # .long _sysri
298: # .long 4
299: #
300: .globl sysrw
301: sysrw: jsb ccaller
302: .long _sysrw
303: .long 12
304: #
305: # .globl sysst
306: #sysst: jsb ccaller
307: # .long _sysst
308: # .long 20
309: #
310: # .globl systm
311: #systm: jsb ccaller
312: # .long _systm
313: # .long 0
314: #
315: .globl systt
316: systt: jsb ccaller
317: .long _systt
318: .long 0
319: #
320: .globl sysul
321: sysul: jsb ccaller
322: .long _sysul
323: .long 0
324: #
325: # .globl sysxi
326: #sysxi: jsb ccaller
327: # .long _sysxi
328: # .long 8
329: #
330: #-----------
331: #
332: # CCALLER is called by the OS interface routines to call the
333: # real C OS interface function.
334: #
335: # General calling sequence is:
336: #
337: # jsb ccaller
338: # .long address_of_C_function
339: # .long 4*number_of_exit_points
340: #
341: # Control IS NEVER returned to a interface routine. Instead, control
342: # is returned to the compiler (THE caller of the interface routine).
343: #
344: # The C function that is called MUST ALWAYS return an integer
345: # indicating the proecedure exit to take or that a normal return
346: # is to be performed.
347: #
348: # C function Interpretation
349: # return value
350: # ------------ -------------------------------------------
351: # <0 Do normal return to instruction past
352: # last procedure exit (distance passed
353: # in by dummy routine and saved in _rsboff)
354: # 0 Take procedure exit 1
355: # 4 Take procedure exit 2
356: # 8 Take procedure exit 3
357: # ... ...
358: #
359: ccaller:
360: #
361: # (1) Save registers in global variables
362: #
363: movl r2,_reg_ra # save RA (R2)
364: movl r3,_reg_cp # save CP (R3)
365: movl r5,_reg_ia # save IA (R5)
366: movl r6,_reg_wa # save WA (R6)
367: movl r7,_reg_wb # save WB (R7)
368: movl r8,_reg_wc # save WC (R8)
369: movl r9,_reg_xr # save XR (R9)
370: movl r10,_reg_xl # save XL (R10)
371: #
372: # (2) Fetch address of C function, fetch offset to 1st instruction
373: # past last procedure exit, and call C function.
374: #
375: movl (sp)+,r0 # point to arg list
376: movl (r0)+,r1 # point to C function entry point
377: movl (r0),_rsboff # get adjustment for normal exit
378: calls $0,(r1) # call C interface function
379: #
380: # (3) Restore registers after C function returns.
381: #
382: movl _reg_ra,r2 # restore RA (R2)
383: movl _reg_cp,r3 # restore CP (R3)
384: movl _reg_ia,r5 # restore IA (R5)
385: movl _reg_wa,r6 # restore WA (R6)
386: movl _reg_wb,r7 # restore WB (R7)
387: movl _reg_wc,r8 # restore WC (R8)
388: movl _reg_xr,r9 # restore XR (R9)
389: movl _reg_xl,r10 # restore XL (R10)
390: #
391: # (4) Based on returned value from C function either do a normal
392: # return or take a procedure exit.
393: #
394: tstl r0 # if normal return ...
395: bgeq erexit
396: addl2 _rsboff,(sp) # point to instruction following exits
397: rsb # return
398: # # else (take procedure exit n)
399: erexit: addl3 r0,(sp)+,r11 # point to address of exit
400: jmp *(r11)+ # take procedure exit
401: #
402: #-----------
403: #
404: # _get_sp - get C caller's SP
405: #
406: # _get_sp() returns the current value of the stack pointer from
407: # the point of reference of a C function.
408: #
409: # From C this procedure is called by
410: #
411: # our_sp = get_sp();
412: #
413: # The generated code will look like
414: #
415: # calls #0,_get_sp
416: # movl r0,our_sp
417: #
418: # On entry to _get_sp, the stack looks like
419: #
420: # +---------------+ (<-- SP before 'calls' executed)
421: # | arg cnt (0) |
422: # |---------------| <-- AP
423: # | old PC |
424: # |---------------|
425: # | old FP |
426: # |---------------|
427: # | old AP |
428: # |---------------|
429: # | mask/PSW |
430: # |---------------|
431: # | 0 |
432: # +---------------+ <-- SP <-- FP
433: #
434: # On exit, all these words will be removed from the stack. Therefore,
435: # the current value of the SP from the caller's perspective is AP+4.
436: #
437: .text
438: .globl _get_sp
439: _get_sp:
440: .word 0 # no registers to save
441: addl3 $4,ap,r0 # compute caller's SP
442: ret # done
443: #
444: #-----------
445: #
446: # _startup - startup compiler
447: #
448: # An OSINT C function calls _startup to transfer control
449: # to the compiler.
450: #
451: .text
452: .globl _startup
453: _startup:
454: .word 0
455: movl _reg_ra,r2 # initialize RA (R2)
456: movl _reg_cp,r3 # initialize CP (R3)
457: movl _reg_ia,r5 # initialize IA (R5)
458: movl _reg_wa,r6 # initialize WA (R6)
459: movl _reg_wb,r7 # initialize WB (R7)
460: movl _reg_wc,r8 # initialize WC (R8)
461: movl _reg_xr,r9 # initialize XR (R9)
462: movl _reg_xl,r10 # initialize XL (R10)
463: #
464: movl sp,_initsp # save initial sp
465: subl3 _stacksiz,sp,_lowsp
466: # set lowest legal sp for sbchk
467: #
468: movl _dfltcase,kvcas # set case flag IN compiler
469: #
470: jmp sec04 # transfer control to compiler
471: #
472: #-----------
473: #
474: # sbchk - check for stack overflow
475: #
476: .text
477: .globl sbchk
478: sbchk: cmpl sp,_lowsp # if sp is ok then
479: blssu sb100
480: rsb # return
481: sb100: tstl (sp)+ # else pop stack
482: jmp sec05 # and go to stack overflow section
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.