|
|
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.