Can now do command line arguments and link in various called library segments
authorNick Downing <nick@ndcode.org>
Sat, 19 Oct 2019 23:02:20 +0000 (10:02 +1100)
committerNick Downing <nick@ndcode.org>
Sat, 19 Oct 2019 23:02:20 +0000 (10:02 +1100)
multics_sim.c
pl1/cu_.alm [new file with mode: 0644]
pl1/pl1_operators_.alm [new file with mode: 0644]

index 577167b..4b01ad7 100644 (file)
 #include "dps8/dps8_sys.h"
 #include "linkdcl.h"
 #include "object_map.h"
+#include "pointer.h"
 #include "rassert.h"
 #include "stack_header.h"
 
+struct arg_list {
+  uint64_t pad0 : 18;
+  uint64_t desc_count : 18;
+  uint64_t dummy0 : 28;
+
+  uint64_t code : 18;
+  uint64_t arg_count : 18;
+  uint64_t dummy1 : 28;
+
+  struct its_pointer args[];
+};
+
+struct arg_desc {
+  uint64_t size : 24;
+  uint64_t number_dims : 4;
+  uint64_t packed : 1;
+  uint64_t type : 6;
+  uint64_t flag : 1;
+  uint64_t dummy0 : 28;
+};
+
+// hack, until we can do alternative names
+#define N_XLATE 5
+struct {
+  const char *from;
+  const char *to;
+} xlate[N_XLATE] = {
+  {"ioa_", "bound_library_wired_"},
+  {"calc", "bound_calc_"},
+  {"com_err_", "bound_library_1_"},
+  {"cu_", "bound_library_1_"},
+  {"pl1_operators_", "bound_library_wired_"}
+};
+
 #define N_PATHS 2
 char *paths[N_PATHS] = {
   "tape/word/system_library_1/",
@@ -42,18 +77,22 @@ struct packed_pointer *isot;
 int stack_segment;
 struct stack_header *stack_header;
 
-#define STACK_OFFSET (sizeof(stack_header) / sizeof(uint64_t))
+#define STACK_OFFSET ((int)(sizeof(struct stack_header) / sizeof(uint64_t)))
 
 #define LOT_OFFSET 0
 #define ISOT_OFFSET (LOT_OFFSET + N_SEGMENT)
 #define LINKAGE_OFFSET (ISOT_OFFSET + N_SEGMENT)
 int next_linkage_offset;
 
-int scratch_segment(void) {
+int allocate_segment(void) {
   rassert(next_segment < N_SEGMENT);
-  int index = next_segment++;
+  return next_segment++;
+}
+
+int scratch_segment(void) {
+  int segment = allocate_segment();
 
-  M[index] = (word36 *)mmap(
+  M[segment] = (word36 *)mmap(
     NULL,
     01000000 * sizeof(uint64_t),
     PROT_READ | PROT_WRITE,
@@ -61,9 +100,9 @@ int scratch_segment(void) {
     -1,
     (off_t)0
   );
-  rassert(M[index] != (word36 *)-1);
+  rassert(M[segment] != (word36 *)-1);
 
-  return index;
+  return segment;
 }
 
 struct object_map *get_object_map(struct loaded_segment *p) {
@@ -82,6 +121,24 @@ struct object_map *get_object_map(struct loaded_segment *p) {
   return object_map;
 }
 
+int allocate_linkage(int length, bool even) {
+  if (even)
+    next_linkage_offset = (next_linkage_offset + 1) & ~1;
+  rassert(next_linkage_offset + length <= 01000000);
+  int offset = next_linkage_offset;
+  next_linkage_offset += length;
+  return offset;
+}
+
+// hack, until we can do alternative names
+const char *xlate_segment(const char *name) {
+  for (int i = 0; i < N_XLATE; ++i)
+    if (strcmp(name, xlate[i].from) == 0)
+      return xlate[i].to;
+  printf("cannot xlate %s\n", name);
+  return name; //exit(EXIT_FAILURE);
+}
+
 struct loaded_segment *load_segment(const char *name) {
   // see if already loaded
   for (int i = 0; i < n_loaded_segment; ++i)
@@ -95,8 +152,7 @@ struct loaded_segment *load_segment(const char *name) {
   p->name = strdup(name);
   rassert(p->name);
 
-  rassert(next_segment < N_SEGMENT);
-  p->segment = next_segment++;
+  p->segment = allocate_segment();
   loaded_segment_xref[p->segment] = p;
 
   // search for segment in path
@@ -164,8 +220,9 @@ found_bitcount:
   );
 
   // copy and fill in linkage section
+  p->linkage_offset = allocate_linkage(object_map->linkage_length, true);
   struct linkage_header *linkage_header = (struct linkage_header *)(
-    M[linkage_segment] + next_linkage_offset
+    M[linkage_segment] + p->linkage_offset
   );
   memcpy(
     linkage_header,
@@ -186,23 +243,17 @@ found_bitcount:
   );
   linkage_header->stats_segment_number = linkage_segment;
 
-  // create LOT entry
-  p->linkage_offset = next_linkage_offset;
-  lot[p->segment] = packed_pointer(linkage_segment, next_linkage_offset);
-  next_linkage_offset += object_map->linkage_length;
-
   // copy static section
+  int static_offset = allocate_linkage(object_map->static_length, true);
   memcpy(
-    M[linkage_segment] + next_linkage_offset,
+    M[linkage_segment] + static_offset,
     M[p->segment] + object_map->static_offset,
     object_map->static_length * sizeof(uint64_t)
   );
 
-  // create ISOT entry
-  isot[p->segment] = packed_pointer(linkage_segment, next_linkage_offset);
-  next_linkage_offset += object_map->static_length;
-
-  // update LOT/ISOT high water
+  // update LOT, ISOT and LOT/ISOT high water
+  lot[p->segment] = packed_pointer(linkage_segment, p->linkage_offset);
+  isot[p->segment] = packed_pointer(linkage_segment, static_offset);
   stack_header->cur_lot_size = next_segment;
 
   return p;
@@ -345,7 +396,7 @@ bool snap_link(void) {
     (struct virgin_linkage_header *)(
       M[p->segment] + object_map->linkage_offset
     );
-   if (
+  if (
      cpu.TPR.TSR != linkage_segment ||
      cpu.TPR.CA & 1 ||
      cpu.TPR.CA <
@@ -411,7 +462,7 @@ bool snap_link(void) {
         exp_word->expression
       );
 
-      struct loaded_segment *q = load_segment("bound_library_1_");
+      struct loaded_segment *q = load_segment(xlate_segment(segname));
       *link = its_pointer(
         q->segment,
         find_entry(q, segname, offsetname, false)
@@ -427,27 +478,23 @@ bool snap_link(void) {
 }
 
 int main(int argc, char **argv) {
-  if (argc < 3) {
+  if (argc < 2) {
     printf(
-      "usage: %s object_segment_name entry_segment$entry_name [arguments]\n",
+      "usage: %s entry_segment$entry_name [arguments]\n",
       argv[0]
     );
     exit(EXIT_FAILURE);
   }
-  char *object_segment_name = argv[1];
   char *entry_segment, *entry_name;
   {
-    char *p = strchr(argv[2], '$');
-    if (p) {
-      *p++ = 0;
-      entry_segment = argv[2];
-      entry_name = p;
-    }
-    else {
-      entry_segment = object_segment_name;
-      entry_name = argv[2];
-    }
+    char *p = strchr(argv[1], '$');
+    rassert(p);
+    *p++ = 0;
+    entry_segment = argv[1];
+    entry_name = p;
   }
+  int n_args = argc - 2;
+  char **args = argv + 2;
 
   // initialize CPU
   cpu_reset_unit_idx(0, false);
@@ -472,6 +519,61 @@ int main(int argc, char **argv) {
   isot = (struct packed_pointer *)(M[linkage_segment] + ISOT_OFFSET);
   next_linkage_offset = LINKAGE_OFFSET;
 
+  // save command line
+  int arg_list_offset = allocate_linkage(6 + n_args * 4, true);
+
+  struct arg_list *arg_list = (struct arg_list *)(
+    M[linkage_segment] + arg_list_offset
+  );
+  arg_list->arg_count = n_args + 1;
+  arg_list->code = 4;
+  arg_list->desc_count = n_args;
+
+  for (int i = 0; i < n_args; ++i) {
+    int arg_offset = allocate_linkage((strlen(args[i]) + 3) >> 2, false);
+    arg_list->args[i] = its_pointer(linkage_segment, arg_offset);
+
+    uint64_t *arg = (uint64_t *)(M[linkage_segment] + arg_offset);
+    static int shifts[4] = {27, 18, 9, 0};
+    for (int j = 0; args[i][j]; ++j)
+      arg[j >> 2] |= (uint64_t)args[i][j] << shifts[j & 3];
+
+    int arg_desc_offset = allocate_linkage(
+      sizeof(struct arg_desc) / sizeof(uint64_t),
+      false
+    );
+    arg_list->args[n_args + 1 + i] =
+      its_pointer(linkage_segment, arg_desc_offset);
+
+    struct arg_desc *arg_desc = (struct arg_desc *)(
+      M[linkage_segment] + arg_desc_offset
+    );
+    arg_desc->flag = 1; // version 2 descriptor
+    arg_desc->type = 21; // character string
+    arg_desc->packed = 1;
+    arg_desc->number_dims = 0;
+    arg_desc->size = strlen(args[i]);
+  }
+
+  int result_offset = allocate_linkage(0x100, false); // 1 kbyte of output
+  arg_list->args[n_args] = its_pointer(linkage_segment, result_offset);
+
+  int arg_desc_offset = allocate_linkage(
+    sizeof(struct arg_desc) / sizeof(uint64_t),
+    false
+  );
+  arg_list->args[n_args * 2 + 1] =
+    its_pointer(linkage_segment, arg_desc_offset);
+
+  struct arg_desc *arg_desc = (struct arg_desc *)(
+    M[linkage_segment] + arg_desc_offset
+  );
+  arg_desc->flag = 1; // version 2 descriptor
+  arg_desc->type = 22; // varying character string
+  arg_desc->packed = 1;
+  arg_desc->number_dims = 0;
+  arg_desc->size = 0x400; // 1 kbyte of output
+
   // create stack segment
   stack_segment = scratch_segment();
   stack_header = (struct stack_header *)M[stack_segment];
@@ -482,7 +584,7 @@ int main(int argc, char **argv) {
   stack_header->isot_ptr = its_pointer(linkage_segment, ISOT_OFFSET);
 
   // load pl1 operators
-  struct loaded_segment *p = load_segment("bound_library_wired_");
+  struct loaded_segment *p = load_segment(xlate_segment("pl1_operators_"));
   //dump_entries(p);
   //exit(EXIT_FAILURE);
   stack_header->pl1_operators_ptr = its_pointer(
@@ -511,7 +613,7 @@ int main(int argc, char **argv) {
   );
 
   // set up registers
-  struct loaded_segment *q = load_segment(object_segment_name);
+  struct loaded_segment *q = load_segment(xlate_segment(entry_segment));
   set_addr_mode(APPEND_mode);
 
   // ic (instruction counter)
@@ -520,6 +622,11 @@ int main(int argc, char **argv) {
   cpu.PPR.P = 0; // privilege
   cpu.PPR.IC = find_entry(q, entry_segment, entry_name, true); // address
 
+  // ap (argument pointer)
+  cpu.PR[0].RNR = 3; // ring
+  cpu.PR[0].SNR = linkage_segment; // segment
+  cpu.PR[0].WORDNO = arg_list_offset; // address
   // sp (stack frame pointer)
   cpu.PR[6].RNR = 3; // ring
   cpu.PR[6].SNR = p->segment; // segment
diff --git a/pl1/cu_.alm b/pl1/cu_.alm
new file mode 100644 (file)
index 0000000..15c22f9
--- /dev/null
@@ -0,0 +1,1627 @@
+" ***********************************************************
+" *                                                         *
+" * Copyright, (C) Honeywell Bull Inc., 1987                *
+" *                                                         *
+" * Copyright, (C) Honeywell Information Systems Inc., 1982 *
+" *                                                         *
+" * Copyright (c) 1972 by Massachusetts Institute of        *
+" * Technology and Honeywell Information Systems, Inc.      *
+" *                                                         *
+" ***********************************************************
+
+" HISTORY COMMENTS:
+"  1) change(1986-05-15,DGHowe), approve(1986-05-15,MCR7375),
+"     audit(1986-07-15,Schroth), install(1986-08-01,MR12.0-1108):
+"     add the entry points get_command_name and get_command_name_rel. Added
+"     the constants fb21_mask and null.
+"  2) change(1986-12-10,DGHowe), approve(1986-12-10,PBF7375),
+"     audit(1986-12-10,McInnis), install(1986-12-17,MR12.0-1250):
+"     Bug fix to get_command_name_common. Redefine has_command_name_mask to be
+"     a full word 400000000000. Take the du modifier off of the anx0 for the
+"     has_command_name_mask.
+"  3) change(2017-01-06,GDixon), approve(2017-01-08,MCR10025),
+"     audit(2017-01-08,Swenson), install(2017-01-08,MR12.6f-0008):
+"     Repair cu_$arg_ptr(_rel) test of arg_list.desc_count, to account for new
+"     arg_list.has_command_name flag.
+"                                                      END HISTORY COMMENTS
+
+
+" Command system utility subroutines
+
+" Initially coded in December 1969 by R. C. Daley
+" Modified by R Feiertag in 1970 to add entries arg_ptr_rel, grow_stack_frame,
+"      shrink_stack_frame, get_cp, and get_cl
+" Modified by V. Voydock in October 1970 as part of reworking of process environment
+" Modified by C. Tavares in May 1971 to add entry caller_ptr
+" Modified by V. Voydock in June 1971 to add entries "ready_proc",
+"       "get_ready_proc", and "set_ready_proc"
+" Modified by V. Voydock in May 1972 to add entries get_ready_mode and set_ready_mode,
+"      and to make cu_$grow_stack_frame round up to mod 16 boundaries
+" Split into two pieces in May 1972 by V. Voydock as part of fast command loop 
+" Modified 21 June 1972 by P. Green to fix arg_ptr not to assume descriptors are present,
+"      and to handle Version 2 descriptors properly.
+" Modified for follow-on by R. Snyder July 20, 1972
+" Modified 11/19/76 by M. Weaver  to add entries generate_call, (get set)_command_processor,
+"      and (get set)_ready_procedure
+" Modified May 1977 by Larry Johnson for arg_count_rel entry.
+" Modified Aug 12, 1977 by S. Webber to remerge with rest_of_cu_
+" Modified: August 1980 by G. Palter to add reset_(command_processor ready_procedure
+"          cl_intermediary), make cu_$(generate_call cl cp ready_proc) work with internal
+"          procedures, add an optional second argument to cu_$arg_count, and add
+"          cu_$evaluate_active_string and cu_$(get set reset)_evaluate_active_string.
+" Modified September 1982 by C. Hornig to remove reference to pl1_operators.
+" Modified: 16 September 1982 by G. Palter to make cu_$stack_frame_size work (phx13864)
+" Modified: 16 January 1983 by G. Palter to make cu_$arg_ptr and friends reject invalid
+"    argument numbers (phx14511)
+" Modified: 1 March 1984 by G. Palter to not use LDAQ/STAQ for copying pointers (phx15722)
+"    and to always initialize the pointer and length arguments of cu_$*arg_ptr* to null and
+"    zero, respectively (phx16016)
+
+" \f
+
+       name    cu_
+
+"                      TABLE OF CONTENTS
+
+       entry   af_arg_count            " return # arguments if an AF
+       entry   af_arg_count_rel                " ... for given arg list
+       entry   af_arg_ptr              " get ptr/lth of an argument if an AF
+       entry   af_arg_ptr_rel          " ... for given arg list
+       entry   af_return_arg           " return # args and ptr/lth of AF return value
+       entry   af_return_arg_rel               " ... for given arg list
+       entry   arg_count                       " get number of arguments
+       entry   arg_count_rel           " ... for given arg list
+       entry   arg_list_ptr            " get ptr to argument list
+       entry   arg_ptr                 " get ptr to argument(n)
+       entry   arg_ptr_rel             " ... for given arg list
+       entry   caller_ptr              " get codeptr to invoker's caller
+       entry   cl                      " entry to call to re-enter environment
+       entry   cp                      " entry to call current command processor
+       entry   decode_entry_value              " extract ptrs from pl1 entry variable
+       entry   evaluate_active_string  " call to evaluate an active string
+       entry   gen_call                        " call, given codeptr and arg list ptr
+       entry   generate_call           " call, given entry variable and arg list ptr
+       entry   get_cl                  " get codeptr to current command level re-entry procedure
+       entry   get_cl_intermediary             " get entry variable for current command level re-entry procedure
+       entry   get_command_processor   " get entry variable for current command processor
+       entry   get_command_name_rel    " get command name 
+       entry   get_command_name                " get command name 
+       entry   get_cp                  " get codeptr to current command processor
+       entry   get_evaluate_active_string      " get entry variable to evaluate an active string
+       entry   get_ready_mode          " get value of internal ready flags
+       entry   get_ready_proc          " get codeptr to procedure to be called after each command line
+       entry   get_ready_procedure             " get entry variable to be called after each command line
+       entry   grow_stack_frame                " allocate space in stack frame (mod 16)
+       entry   level_get                       " get current validation level
+       entry   level_set                       " set current validation level
+       entry   make_entry_value                " create pl1 entry variable from codeptr and enironmentptr
+       entry   ptr_call                        " call, given codeptr in arg list
+       entry   ready_proc              " entry to call after each command line is processed
+       entry   reset_cl_intermediary   " reset to default command level re-entry procedure
+       entry   reset_command_processor " reset to default command processor
+       entry   reset_evaluate_active_string    " reset to default entry to evaluate an active string
+       entry   reset_ready_procedure   " reset to default ready message printer
+       entry   set_cl                  " set external entry for re-entry to command level
+       entry   set_cl_intermediary             " set entry for re-entry to command level
+       entry   set_command_processor   " set entry for current command processor
+       entry   set_cp                  " set external entry for current command processor
+       entry   set_evaluate_active_string      " set entry to evaluate an active string
+       entry   set_ready_mode          " set value of internal ready flags
+       entry   set_ready_proc          " set external entry to be called after each command line
+       entry   set_ready_procedure             " set entry to be called after each command line
+       entry   shrink_stack_frame              " free up space in stack frame
+       entry   stack_frame_ptr         " get ptr to stack frame
+       entry   stack_frame_size                " get size of stack frame
+
+" \f
+       include stack_header
+
+       include stack_frame
+
+" \f
+
+       tempd   temp_ptr,temp_ptr2              " temporaries for ptr_call
+
+
+" Constants
+
+       bool    var_desc,10120          " identifies PL1 version 1 varying character string
+       bool    v2_var,130000           " identifies PL1 version 2 varying character string
+
+fb21_mask:
+       oct     000017777777            " mask off fixed bin 21
+
+descriptor_mask:
+       oct     000077777777            " mask off top 12 bits
+
+desc_mask:                             " mask for PL1 version 1 descriptor (ignore sets/uses)
+       vfd     15/0,21/-1
+
+has_command_name_mask:
+       oct     400000000000
+
+v2_mask:       vfd     1/1,6/0,29/-1           " Mask for PL1 version 2 (modern style)
+
+       even
+null:  its     -1,1                    " null pointer
+ptrmask:       oct     077777000077,777777077077       " mask for pointer comparisons
+
+
+" Variables
+
+       use     int_stat                internal static storage
+       join    /static/int_stat
+
+cl_arg:        oct     400000000000
+
+ready_mode:
+       oct     400000000000
+
+       even
+cl_entry:      its     -1,1                    " entry to re-enter command level
+       its     -1,1
+
+cl_arglist:
+       vfd     18/2,18/4
+       vfd     18/0,18/0
+       its     -1,1
+
+cp_entry:      its     -1,1                    " entry for current command processor
+       its     -1,1
+
+ready_entry:                           " entry for current ready procedure
+       its     -1,1
+       its     -1,1
+
+ready_arglist:
+       vfd     18/2,18/4               arglist for call to ready procedure
+       dec     0
+       its     -1,1
+
+eas_entry:                             " entry for current active string evalauator
+       its     -1,1
+       its     -1,1
+
+       use     main
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    cl ..... entry to re-enter command level upon receipt of error conditions
+"
+"      call cu_$cl (cl_modes);
+"
+"      dcl 1 cl_modes aligned, /* optional argument */
+"          2 resetread bit (1) unaligned, /* ON => do a resetread on user_i/o */
+"          2 pad bit (34) unaligned;
+"
+"      If cl_modes isn't supplied, a canned structure is passed to request a resetread
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+cl:    lda     ap|0                    " pick up arg list header
+       cana    =o777777,du             " any arguments passed?
+       tnz     cl_with_args            " ... yes -- use supplied arglist
+       eppap   pr5|cl_arglist          " ... no -- use canned arglist
+       epp2    pr5|cl_arg              " ...     which requests resetread
+       spri2   pr5|cl_arglist+2
+
+cl_with_args:
+       epp1    pr5|cl_entry            " will be calling this entry variable
+       ldaq    pr1|0                   " is it a user specified value?
+       eraq    null
+       anaq    ptrmask
+       tnz     generate_call_common    " ... yes -- go off and perform the call
+
+       callsp  get_to_cl_$unclaimed_signal     " ... no -- use default (external) proc
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      get_cl_intermediary .... entry to retrieve entry var to re-enter command level
+"
+"      call cu_$get_cl_intermediary(cl_entry);
+"
+"      1. cl_entry (entry) - entry variable to procedure to re-enter command level
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " "" " " " " " " " " " " " "
+
+get_cl_intermediary:
+       epp2    ap|2,*                  " get ptr to entry variable argument
+       ldaq    pr5|cl_entry            " is it the default procedure?
+       eraq    null
+       anaq    ptrmask
+       tnz     get_cl_intermediary_non_default    " ... no -- return the static one
+
+       epp3    get_to_cl_$unclaimed_signal     " ... yes  -- return default value
+       spri3   pr2|0
+       ldaq    null                    "           (it's external)
+       staq    pr2|2
+       short_return
+
+get_cl_intermediary_non_default:
+       epp3    pr5|cl_entry,*          " copy from our internal static
+       spri3   pr2|0
+       epp3    pr5|cl_entry+2,*
+       spri3   pr2|2
+       short_return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      get_cl .... entry to retrieve procedure ptr to re-enter command level
+"
+"      call cu_$get_cl(cl_ptr);
+"
+"      1. cl_ptr (ptr) - pointer to procedure to re-enter command level
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " "" " " " " " " " " " " " "
+
+get_cl:        epp2    pr5|cl_entry,*          " pick up current command level proc ptr
+       spri2   ap|2,*
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    set_cl_intermediary ..... entry to specify procedure to call to re-enter command level
+"
+"      call cu_$set_cl_intermediary(cl_entry)
+"
+"      1. cl_entry (entry) - entry to procedure to re-enter command level
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+set_cl_intermediary:
+       epp2    ap|2,*                  " get pointer to caller's entry var
+       epp3    pr2|0,*                 " copy entry variable to our static
+       spri3   pr5|cl_entry
+       epp3    pr2|2,*
+       spri3   pr5|cl_entry+2
+       short_return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    set_cl ..... entry to specify external proc to call to re-enter command level
+"
+"      call cu_$set_cl(cl_ptr)
+"
+"      1. cl_ptr (ptr) - pointer to external proc to re-enter command level;
+"                      if null, the default procedure is used
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+set_cl:        epp2    ap|2,*                  " get ptr to the codeptr
+       epp2    pr2|0,*                 " copy codeptr to our static
+       spri2   pr5|cl_entry
+       ldaq    null                    " indicate external procedure
+       staq    pr5|cl_entry+2
+       short_return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    reset_cl_intermediary .... entry to reset to default re-enter command level proc
+"
+"      call cu_$reset_cl_intermediary ()
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+reset_cl_intermediary:
+       ldaq    null                    " set to null -- cu_$cl will special case
+       staq    pr5|cl_entry
+       staq    pr5|cl_entry+2
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    cp ..... entry to-call currently specified command processor
+"
+"      call cu_$cp (line_ptr, line_lth, code)
+"
+"      1. line_ptr (ptr) - pointer to command line to execute
+"      2. line_lth (fixed bin(21)) - length of command line
+"      3. code (fixed bin(35)) - standard status code (Output)
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+cp:    epp1    pr5|cp_entry            " will be calling this entry variable
+       ldaq    pr1|0                   " is it user supplied procedure?
+       eraq    null
+       anaq    ptrmask
+       tnz     generate_call_common    " ... yes -- go off and perform the call
+
+       callsp  command_processor_$command_processor_   " ... no -- use default proc
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      get_command_processor .... entry to retrieve entry var of current command processor
+"
+"      call cu_$get_command_processor (cp_entry);
+"
+"      1. cp_entry (entry) - entry variable of current command processor
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " "" " " " " " " " " " " " "
+
+get_command_processor:
+       epp2    ap|2,*                  " get pointer to user's entry variable
+       ldaq    pr5|cp_entry            " is default procedure in use?
+       eraq    null
+       anaq    ptrmask
+       tnz     get_cp_non_default              " ... no
+
+       epp3    command_processor_$command_processor_   " ... yes -- return it
+       spri3   pr2|0
+       ldaq    null
+       staq    pr2|2                   "    (it's external)
+       short_return
+
+get_cp_non_default:
+       epp3    pr5|cp_entry,*          " copy from our internal static
+       spri3   pr2|0
+       epp3    pr5|cp_entry+2,*
+       spri3   pr2|2
+       short_return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      get_cp .... entry to retrieve procedure ptr to current command processor
+"
+"      call cu_$get_cp (cp_ptr);
+"
+"      1. cp_ptr (ptr) - pointer to current command processor
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " "" " " " " " " " " " " " "
+
+get_cp:        epp2    pr5|cp_entry,*          " pick up current command processor
+       spri2   ap|2,*
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    set_command_processor ..... entry to specify procedure to call as the command processor
+"
+"      call cu_$set_command_processor (cp_entry)
+"
+"      1. cp_entry (entry) - entry to become the command processor
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+set_command_processor:
+       epp2    ap|2,*                  " get pointer to caller's entry var
+       epp3    pr2|0,*                 " copy entry variable to our static
+       spri3   pr5|cp_entry
+       epp3    pr2|2,*
+       spri3   pr5|cp_entry+2
+       short_return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    set_cp ..... entry to specify external proc to be command processor
+"
+"      call cu_$set_cp (cp_ptr)
+"
+"      1. cp_ptr (ptr) - pointer to external proc to be the command processor;
+"                      if null, the default procedure is used
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+set_cp:        epp2    ap|2,*                  " get ptr to the codeptr
+       epp2    pr2|0,*                 " copy codeptr to our static
+       spri2   pr5|cp_entry
+       ldaq    null                    " indicate external procedure
+       staq    pr5|cp_entry+2
+       short_return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    reset_command_processor .... entry to reset to default command processor
+"
+"      call cu_$reset_command_processor ()
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+reset_command_processor:
+       ldaq    null                    " reset to null -- cu_$cp will then
+       staq    pr5|cp_entry            " ... transfer to the default
+       staq    pr5|cp_entry+2
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"     ready_proc ..... entry to be called after each command line is processed --
+"                 (default procedure prints a ready message if on)
+"
+"      call cu_$ready_proc (ready_modes);
+"
+"      dcl 1 ready_modes aligned, /* optional argument */
+"          2 ready_sw bit(1) unaligned, /* ON => print a ready message */
+"          2 pad bit(35) unaligned;
+"
+"      If ready_modes isn't supplied, an internal static structure is passed whose
+"      contents may be changed via cu_$set_ready_mode and read via cu_$get_ready_mode;
+"      the default value for ready_modes.ready_sw in the static structure is "1"b.
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+ready_proc:
+       lda     ap|0                    " pick up arg list header
+       cana    =o777777,du             " any arguments passed?
+       tnz     ready_with_args         " ... yes -- use supplied arglist
+       eppap   pr5|ready_arglist               " ... no -- use current setting
+       epp2    pr5|ready_mode          " ...     controlled by ready_on/off
+       spri2   pr5|ready_arglist+2
+
+ready_with_args:
+       epp1    pr5|ready_entry         " will be calling this entry variable
+       ldaq    pr1|0                   " user supplied procedure?
+       eraq    null
+       anaq    ptrmask
+       tnz     generate_call_common    " ... yes -- go off and perform the call
+
+       callsp  print_ready_message_$print_ready_message_    " ... no -- use default
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      get_ready_procedure .... entry to retrieve entry var of current ready procedure
+"                           (procedure called after each command line normally to
+"                            print a ready message)
+"
+"      call cu_$get_ready_procedure (ready_entry);
+"
+"      1. ready_entry (entry) - entry variable of current ready procedure
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " "" " " " " " " " " " " " "
+
+get_ready_procedure:
+       epp2    ap|2,*                  " get ptr to entry variable argument
+       ldaq    pr5|ready_entry         " using default procedure?
+       eraq    null
+       anaq    ptrmask
+       tnz     get_ready_procedure_non_default    " ... no
+
+       epp3    print_ready_message_$print_ready_message_    " ... yes -- return it
+       spri3   pr2|0
+       ldaq    null                    "    (it's external)
+       staq    pr2|2
+       short_return
+
+get_ready_procedure_non_default:
+       epp3    pr5|ready_entry,*               " copy from our internal static
+       spri3   bp|0
+       epp3    pr5|ready_entry+2,*
+       spri3   bp|2
+       short_return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      get_ready_proc .... entry to retrieve procedure ptr to current ready procedure
+"
+"      call cu_$get_ready_proc (ready_ptr);
+"
+"      1. ready_ptr (ptr) - pointer to current ready procedure
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " "" " " " " " " " " " " " "
+
+get_ready_proc:
+       epp2    pr5|ready_entry,*               " pick up current command processor
+       spri2   ap|2,*
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    set_ready_procedure ..... entry to specify procedure to call as the command processor
+"
+"      call cu_$set_ready_procedure (ready_entry)
+"
+"      1. ready_entry (entry) - entry to become the command processor
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+set_ready_procedure:
+       epp2    ap|2,*                  " get pointer to caller's entry var
+       epp3    pr2|0,*                 " copy entry variable to our static
+       spri3   pr5|ready_entry
+       epp3    pr2|2,*
+       spri3   pr5|ready_entry+2
+       short_return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    set_ready_proc ..... entry to specify external proc to be ready procedure
+"
+"      call cu_$set_ready_proc (ready_ptr)
+"
+"      1. ready_ptr (ptr) - pointer to external proc to be the ready procedure;
+"                       if null, the default procedure is used
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+set_ready_proc:
+       epp2    ap|2,*                  " get ptr to the codeptr
+       epp2    pr2|0,*                 " copy codeptr to our static
+       spri2   pr5|ready_entry
+       ldaq    null                    " indicate external procedure
+       staq    pr5|ready_entry+2
+       short_return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    reset_ready_procedure .... entry to reset to default ready procedure
+"
+"      call cu_$reset_ready_procedure ()
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+reset_ready_procedure:
+       ldaq    null                    " reset to null -- cu_$ready_proc will
+       staq    pr5|ready_entry         " transfer to the default
+       staq    pr5|ready_entry+2
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      set_ready_mode ..... entry to set the internal ready flags for controlling ready
+"                       message printing
+"
+"      call cu_$set_ready_mode (ready_flags);
+"
+"      1. ready_flags (see description of cu_$ready_proc) (INPUT)
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+set_ready_mode:
+       lda     ap|2,*                  " copy flags to out static
+       sta     pr5|ready_mode
+       short_return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      get_ready_mode ..... entry to return the value of the ready flags
+"
+"      call cu_$get_ready_mode (ready_flags);
+"
+"      1. ready_flags (see description of cu_$ready_proc)  (OUTPUT)
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+get_ready_mode:
+       lda     pr5|ready_mode          " copy ready flags to caller
+       sta     ap|2,*
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    evaluate_active_string ..... entry to-call current active-string evaluator
+"
+"      call cu_$evaluate_active_string (info_ptr, active_string, string_type,
+"                                 return_value, code);
+"
+"      1. info_ptr (ptr) - reserved for future expansion and must be null
+"      2. active_string (char (*)) - string to evaluate without outermost brackets
+"      3. string_type (fixed bin) - type of active string (see cp_active_string_types.incl.pl1)
+"      4. return_value (char (*) var) - result of the evaluation (Output)
+"      5. code (fixed bin(35)) - standard status code (Output)
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+evaluate_active_string:
+       epp1    pr5|eas_entry           " will be calling this entry variable
+       ldaq    pr1|0                   " user supplied procedure?
+       eraq    null
+       anaq    ptrmask
+       tnz     generate_call_common    " ... yes -- go off and perform the call
+
+       callsp  command_processor_$eval_string     " ... no -- use default
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      get_evaluate_active_string .... entry to retrieve entry var of current active
+"                                string evaluator
+"
+"      call cu_$get_evaluate_active_string (eas_entry);
+"
+"      1. eas_entry (entry) - entry variable of current active-string evaluator
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " "" " " " " " " " " " " " "
+
+get_evaluate_active_string:
+       epp2    ap|2,*                  " get ptr to entry variable argument
+       ldaq    pr5|eas_entry           " using defaulr procedure?
+       eraq    null
+       anaq    ptrmask
+       tnz     get_eas_non_default             " ... no
+
+       epp3    command_processor_$eval_string     " ... yes -- return it
+       spri3   pr2|0
+       ldaq    null                    "    (it's external)
+       staq    pr2|2
+       short_return
+
+get_eas_non_default:
+       epp3    pr5|eas_entry,*         " copy from our internal static
+       spri3   pr2|0
+       epp3    pr5|eas_entry+2,*
+       spri3   pr2|2
+       short_return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    set_evaluate_active_string ..... entry to specify procedure to call as the active
+"                              string evaluator
+"
+"      call cu_$set_evaluate_active_string (eas_entry)
+"
+"      1. eas_entry (entry) - entry to become the active-string evaluator
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+set_evaluate_active_string:
+       epp2    ap|2,*                  " get pointer to caller's entry var
+       epp3    pr2|0,*                 " copy entry variable to our static
+       spri3   pr5|eas_entry
+       epp3    pr2|2,*
+       spri3   pr5|eas_entry+2
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    reset_evaluate_active_string .... entry to reset to default active-string evaluator
+"
+"      call cu_$reset_evaluate_active_string ()
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+reset_evaluate_active_string:
+       ldaq    null                    " reset to null --
+       staq    pr5|eas_entry           " ... cu_$evaluate_active_string will
+       staq    pr5|eas_entry+2         " ... transfer to default
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"     generate_call ... entry to call an entry variable with the supplied argument list
+"
+"      call cu_$generate_call (entry_variable, arg_list_ptr);
+"
+"      1. entry_variable (entry) -- the entry to be called.  It may be an internal
+"                               procedure;" this entry will take care of the display
+"                               ptr in the argument list.
+"      2. arg_list_ptr (ptr) -- pointer to the argument list to be given to the entry
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+generate_call:
+       epp1    ap|2,*                  " get ptr to entry variable
+       eppap   ap|4,*                  " get ptr to argument list for call
+       eppap   ap|0,*                  " ... and point to actual arglist
+
+
+" Control reaches here from the cu_$cl, etc. entries to invoke their specific entry variable
+
+generate_call_common:
+       lxl0    ap|0                    " pick up argument list code
+       anx0    8+2,du                  " check if display pointer present
+       tnz     3,ic                    " ... yes -- go get it
+       ldaq    null                    " ... no -- use null (external call)
+       tra     3,ic                    "         and goto common code
+       ldx2    ap|0                    " ... 2*nargs
+       ldaq    ap|2,2                  " ... fetch display pointer
+
+       eraq    pr1|2                   " compare with entry's environmentptr
+       anaq    ptrmask
+       tnz     2,ic                    " ... not equal -- must copy arglist
+
+       callsp  pr1|0,*                 " display ptrs agree -- make the call
+
+
+" Entry variable's environmentptr is different from arglist's display ptr -- the arglist
+"  must be copied and the proper display pointer inserted...
+
+       eax1    0                       " assume that entry is external
+       ldaq    pr1|2                   " check if entry is external or internal
+       eraq    null
+       anaq    ptrmask
+       tze     2,ic                    " ... external -- no display ptr in arglist
+       eax1    2                       " ... internal -- must insert display ptr
+
+       eax7    stack_frame.min_length+17,1     " miniumum stack frame size + display
+                                       " ... pointer (if used) + rounding
+       adx7    ap|0                    " ... plus argument pointers
+       adx7    ap|1                    " ... plus descriptor pointers
+
+       anx7    =o777760,du             " ... round to mod 16
+       tsp2    sb|stack_header.push_op_ptr,* " get a stack frame
+       lda     stack_frame.support_bit,dl      " ... which is a support frame
+       orsa    sp|stack_frame.flag_word
+
+       epp2    sp|stack_frame.min_length       " arglist goes here
+
+       ldaq    ap|0                    " copy argument list header
+       staq    pr2|0
+
+       eax2    4                       " assume no display pointer
+       cmpx1   0,du                    " putting in a display pointer?
+       tze     2,ic                    " ... no -- have correct code already
+       eax2    8                       " ... yes -- get proper code for header
+       sxl2    pr2|0                   " update code in arglist header
+
+       ldx2    pr2|0                   " 2*nargs
+       tze     6,ic                    " ... no arguments to copy
+       epp3    ap|0,2*                 " copy argument list pointers
+       spri3   pr2|0,2
+       eax2    -2,2                    " ... done?
+       tpnz    -3,ic                   " ... ... no
+
+       ldx2    pr2|0                   " 2*nargs again
+       eppap   ap|0,2                  " ... ptr to last argptr in original list
+       epp3    pr2|0,2                 " ... ptr to last argptr in new list
+
+       cmpx1   0,du                    " copy entry's environment ptr?
+       tze     4,ic                    " ... no
+       epp5    pr1|2,*                 " ... yes
+       spri5   pr3|2
+       epp3    pr3|2                   " ... indicate descriptors after display
+
+       ldx2    pr2|1                   " check if descriptors to copy
+       tze     generate_call_call              " ... no
+
+       cmpx0   0,du                    " copy descriptors -- skip old display?
+       tze     2,ic                    " ... no
+       eppap   ap|2                    " ... yes
+
+       ldx2    pr2|1                   " 2*ndescs
+       epp5    ap|0,2*                 " copy descriptors
+       spri5   pr3|0,2
+       eax2    -2,2                    " ... done?
+       tpnz    -3,ic                   " ... ... no
+
+generate_call_call:
+       call    pr1|0,*(pr2|0)          " make the call
+       return                          " ... and return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    gen_call ..... call specified external procedure with specified argument list
+"
+"      call cu_$gen_call(proc_ptr, arg_list_ptr)
+"
+"      1. proc_ptr (ptr) - pointer to external procedure to be called
+"      2. arg_list_ptr (ptr) - pointer to argument list for procedure call
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+gen_call:      eppbp   ap|2,*          get pointer to procedure pointer
+       eppap   ap|4,*          pick up argument list pointer
+       eppap   ap|0,*          ..
+       callsp  bp|0,*          call procedure entry point
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    ptr_call ..... call external procedure specified by first argument in call
+"
+"      call cu_$ptr_call (proc_ptr, arg1, ... , argN)
+"
+"      1. proc_ptr (ptr) - pointer to external procedure to be called
+"      2. arg1 ... argN - optional - arguments to be supplied in the call
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+ptr_call:      eax7    stack_frame.min_length+19       " minimum stack frame plus 4 words
+                                       " ... temporary storage plus rounding
+       adx7    ap|0                    " ... plus room for argument pointers
+       adx7    ap|1                    " ... plus room for descriptors
+
+       anx7    =o777760,du             " ... round to mod 16
+       tsp2    sb|stack_header.push_op_ptr,* " get a stack frame
+       lda     stack_frame.support_bit,dl      " ... which is a support frame
+       orsa    sp|stack_frame.flag_word
+
+       epp2    sp|stack_frame.min_length       " start of temporaries
+
+       epp3    ap|2,*                  " save codeptr of procedure to call
+       epp3    pr3|0,*
+       spri3   pr2|0
+
+       ldaq    ap|0                    " copy arglist header
+       staq    pr2|2
+
+       ldx1    pr2|2                   " decrement number of arguments
+       eax1    -2,1
+       stx1    pr2|2
+       tze     5,ic                    " no arguments in call ... skip copying
+
+       epp3    ap|2,1*                 " copy argument pointers
+       spri3   pr2|2,1
+       eax1    -2,1                    " ... done?
+       tpnz    -3,ic                   " ... ... no
+
+       ldx1    pr2|3                   " get descriptors count
+       tze     ptr_call_call           " none -- go make the call
+       eax1    -2,1                    " flush first descriptor
+       stx1    pr2|3
+       tze     ptr_call_call           " none left
+
+       ldx2    ap|0                    " move ap past argptrs and 1st
+       eppap   ap|2,2                  " ... descriptor
+       ldx2    pr2|2                   " move past argptrs in new arglist
+       epp3    pr2|2,2
+
+       epp5    ap|0,1*                 " copy descriptors
+       spri5   pr3|0,1
+       eax1    -2,1                    " ... done?
+       tpnz    -3,ic                   " ... ... no
+
+ptr_call_call:
+       call    pr2|0,*(pr2|2)          " make the call
+       return                          " ... and return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    arg_count ..... get number of arguments passed to caller of arg_count
+"
+"      call cu_$arg_count (nargs, code)
+"
+"      1. nargs (fixed bin(17)) - number of arguments (returned).
+"      2. code (fixed bin(35)) - optional - set to one of zero, error_table_$nodescr, or
+"                            error_table_$active_function.
+"
+"      If code is supplied, a check is made that the last argument is not char(*) varying
+"      which is indicative of being invoked as an active function.  This check provides a
+"      mechanism for command-only procedures to detect improper usage.
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+arg_count:
+       eax0    4                       " code (if present) is second argument
+       epp1    sp|stack_frame.arg_ptr,*        " ptr to caller's stack frame
+       tra     arg_count_common                " join main section of code
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    arg_count_rel ..... get number of arguments in specified argument list
+"
+"      call cu_$arg_count_rel (nargs, arg_list_ptr, code);
+"
+"      1. nargs (fixed bin(17)) - number of args in that list (output)
+"      2. arg_list_ptr (ptr) - pointer to arg list in question (input)
+"      3. code (fixed bin(35)) - optional - see cu_$arg_count above
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+arg_count_rel:
+       eax0    6                       " code (if present) is third argument
+       epp1    ap|4,*                  " get arglist pointer
+       epp1    pr1|0,*
+
+
+arg_count_common:
+       lda     pr1|0                   " return the argument count
+       arl     18+1                    " ... which was in au and was also doubled
+       sta     ap|2,*
+
+       cmpx0   ap|0                    " did caller supply a code argument?
+       tmoz    arg_count_hard          " ... yes
+       short_return                    " ... no -- all done, return to caller
+
+
+" Status code is specified: check that last argument is not character(*) varying which would
+"  indicate active function usage.
+
+arg_count_hard:
+       stz     ap|0,0*                 " initialize return code
+
+       ldx1    pr1|0                   " any arguments?
+       tnz     ach_continue            " ... yes
+       short_return                    " ... no -- OK for command to have no args
+
+ach_continue:
+       lda     pr1|0                   " pick up argument list header
+       cana    4+8,dl                  " make sure its a PL1 call
+       tze     ach_err_no_descs                " ... it isn't
+
+       ldx1    pr1|0                   " 2*nargs to x1
+       cmpx1   pr1|1                   " same number of descriptors present?
+       tnz     ach_err_no_descs                " ... no -- can't determine if valid
+
+       adx1    pr1|1                   " take descriptors into account also
+
+       lxl2    pr1|0                   " check if display pointer is present
+       anx2    8+2,du
+       tze     2,ic                    " ... no
+       eax1    2,1                     " ... yes -- skip past it also
+
+       lda     pr1|0,1*                        " fetch the descriptor
+       tpl     ach_check_v1            " might be a version 1 descriptor
+
+       ldq     v2_mask                 " mask out all but datatype
+       cmk     v2_var,du                       " is it char(*) varying?
+       tze     ach_err_af              " ... yes -- invoked as an active function
+       short_return                    " ... no -- all is OK
+
+ach_check_v1:
+       ldq     desc_mask                       " pick up mask for version 1 descriptors
+       cmk     var_desc,du             " is it char(*) varying?
+       tze     ach_err_af              " ... yes
+       short_return                    " ... no
+
+
+ach_err_no_descs:                              " no descriptors in arglist
+       lda     error_table_$nodescr
+       sta     ap|0,0*
+       short_return
+
+ach_err_af:                            " called as active function
+       lda     error_table_$active_function
+       sta     ap|0,0*
+       short_return
+
+"\f
+
+" " " " " " " " " " " " " " " " " " " " "" " " " " " " " "" " "" " " "" " "" "" 
+"     arg_ptr_rel ..... get nth argument of specified argument list 
+"
+"      call cu_$arg_ptr_rel(argno, argptr, arglen, code, arg_list_ptr);
+"
+"      1. argno (fixed bin(17)) - specifies the desired argument.
+"      2. argptr (ptr) - pointer to specified argument (returned).
+"      3. arglen (fixed bin(17)) - size of specified argument (returned).
+"      4. code (fixed bin(17)) - error status code (returned).
+"      5. arg_list_ptr (ptr) - pointer to desired argument list.
+"
+" " " " " " " " " " " " " " " "" " "" " " " " "" " " " " " " " "" "" " " "" "" "
+
+arg_ptr_rel:
+       eppbp   ap|10,*                 " get the argument list pointer
+       eppbp   bp|0,*                  " ...
+       tra     arg_ptr_common
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"    arg_ptr ..... get ptr (and size) of caller's nth argument
+"
+"      call cu_$arg_ptr(argno, argptr, arglen, code)
+"
+"      1. argno (fixed bin(17)) - specifies the desired argument.
+"      2. argptr (ptr) - pointer to specified argument (returned).
+"      3. arglen (fixed bin(17)) - size of specified argument (returned).
+"      4. code (fixed bin(17)) - error status code (returned).
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+arg_ptr:       eppbp   sp|stack_frame.arg_ptr,*        " get pointer to caller's argument list
+
+arg_ptr_common:
+       ldaq    null                    " initialize output values
+       staq    ap|4,*                  " ... null argument pointer
+       stz     ap|6,*                  " ... zero length
+       stz     ap|8,*                  " ... zero error code
+
+       lda     ap|2,*                  " pick up argument number
+       tmoz    arg_ptr_noarg           " ... must be positive
+       als     1
+       eax1    0,al                    " 2*argument_idx -> X1
+       cmpx1   bp|0                    " check against the argument count
+       tpnz    arg_ptr_noarg           " ... argument_idx is too large
+
+       eppbb   bp|0,1*                 " copy the argument pointer
+       spribb  ap|4,*
+
+       ldx2    bp|1                    " get descriptor word count
+       tze     arg_ptr_no_descriptors  " ... no descriptors
+       adx1    bp|0                    " compute offset to the descriptor
+       lxl0    bp|0                    " ... check for an environment pointer
+       anx0    8+2,du
+       tze     2,ic
+       eax1    2,1                     " ... skip over environment pointer
+
+       lda     bp|0,1*                 " pick up the descriptor
+       tmi     *+2
+       ana     =o777777,dl             " mask for version 1 descriptors
+       ana     descriptor_mask         " mask for version 2 descriptors
+       sta     ap|6,*                  " return the argument length
+
+arg_ptr_no_descriptors:
+       short_return
+
+arg_ptr_noarg:                         " unknown argument specified
+       lda     error_table_$noarg
+       sta     ap|8,*
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " "" " " " " " " " "" " "" " " "" " "" ""
+"     get_command_name_rel ..... get the command name from the passed arg list
+"
+"      call cu_$get_command_name_rel( command_name_ptr, command_name_length, 
+"                              code, arg_list_ptr);
+"
+"      1. command_name_ptr (pointer) - ptr to command_name (returned)
+"      2. command_name_length (fixed bin (21)) - size of command_name (returned)
+"      3. code (fixed bin(35)) - error status code (returned).
+"      4. arg_list_ptr (pointer) - pointer to desired argument list.
+"
+" " " " " " " " " " " " " " " "" " "" " " " " "" " " " " " " " "" "" " " "" """
+
+get_command_name_rel:
+       eppbp   ap|8,*                  " get the argument list pointer
+       eppbp   bp|0,*                  " ...
+       tra     get_command_name_common
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"    get_command_name ..... get command name from callers arg list
+"
+"      call cu_$get_command_name(command_name_ptr, command_name_length, code)
+"
+"      1. command_name_ptr (pointer) - ptr to command_name (returned)
+"      2. command_name_length (fixed bin (21)) - size of command_name (returned)
+"      3. code (fixed bin(35)) - error status code (returned).
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+get_command_name:
+       eppbp   sp|stack_frame.arg_ptr,*        " get pointer to caller's argument list
+
+get_command_name_common:
+       ldaq    null                    " initialize output values
+       staq    ap|2,*                  " ... command nm ptr = null
+       stz     ap|4,*                  " ... size = 0
+       stz     ap|6,*                  " ... zero error code
+
+
+" check if has name is set
+
+       lxl0    bp|1                    " get has name flag
+       anx0    has_command_name_mask   " and upper bit of 2nd half
+       tze     get_command_name_no_name        " has name not set return error code
+
+" check if non-quick internal procedure
+
+       lxl0    bp|0                    " get call type
+       anx0    8,du                    " compare to 000010 octal
+       tnz     get_command_name_no_name        " internal call therfore don't have a command name
+
+" get effective ptr to name and size is + 2 past
+
+       ldx0    bp|0                    " get arg count
+       eppbb   bp|2,x0                 " get ptr past args
+       ldx0    bp|1                    " get desc count
+       eppbb   bb|0,x0                 " got ptr to name ptr
+
+" set return values of name ptr and size
+
+       epplb   bb|0,*                  " get name ptr
+       sprilb  ap|2,*                  " store name ptr
+       lda     bb|2                    " get size
+       ana     fb21_mask                       "get fixed bin 21 value
+       sta     ap|4,*                  " store size
+
+       short_return
+
+get_command_name_no_name:              " name not available
+       lda     error_table_$command_name_not_available
+       sta     ap|6,*          
+       short_return
+
+
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      af_return_arg ..... returns info on active function arg lists
+"
+"      call cu_$af_return_arg (n_args, return_ptr, return_len, code);
+"
+"      1. n_args               number of args (output) (not including return arg)
+"      2. return_ptr   pointer to return arg (output)
+"      3. return_len   max length of return arg (output)
+"      4. code         standard status code
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+af_return_arg:
+       ldaq    null                    " initialize output arguments
+       staq    ap|4,*
+       stz     ap|6,*
+
+       eax2    8                       " error code is 4th argument
+       tsx1    verify_af                       " check the call
+       arg     af_return_arg_return    " ... error return
+
+af_return_arg_common:
+       sta     ap|6,*                  " set return value's maximum length
+
+       eppbb   bb|0,*                  " get pointer to return value
+       eppbb   bb|-1                   " ... and adjust to its length word
+       spribb  ap|4,*
+
+af_return_arg_return:
+       stq     ap|2,*                  " set the argument count (from verify_af)
+       short_return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      af_return_arg_rel ..... like af_return arg, but the fifth argument is
+"                          a pointer to the argument list to use
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+af_return_arg_rel:
+       ldaq    null                    " initialize output arguments
+       staq    ap|4,*
+       stz     ap|6,*
+
+       eax2    8                       " error code is 4th argument
+       eppbp   ap|10,*                 " get the real argument list pointer
+       eppbp   bp|0,*                  " ...
+
+       tsx1    verify_af_rel           " verify that the call is OK
+       arg     af_return_arg_return    " ... error return
+
+       tra     af_return_arg_common
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      af_arg_count ..... return active function arg count
+"
+"      call cu_$af_arg_count (n_args, code);
+"
+"      1. n_args               number of arguments (output)
+"      2. code         standard status code
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+af_arg_count:
+       eax2    4                       " error code is 2nd argument
+       tsx1    verify_af                       " check the call
+       arg     af_arg_count_return             " ... error return
+
+af_arg_count_return:
+       stq     ap|2,*                  " set the argument count
+       short_return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      af_arg_count_rel ..... like af_arg_count but the third arg is
+"                          a pointer to the argument list to use
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+af_arg_count_rel:
+       eppbp   ap|6,*                  " get a pointer to the argument list
+       eppbp   bp|0,*                  " ...
+
+       eax2    4                       " error code is 2nd argument
+       tsx1    verify_af_rel           " check the call
+       arg     af_arg_count_rel_return " ... error return
+
+af_arg_count_rel_return:
+       stq     ap|2,*                  " set the argument count
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      af_arg_ptr ..... returns pointer to an active function argument
+"
+"      call cu_$af_arg_ptr (arg_no, arg_ptr, arg_len, code);
+"
+"      1. arg_no               the number of the argument desired (input)
+"      2. arg_ptr      pointer to that argument (output)
+"      3. arg_len      its length (output)
+"      4. code         standard status code
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+af_arg_ptr:
+       ldaq    null                    " initialize output arguments
+       staq    ap|4,*
+       stz     ap|6,*
+
+       eax2    8                       " error code is 4th argument
+       tsx1    verify_af                       " check the call
+       arg     af_arg_ptr_return               " ... error return
+
+af_arg_ptr_common:
+       cmpq    ap|2,*                  " check argument_idx against n_argument
+       tmi     af_arg_ptr_noarg                " ... too large
+
+       ldq     ap|2,*                  " pick up the argument_idx
+       tmoz    af_arg_ptr_noarg                " ... must be positive
+
+       qls     18+1                    " convert to pointer offset
+       eppbp   bp|0,qu                 " make bp -> the argument pointer
+
+       ldq     bp|0,3*                 " fetch the argument descriptor
+       tmi     2,ic
+       anq     -1,dl                   " version 1 descriptor length mask
+       anq     =o77777777              " mask all but the length
+       stq     ap|6,*                  " set the length
+
+       eppbb   bp|0,*                  " get the argument pointer
+       spribb  ap|4,*
+
+af_arg_ptr_return:
+       short_return
+
+af_arg_ptr_noarg:
+       lda     error_table_$noarg
+       sta     ap|8,*
+       short_return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      af_arg_ptr_rel ..... like af_arg_ptr
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+af_arg_ptr_rel:
+       ldaq    null                    " initialize output arguments
+       staq    ap|4,*
+       stz     ap|6,*
+
+       eppbp   ap|10,*                 " get the argument list pointer
+       eppbp   bp|0,*                  " ...
+
+       eax2    8                       " error code is 4th argument
+       tsx1    verify_af_rel           " check the call
+       arg     af_arg_ptr_return               " ... error return
+
+       tra     af_arg_ptr_common               " go do the work
+
+" \f
+
+" Verifies that the given argument list belongs to an active function.  Ie: The last
+"    argument must be a varying character string
+
+verify_af:
+       eppbp   sp|stack_frame.arg_ptr,*        " use caller's argument list
+
+verify_af_rel:                         " use argument list pointer already in bp
+       stz     ap|0,2*                 " clear status code
+
+       lda     bp|0                    " pick up argument list header
+       cana    4+8,dl                  " must be a PL/I call
+       tze     af_error_not_af
+
+       eax0    0,au                    " argument count to X0
+       tze     af_error_not_af         " ... no arguments: can't be an AF
+
+       cmpx0   bp|1                    " last argument must have a descriptor
+       tnz     af_error_nodescr
+
+       eppbb   bp|0,0                  " set to locate the descriptors
+       eax3    0,0                     " ... check for an environment pointer
+       ana     8+2,dl
+       tze     2,ic                    " ... no environment pointer
+       eax3    2,3                     " ... skip over environment pointer
+
+       lda     bb|0,3*                 " get the descriptor
+       tpl     check_v1_desc           " ... it's a version 1 descriptor
+
+       ldq     v2_mask                 " get mask to look at data type
+       cmk     v2_var,du                       " and check if it's a varying string
+       tnz     af_error_not_af         " ... no
+       ana     =o77777777              " get the return value's length
+       eaq     -2,0                    " compute actual argument count
+       qrl     18+1                    " ... which excludes the return value
+       tra     1,1                     " normal return
+
+check_v1_desc:                         " version 1 argument descriptor
+       ldq     desc_mask                       " get mask to look at data type
+       cmk     var_desc,du             " and check if it's a varying string
+       tnz     af_error_not_af         " ... no
+       ana     -1,dl                   " get the return value's length
+       eaq     -2,0                    " compute actual argument count
+       qrl     18+1                    " ... which excludes the return value
+       tra     1,1                     " normal return
+
+af_error_nodescr:                              " no descriptors in argument list
+       lda     error_table_$nodescr
+       tra     af_error_return
+
+af_error_not_af:                               " last argument isn't character(*) varying
+       lda     error_table_$not_act_fnc
+
+af_error_return:
+       sta     ap|0,2*                 " set return code
+       eaq     0,0                     " put argument count into the Q
+       qrl     18+1                    " ...
+       tra     0,1*                    " take error return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"   caller_ptr ..... get pointer to text section of invoker's caller
+"
+"      call cu_$caller_ptr (pointer);
+"
+"      1. pointer (ptr) is the pointer to invoker's caller's text section
+"           provided he had a stack frame, or null if no caller exists.
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+caller_ptr:
+       eppbp   sp|stack_frame.prev_sp,*        get pointer to previous frame
+       eppbb   bp|stack_frame.return_ptr,*     pick up the caller's pointer
+       spribb  ap|2,*                  return pointer to caller
+       short_return                    return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"   arg_list_ptr ..... get pointer to caller's argument list
+"
+"      call cu_$arg_list_ptr(ap)
+"
+"      1. ap (ptr) - pointer to caller's argument list (OUTPUT)
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+arg_list_ptr:
+       eppbp   sp|stack_frame.arg_ptr,*        " pick up caller's argument list pointer
+       spribp  ap|2,*                  " return it to caller
+       short_return                    " return control to caller
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    stack_frame_ptr ..... get pointer to caller's stack frame
+"
+"      call cu_$stack_frame_ptr(sp)
+"
+"      1. sp (ptr) - pointer to caller's stack frame (returned).
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+stack_frame_ptr:
+       sprisp  ap|2,*          return stack frame pointer to caller
+       short_return            return control to caller
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    stack_frame_size ..... get size of caller's stack frame
+"
+"      call cu_$stack_frame_size(len)
+"
+"      1. len (fixed bin(17)) - size of caller's stack frame (returned).
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+
+stack_frame_size:
+       ldq     sp|stack_frame.next_sp+1        " get offset of next stack frame ...
+       qrl     18                      " ... into lower half of Q
+       sblq    sp|0,dl                 " subtract offset of our stack frame ...
+       stq     ap|2,*                  " ... and you have the stack frame size
+       short_return
+"\f
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    grow_stack_frame ..... allocate space at end of caller's stack frame
+"
+"      call cu_$grow_stack_frame(len, ptr, code)
+"
+"      1. len (fixed bin(17)) - length (in words) by which to grow frame.
+"      2. ptr (ptr) - pointer to space allocated in frame (returned).
+"      3. code (fixed bin(17)) - error status code (returned).
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+
+grow_stack_frame:
+       eppbp   sb|stack_header.stack_end_ptr,* pick up pointer to next stack frame
+       spribp  ap|4,*          return it as ptr to allocated space
+       stz     ap|6,*          preset error code to zero (OK)
+       lda     ap|2,*          pick up size by which to grow frame
+       ada     15,dl           force size to mod 16
+       ana     =o777760,dl     ..
+       eax1    0,al            place size (now mod 16) into index 1
+       adx1    sb|stack_header.stack_end_ptr+1 add size to stack end pointer
+       stx1    sp|stack_frame.next_sp+1 bump next frame pointer
+       stx1    sb|stack_header.stack_end_ptr+1 update stack end pointer too
+       lda     ap|0            check for call from PL/I procedure
+       cana    =o14,dl         ..
+       tze     sb|stack_header.ret_no_pop_op_ptr,*     .. skip if not called by PL/I procedure
+       stx1    sp|5            .. otherwise, correct sp|5 for PL/I
+       short_return            return control to caller
+
+" \f
+" " " " " " " " " "  " " " " " " "  " " " " " " " " " "  " " " " "" " " "
+"
+"      shrink_stack_frame .....  reduce the size of the present stack frame
+"
+"      call cu_$shrink_stack_frame (stack_ptr, code);
+"
+"      1. stack_ptr (ptr) - pointer to position in the present stack frame which
+"                       will be the beginning of the next stack frame.
+"                       The pointer must be sixteen word aligned.
+"      2. code (fixed bin(17)) - error status code (returned).
+"
+" " " " " " " " " " " " " " " " " " "   " " " " " " " " " "   " "  " " " " " 
+
+
+shrink_stack_frame:
+       stz     ap|4,*          zero out code
+       eppbp   ap|2,*          get stack pointer
+       eax1    bp|0,*          ..
+       canx1   =o000017,du     check for sixteen aligned
+       tze     aligned         ..
+
+       lda     error_table_$eight_unaligned    if not aligned return code
+       sta     ap|4,*          ..
+       short_return            ..
+
+aligned:       eax2    sp|stack_frame.min_length check to see if before this frame
+       cmpx2   bp|1            ..
+       tmi     inscope1                ..
+
+       lda     error_table_$frame_scope_err    if so return error code
+       sta     ap|4,*          ..
+       short_return            ..
+
+inscope1:      cmpx1   sb|stack_header.stack_end_ptr+1 check to see if after this frame
+       tmi     inscope2                ..
+
+       lda     error_table_$frame_scope_err    if so return error code
+       sta     ap|4,*          ..
+       short_return            ..
+
+inscope2:      stx1    sp|stack_frame.next_sp+1 if all ok, set next frame pointer
+       stx1    sb|stack_header.stack_end_ptr+1 set end ptr
+       lda     ap|0            check for PL/1 call
+       cana    =o14,dl         ..
+       tze     sb|stack_header.ret_no_pop_op_ptr,*     skip if not PL/1
+       stx1    sp|5            correct sp|5 for PL/1
+       short_return            return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"     decode_entry_value ..... extract ptrs from PL/I entry variable
+"
+"      call cu_$decode_entry_value(entry_value, ep_ptr, env_ptr)
+"
+"      1. entry_value (entry) - entry value to be decoded
+"      2. ep_ptr (ptr) - entry point pointer
+"      3. env_ptr (ptr) - environment pointer
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+
+decode_entry_value:
+       epp5    ap|2,*          get ptr to  entry value
+       epp3    pr5|0,*         pick up entry ptr from entry variable
+       spri3   ap|4,*          store entry ptr in second arg
+       epp3    pr5|2,*         pick up environment ptr from  entry variable
+       spri3   ap|6,*          store environment ptr in third arg
+       short_return
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"     make_entry_value ..... construct PL/I entry value from input pointer
+"
+"      call  cu_$make_entry_value (ep_ptr, entry_var)
+"
+"      1. ep_ptr (ptr) - points to external entry point
+"      2. entry_var (entry) - entry variable to be filled in
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+
+make_entry_value:
+       epp5    ap|2,*          get ptr to first arg
+       epp5    pr5|0,*         pick up ep_ptr
+       epp3    ap|4,*          get ptr to entrry variable
+       spri5   pr3|0           store ep_ptr into  it
+       ldaq    null            pick up null ptr
+       staq    pr3|2           and store in entry variable
+       short_return
+
+" \f
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    level_get ..... entry to get (return) the current validation level
+"
+"      call cu_$level_get (level)
+"
+"      1. level (fixed bin(17)) - current validation level (returned).
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+level_get:
+       callsp  hcs_$level_get          " only hardcore knows for sure
+
+
+
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"    level_set ..... entry to set the current validation level
+"
+"      call cu_$level_set(level)
+"
+"      1. level (fixed bin(17)) - validation level to be set.
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+level_set:
+       callsp  hcs_$level_set          " hardcore will do this
+
+       end
diff --git a/pl1/pl1_operators_.alm b/pl1/pl1_operators_.alm
new file mode 100644 (file)
index 0000000..1b94b37
--- /dev/null
@@ -0,0 +1,7570 @@
+" ***********************************************************
+" *                                                         *
+" * Copyright, (C) Honeywell Bull Inc., 1987                *
+" *                                                         *
+" * Copyright, (C) Honeywell Limited, 1984                  *
+" *                                                         *
+" * Copyright, (C) Honeywell Information Systems Inc., 1983 *
+" *                                                         *
+" * Copyright (c) 1972 by Massachusetts Institute of        *
+" * Technology and Honeywell Information Systems, Inc.      *
+" *                                                         *
+" ***********************************************************
+
+" HISTORY COMMENTS:
+"  1) change(87-03-05,Huen), approve(87-03-05,MCR7629),
+"     audit(87-04-15,RWaters), install(87-05-14,MR12.1-1029):
+"     Fix PL/1 error 2138 -
+"      Update the comments in "call_ent_var_desc" and "call_ext_in_desc" to
+"      indicate the offset of the argument list is in x1.  Fix PL/1 error 2122 -
+"      Allow Ceiling function work with negative fixed bin scaled numbers.
+"  2) change(87-06-26,Huen), approve(87-06-26,MCR7732),
+"     audit(87-07-10,RWaters), install(87-11-30,MR12.2-1004):
+"     Fix bug2121
+"  3) change(88-06-24,Huen), approve(88-06-24,MCR7916),
+"     audit(88-07-11,RWaters), install(88-07-15,MR12.2-1057):
+"     Fix high priority fortran error 510 -
+"      Fix bug causing fortran inquire statement gives incorrect response after
+"      the call to the condition handler.
+"  4) change(89-01-16,Huen), approve(89-01-16,MCR8033),
+"     audit(89-01-19,RWaters), install(89-02-28,MR12.3-1016):
+"     Fix PL/1 error 2192 (phx21224) -
+"      Changing indicators to allow maximum negative integer.
+"                                                      END HISTORY COMMENTS
+
+
+" NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
+"
+" pl1_operators_ MUST be bound with conversion program any_to_any_, put_format_, put_field_,
+"             and ALL of the math routines referenced from transfer vector
+"
+" NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
+"
+"      Operator Segment for PL/I Version II
+"      Barry Wolman
+"      March, 1969
+"
+"      Modified: 19 October, 1971 by BLW
+"      Modified: 27 January, 1972 by BLW
+"      Modified:  2 April, 1972 by BLW
+"      Modified:  1 July, 1972 by RBSnyder for follow-on
+"      Modified: 21 July, 1972 by BLW to fix mod operators
+"      Modified: 21 November, 1972 by BLW to add controlled operators
+"      Modified: 28 February, 1973 by BLW for odd base register saving
+"      Modified: 2 June, 1973 by BLW to use EIS for string operations
+"      Modified: 7 April, 1974 by BLW to fix bug 1078
+"      Modified: 10 April, 1974 by BLW to fix bug 1083
+"      Modified: 15 August, 1974 by BLW to fix bugs 1170, 1171, 1201, and 1202
+"      Modified: 1 November, 1974 by RAB to fix bug 1245
+"      Modified: 4 November, 1974 by RAB to add ldi to return_words
+"      Modified: 6 November, 1974 by SHW for new call/push/return sequences
+"      Modified: 14 November, 1974 by RAB to fix bug 1254
+"      Modified: 3 January, 1975 by RHS to support quick record i/o
+"      Modified:       1 February, 1975 by RAB to fix bug 1318
+"      Modified: 5 May, 1975 by RAB for separate static and new trace
+"      Modified: 22 May, 1975 by RAB to fix bug 1348
+"      Modified:       25 June, 1975 by RAB for new segdefs
+"      Modified:       5 November 1975 by RAB for new area package
+"      Modified:       29 December 1975 by RAB to fix bug 1449
+"      Modified: 27 February, 1976 by GDC for DFAST new entries
+"      Modified:  2 March, 1976 by RHS for quick "put list"s, a subset of quick stream i/o
+"      Modified:        1 June, 1976 by RAB to use free_|free_ for alloc_storage
+"      Modified:        6 June, 1976 by RHS for quick "put edit"s
+"      Modified:       12 October 1976 by RAB to have signal ops save and restore ALL regs properly
+"      Modified:       3 December 1976 by RAB to implement long_profile
+"      Modified:       16 December 1976 by RAB to fix 1564 (pointer and offset operators)
+"      Modified:       23 December 1976 by RAB for after, before, ltrim, rtrim
+"      Modified:       24 March 1977 by RAB for new complex divide algorithm
+"      Modified: 10 May 1977 by MBW to use user free area instead of free_
+"      Modified 770619 by PG to implement clock, vclock, and stacq
+"      Modified: 23 June 1977 by S. Webber to add ftn_open_element, ftn_file_manip_term
+"              operators
+"      Modified: 7/7/77 D. Levin change ftn_file_manip_term to ftn_get_area_ptr
+"      Modified:       7/7/77 by RAB to partially fix bug 1642.  This partially
+"              removes formline_ code put in to fix bug 1074.
+"      Modified:       16 August 1977 by RAB to complete removal of formline_ code in
+"              returns(char(*))
+"      Modified:       16 August 1977 by RAB to speed up long_profile operator
+"      Modified: 09/20/77 to extend trace interface to ALM and COBOL by P. Krupp.
+"      Modified: 19 December 1977 by DSL - implement "static" stack frame for fortran I/O.
+"              Refer to comments immediately preceding the label "fortran_read".
+"      Modified: 15 Feb 1978 by PCK to implement stop, return_main, set_main_flag and
+"              begin_return_main operators
+"      Modified: 21 March 1978 by DSL stack_frame.incl.alm changes. stack_frame.fio_ps_ptr
+"              changed to stack_frame.support_ptr.
+"      Modified: 15 June 1978 by PCK to implement size_check_uns_fx1 and size_check_uns_fx2
+"              operators
+"      Modified:       28 July 1978 by RAB to fix Fortran bug 169 in which amod failed if 2nd arg
+"              was negative
+"      Modified 781127 by PG to fix 1800 in which size_check_fx1 and size_check_uns_fx1
+"              changed the indicators
+"      Modified 790223 by PG to fix 1821 (many, many operators were using signed arithmetic
+"              on addresses in the upper when extending the stack!). Also removed
+"              a lot of unused labels and names.
+"      Modified 790608 by PG to add TCT tables.
+"      Modified 790705 by PG to fix 1846 (eaa,neg sequence used by many
+"              operators took faults on stacks = 128K.
+"      Modified 9 July 1979 by CRD to add new operator fortran_end.
+"      Modified 7 August 1979 by CRD to add new operator fort_dmod to fix
+"              bug 221 and to bring dmod into inline ALM code.
+"      Modified 791205 by PG to fix bug in TCT tables that caused code compiled by 25b
+"              to fail if trace was used, due to misplaced even pseudo-op.
+"      Modified 6 December 1979 by BSG for ix_rev_chars
+"      Modified 12 February 1980 by CRD to add to fort_math_names table.
+"      Modified 28 February 1980 by CRD to fix after/before for bit strings. (Bug 1915)
+"      Modified 28 February 1980 by CRD to change the way many operators restore pr0.
+"              Many operators did eppap operator_table, which doesn't work if trace
+"              is being used.  Since the entry sequences store the operator pointer,
+"              these instructions were changed to eppap sp|stack_frame.operator_ptr,*.
+"      Modified 6 March 1980 by CRD to add three new operators: shorten_stack_protect_ind,
+"              save_stack_quick, and restore_stack_quick.
+"      Modified 22 October 1980 by CRD to add new operators for new Fortran
+"              intrinsic functions.
+"      Modified 7 November 1980 by M. N. Davidoff to fix bug 2033 in which longbs_to_bs18
+"              always returned zero.
+"      Modified 7 November 1980 by M. N. Davidoff to fix bug 2030 in which longbs_to_fx2
+"              didn't work for bit strings longer than 71 bits.
+"      Modified 8 February 1980 by M. N. Davidoff to fix bug 2041 in which ix_rev_chars
+"              failed when length(arg2)=1.
+"      Modified 27 February 1981 by PCK to make the alm entry operators
+"              preserve the contents of the lisp linkage pointer (pr1)
+"              when trace is active
+"      Modified 28 July by PCK to fix bug 2068 in which the current stack
+"              gets trashed if an asynchronous fault such as an alarm
+"              signal or page fault occurs when the stack is being extended
+"              by any of the divide operators.
+"      Modified 31 August 1981 by C R Davis to fix trans_sign_fl to set the
+"              indicators properly, and to add the blank field to
+"              ftn_open_element.
+"      Modified 27 October 1981 by C R Davis to add ftn_inquire_element.
+"      Modified  1 April 1982   by T G Oke to add fortran INTRINSICs for external reference
+"      Modified 10 May 1982 by H Hoover to add 'mpy_overflow_check'.
+"      Modified 27 August 1982 by T Oke to add 'fort_cleanup' and
+"              'fort_return_mac'.
+"      Modified September 1982 by C. Hornig to have long_profile work with
+"              separate_static.
+"      Modified 21 September 1982 by T Oke to add 'fort_storage'.
+"      Modified  5 Novemeber 1982 by T Oke to add 'VLA_words_per_seg' to
+"              pl1_operators_ pointer referenced, and 'VLA_words_per_seg_'
+"              entry.
+"      Modified 14 January   1983 by T Oke to ensure indicator storage is
+"              is done in stack_frame.return_ptr+1 on all out-calls.
+"              References to PR6 changed to 'sp' for consistency.
+"              Internal operator calls to pl1_support routines also save
+"              and restore the indicators, using a new location
+"              'temp_indicators'.
+"      Modified 23 November 1983 by H. Hoover to support Hexadecimal
+"              Floating Point (HFP).
+"      Modified 22 June 1984 by M. Mabey to add the fortran bit-shifting
+"              functions to the fort_math_names and hfp_fort_math_names
+"              tables.
+"      Modified 14 February 1985 by M. Mabey to change the transfers to
+"              the double precision arc_sine and arc_cosine routines to
+"              reference the new routine 'double_arc_sine_'
+"      Modified 10 April 1985 by M. Mabey to change the transfers to the
+"              double precision tangent routine to reference the new
+"              routine 'double_tangent_'
+"         Modified: 15 January, 1987 by SH to correct the comments in routines
+"                   "call_ent_var_desc" and "call_ent_in_desc" to indicate
+"                   the offset of the argument list is in x1.
+"         Modified: 16 January,1987 by SH & RW to allow ceiling function work
+"                   with negative fixed bin scaled numbers.
+"         Modified: 24 June,1987 by SH to remove the 48 words extension instead
+"              of all stack extension upon return from the 'call_signal_'
+"              routine.
+"         Modified: 24 June, 1988 by SH to adjust the next_stackframe_ptr and
+"              perm_extension_ptr in the "ft_fast_call" routine.
+"      Modified: 15 January, 1989 by RG & SH to fix size_check_fx1, 
+"              size_check_fx2, size_check_uns_fx1, size_check_uns_fx2.
+"              Errors previously occurred on Maximum negative of fx1 and
+"              fx2 in magnitude comparison.
+       name    pl1_operators_
+
+       include stack_header
+
+"      We are attempting to set a standard for the storage and return of
+"      indicators for a program.  On call-out the operators will store the
+"      indicator register in the low 18-bits of stack_frame.return_ptr+1,
+"      the upper 18-bits are the return word offset, and are stored from
+"      X0 typically.  On return the operators will restore the indicators
+"      from this low 18-bit portion.
+
+       include stack_frame
+       include eis_bits
+       include iocbx
+       include plio2_fsb
+       include plio2_ps
+       include fortran_ps
+       include fortran_open_data
+       include fortran_inquire_data
+"
+       segdef  alloc
+       segdef  alm_call
+       segdef  alm_entry
+       segdef  alm_operators_begin
+       segdef  alm_operators_end
+       segdef  alm_push
+       segdef  alm_return
+       segdef  alm_return_no_pop
+       segdef  alm_trace_operators_begin
+       segdef  alm_trace_operators_end
+       segdef  begin_pl1_operators
+       segdef  call_signal_
+       segdef  end_pl1_operators
+       segdef  entry_operators
+       segdef  entry_operators_end
+       segdef  fort_math_names
+       segdef  hfp_fort_math_names
+       segdef  forward_call
+       segdef  get_our_lp
+       segdef  hfp_operator_table
+       segdef  operator_table
+       segdef  plio4
+       segdef  put_return
+       segdef  tct_byte_0
+       segdef  tct_byte_1
+       segdef  tct_byte_2
+       segdef  tct_byte_3
+       segdef  tct_octal_040
+       segdef  tct_octal_060
+       segdef  trace_alm_entry
+       segdef  trace_entry_operators
+       segdef  trace_entry_operators_end
+       segdef  trace_operator_table
+       segdef  trace_hfp_operator_table
+       segdef  var_call
+       segdef  VLA_words_per_seg_
+"
+"      Definitions of variables used by operators.  Since all
+"      of the operators execute using the stack frame of the
+"      pl/1 program for their temporary storage, locations 8-15 & 32-63
+"      of the pl/1 stack frame are reserved for operator use.
+"
+"      sp|6 has been reserved for probe.
+"
+       equ     display_ptr,32
+       equ     descriptor_ptr,34
+       equ     linkage_ptr,36
+       equ     text_base_ptr,38
+       equ     tbp,38
+       equ     temp_pt,40              string register
+       equ     ps_ptr,42
+       equ     page,44
+       equ     temp_indicators,45
+       equ     double_temp,46
+       equ     cpu,46
+       equ     remainder,46
+       equ     temp_size,48
+       equ     extend_size,49
+       equ     bit_lg1,50              string register
+       equ     char_lg1,51             string register
+       equ     t3,51
+       equ     bit_or_char,52          string register
+       equ     t1,52
+       equ     bit_op,53
+       equ     t5,53
+       equ     cat_lg1,54
+       equ     t2,54
+       equ     qmask,55
+       equ     arg_list,56
+       equ     save_regs,56
+       equ     save_x01,56
+       equ     label_var,56
+       equ     complex,56              complex AQ
+       equ     temp2,58
+       equ     lv,60
+       equ     num,60
+       equ     lg2,61
+       equ     temp,62
+       equ     t4,63
+       equ     count,63
+"
+"      following locations used in stack extension by divide subroutine
+"
+       equ     divide_extension_size,32
+       equ     qhat,0
+       equ     rhat,1
+       equ     carry,2
+       equ     carrya,3
+       equ     shift,4
+       equ     norm_shift,5
+       equ     div_temp,6
+       equ     dividend,8
+       equ     divisor,14
+       equ     quotient,18
+       equ     divide_lp,24
+"
+       bool    rpd_bits,001400 bits for RPD instruction (A,B)
+"
+       bool    blank,40
+"
+"      Definitions related to Hexadecimal Floating Point (HFP) mode:
+"
+       bool    HFP_mask,000010 mask for bit in IR that sets HFP mode
+       bool    M2.0H,003700    yields HFP -2.0 under 'du' modification
+       bool    M0.5H,001400    yields HFP -0.5 under 'du' modification
+       bool    P0.0H,400000    yields HFP +0.0 under 'du' modification
+       bool    P0.5H,000400    yields HFP +0.5 under 'du' modification
+       bool    P1.0H,002040    yields HFP +1.0 under 'du' modification
+       bool    P2.0H,002100    yields HFP +2.0 under 'du' modification
+"\f                             
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      MACROS USED IN THIS PROGRAM
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+
+"      Macro to load PR4 with ptr to linkage section of pl1_operators_.
+"      PR7 is set to the base of the stack.  The AQ is effectively clobbered.
+"      A subroutine of the same name also exists, when speed is not critical.
+"
+       macro   get_our_lp
+       epbpsb  sp|0            make sure sb is set up
+       epaq    *               get ptr to ourselves
+       lprplp  sb|stack_header.lot_ptr,*au get packed ptr to linkage from lot
+       &end
+"
+"      Macro to load AU with the complement of the stack frame offset.
+"
+       macro   get_stack_offset
+       eaa     sp|0            get offset of stack frame in au
+       era     mask_bit_one    form 2's complement of whole a-reg
+       adla    1,dl            w/o overflow
+       &end
+"
+"      The following macro (transfer_vector) is used to duplicate the transfer vector
+"      and the constants and code which preceed it for the trace programs. All labels
+"      in the macro should be preceeded by "&1" in order to eliminate duplicate labels.
+"
+"      Any operators which are to be different for the trace vector should have
+"      the target of the transfer preceeded by "&1".
+"
+
+       macro   transfer_vector
+"
+" Due to the presence of double-word constants (at bit_mask and mask_bit)
+" these instructions must presently begin on an even-word boundary.
+" Note that if an odd number  of words is added to the front of the
+" operator_table region, then the following even pseudo-op must be
+" changed to an odd pseudo-op. If you forget, an assembly error will
+" result (due to clever divide-by-zero, below).
+"
+       even
+"
+" The following section, from location 0 to label operator_table, is referenced
+" directly from PL/1 programs by means of offsets of the form ap|-n (ap pointing
+" at pl1_operators_$operator_table).  For this reason, the order of the
+" following instructions must not be changed.  Any new coding must be placed at
+" the FRONT of the segment.
+"
+" This table translates a bit number between 0 and 35 to a char number
+" between 0 and 3.
+"
+       even
+&1&2bitno_to_charno_table:
+       dup     9
+       dec     0
+       dupend
+       dup     9
+       dec     1
+       dupend
+       dup     9
+       dec     2
+       dupend
+       dup     9
+       dec     3
+       dupend
+"
+"      The following tables are for use with the TCT instruction.
+"      Any single, given, character can be searched for using these
+"      tables.
+"
+       dup     115
+       dec     -1
+       dupend
+"
+&1&2tct_octal_060:
+       dup     4
+       dec     -1
+       dupend
+"
+&1&2tct_octal_040:
+       dup     8
+       dec     -1
+       dupend
+&1&2tct_byte_0:
+       vfd     9/0,9/-1,9/-1,9/-1
+       dup     127
+       dec     -1
+       dupend
+"
+&1&2tct_byte_1:
+       vfd     9/-1,9/0,9/-1,9/-1
+       dup     127
+       dec     -1
+       dupend
+"
+&1&2tct_byte_2:
+       vfd     9/-1,9/-1,9/0,9/-1
+       dup     127
+       dec     -1
+       dupend
+"
+&1&2tct_byte_3:
+       vfd     9/-1,9/-1,9/-1,9/0
+       dup     127
+       dec     -1
+       dupend
+"
+"      The number of words per segment of a FORTRAN Very Large Array.
+"
+&1&2VLA_words_per_seg_:
+       vfd     36/256*1024
+"
+"      table of csl's for use by bool builtin function
+"
+&1&2csl_vector:
+       csl     (pr,rl),(pr,rl),bool(0)
+       csl     (pr,rl),(pr,rl),bool(1)
+       csl     (pr,rl),(pr,rl),bool(2)
+       csl     (pr,rl),(pr,rl),bool(3)
+       csl     (pr,rl),(pr,rl),bool(4)
+       csl     (pr,rl),(pr,rl),bool(5)
+       csl     (pr,rl),(pr,rl),bool(6)
+       csl     (pr,rl),(pr,rl),bool(7)
+       csl     (pr,rl),(pr,rl),bool(10)
+       csl     (pr,rl),(pr,rl),bool(11)
+       csl     (pr,rl),(pr,rl),bool(12)
+       csl     (pr,rl),(pr,rl),bool(13)
+       csl     (pr,rl),(pr,rl),bool(14)
+       csl     (pr,rl),(pr,rl),bool(15)
+       csl     (pr,rl),(pr,rl),bool(16)
+       csl     (pr,rl),(pr,rl),bool(17)
+"
+"      shift table for character offset
+"
+&1&2co_to_bo:  dec     0,9b17,18b17,27b17
+"
+"      shift table for half word offset
+"
+&1&2ho_to_bo:  dec     0,18b17
+"
+"      store table from a, 9 bit bytes, character offset
+"                              OFFSET  SIZE
+"
+&1&2store_a9_co:
+       stba    bp|0,40         0       1
+       stba    bp|0,20         1
+       stba    bp|0,10         2
+       stba    bp|0,04         3
+       stba    bp|0,60         0       2
+       stba    bp|0,30         1
+       stba    bp|0,14         2
+       stba    bp|0,04         3
+       stba    bp|0,70         0       3
+       stba    bp|0,34         1
+       stba    bp|0,14         2
+       stba    bp|0,04         3
+       sta     bp|0            0       4
+       stba    bp|0,34         1
+       stba    bp|0,14         2
+       stba    bp|0,04         3
+       sta     bp|0            0       5
+       stba    bp|0,34         1
+       stba    bp|0,14         2
+       stba    bp|0,04         3
+"
+"      store table from q, 9 bit bytes, character offset
+"                              OFFSET  SIZE
+"
+&1&2store_q9_co:
+       nop     0,dl            0       2
+       nop     0,dl            1
+       nop     0,dl            2
+       stbq    bp|1,40         3
+       nop     0,dl            0       3
+       nop     0,dl            1
+       stbq    bp|1,40         2
+       stbq    bp|1,60         3
+       nop     0,dl            0       4
+       stbq    bp|1,40         1
+       stbq    bp|1,60         2
+       stbq    bp|1,70         3
+       stbq    bp|1,40         0       5
+       stbq    bp|1,60         1
+       stbq    bp|1,70         2
+       stq     bp|1            3
+"
+"      store table from a, 9 bit bytes, half word offset
+"                              OFFSET  SIZE
+"
+&1&2store_a9_ho:
+       stba    bp|0,40         0       1
+       stba    bp|0,10         1
+       stba    bp|0,60         0       2
+       stba    bp|0,14         1
+       stba    bp|0,70         0       3
+       stba    bp|0,14         1
+       sta     bp|0            0       4
+       stba    bp|0,14         1
+       sta     bp|0            0       5
+       stba    bp|0,14         1
+       sta     bp|0            0       6
+       stba    bp|0,14         1
+"
+"      store table from q, 9 bit bytes, half word offset
+"                              OFFSET  SIZE
+"
+&1&2store_q9_ho:
+       nop     0,dl            0       2
+       nop     0,dl            1
+       nop     0,dl            0       3
+       stbq    bp|1,40         1
+       nop     0,dl            0       4
+       stbq    bp|1,60         1
+       stbq    bp|1,40         0       5
+       stbq    bp|1,70         1
+       stbq    bp|1,60         0       6
+       stq     bp|1            1
+"
+"      store table from a, 6 bit bytes, half word offset
+"                              OFFSET  SIZE
+"
+&1&2store_a6_ho:
+       stca    bp|0,40         0       1
+       stca    bp|0,04         1
+       stca    bp|0,60         0       2
+       stca    bp|0,06         1
+       stca    bp|0,70         0       3
+       stca    bp|0,07         1
+       stca    bp|0,74         0       4
+       stca    bp|0,07         1
+       stca    bp|0,76         0       5
+       stca    bp|0,07         1
+       sta     bp|0            0       6
+       stca    bp|0,07         1
+       sta     bp|0            0       7
+       stca    bp|0,07         1
+       sta     bp|0            0       8
+       stca    bp|0,07         1
+       sta     bp|0            0       9
+       stca    bp|0,07         1
+"
+"      store table from q, 6 bit bytes, half word offset
+"                              OFFSET  SIZE
+"
+&1&2store_q6_ho:
+       nop     0,dl            0       2
+       nop     0,dl            1
+       nop     0,dl            0       3
+       nop     0,dl            1
+       nop     0,dl            0       4
+       stcq    bp|1,40         1
+       nop     0,dl            0       5
+       stcq    bp|1,60         1
+       nop     0,dl            0       6
+       stcq    bp|1,70         1
+       stcq    bp|1,40         0       7
+       stcq    bp|1,74         1
+       stcq    bp|1,60         0       8
+       stcq    bp|1,76         1
+       stcq    bp|1,70         0       9
+       stq     bp|1            1
+"
+" THE FOLLOWING SECTION IS DIRECTLY REFERENCED FROM PL/1 PROGRAMS BY MEANS OF
+" ap|offset.  FOR THIS REASON, THE ORDER OF THE FOLLOWING INSTRUCTIONS MUST
+" NOT BE CHANGED.
+"
+&1&2operator_table:
+&1&2bit_mask:
+       vfd     0/-1,72/0
+       vfd     1/-1,71/0
+       vfd     2/-1,70/0
+       vfd     3/-1,69/0
+       vfd     4/-1,68/0
+       vfd     5/-1,67/0
+       vfd     6/-1,66/0
+       vfd     7/-1,65/0
+       vfd     8/-1,64/0
+       vfd     9/-1,63/0
+       vfd     10/-1,62/0
+       vfd     11/-1,61/0
+       vfd     12/-1,60/0
+       vfd     13/-1,59/0
+       vfd     14/-1,58/0
+       vfd     15/-1,57/0
+       vfd     16/-1,56/0
+       vfd     17/-1,55/0
+       vfd     18/-1,54/0
+       vfd     19/-1,53/0
+       vfd     20/-1,52/0
+       vfd     21/-1,51/0
+       vfd     22/-1,50/0
+       vfd     23/-1,49/0
+       vfd     24/-1,48/0
+       vfd     25/-1,47/0
+       vfd     26/-1,46/0
+       vfd     27/-1,45/0
+       vfd     28/-1,44/0
+       vfd     29/-1,43/0
+       vfd     30/-1,42/0
+       vfd     31/-1,41/0
+       vfd     32/-1,40/0
+       vfd     33/-1,39/0
+       vfd     34/-1,38/0
+       vfd     35/-1,37/0
+&1&2ones:      vfd     36/-1,36/0
+       vfd     36/-1,1/-1,35/0
+       vfd     36/-1,2/-1,34/0
+       vfd     36/-1,3/-1,33/0
+       vfd     36/-1,4/-1,32/0
+       vfd     36/-1,5/-1,31/0
+       vfd     36/-1,6/-1,30/0
+       vfd     36/-1,7/-1,29/0
+       vfd     36/-1,8/-1,28/0
+       vfd     36/-1,9/-1,27/0
+       vfd     36/-1,10/-1,26/0
+       vfd     36/-1,11/-1,25/0
+       vfd     36/-1,12/-1,24/0
+       vfd     36/-1,13/-1,23/0
+       vfd     36/-1,14/-1,22/0
+       vfd     36/-1,15/-1,21/0
+       vfd     36/-1,16/-1,20/0
+       vfd     36/-1,17/-1,19/0
+       vfd     36/-1,18/-1,18/0
+       vfd     36/-1,19/-1,17/0
+       vfd     36/-1,20/-1,16/0
+       vfd     36/-1,21/-1,15/0
+       vfd     36/-1,22/-1,14/0
+       vfd     36/-1,23/-1,13/0
+       vfd     36/-1,24/-1,12/0
+       vfd     36/-1,25/-1,11/0
+       vfd     36/-1,26/-1,10/0
+       vfd     36/-1,27/-1,9/0
+       vfd     36/-1,28/-1,8/0
+       vfd     36/-1,29/-1,7/0
+       vfd     36/-1,30/-1,6/0
+       vfd     36/-1,31/-1,5/0
+       vfd     36/-1,32/-1,4/0
+       vfd     36/-1,33/-1,3/0
+       vfd     36/-1,34/-1,2/0
+       vfd     36/-1,35/-1,1/0
+"
+&1&2mask_bit:
+       vfd     0/0,36/-1,36/-1
+       vfd     1/0,35/-1,36/-1
+       vfd     2/0,34/-1,36/-1
+       vfd     3/0,33/-1,36/-1
+       vfd     4/0,32/-1,36/-1
+       vfd     5/0,31/-1,36/-1
+       vfd     6/0,30/-1,36/-1
+       vfd     7/0,29/-1,36/-1
+       vfd     8/0,28/-1,36/-1
+       vfd     9/0,27/-1,36/-1
+       vfd     10/0,26/-1,36/-1
+       vfd     11/0,25/-1,36/-1
+       vfd     12/0,24/-1,36/-1
+       vfd     13/0,23/-1,36/-1
+       vfd     14/0,22/-1,36/-1
+       vfd     15/0,21/-1,36/-1
+       vfd     16/0,20/-1,36/-1
+       vfd     17/0,19/-1,36/-1
+       vfd     18/0,18/-1,36/-1
+       vfd     19/0,17/-1,36/-1
+       vfd     20/0,16/-1,36/-1
+       vfd     21/0,15/-1,36/-1
+       vfd     22/0,14/-1,36/-1
+       vfd     23/0,13/-1,36/-1
+       vfd     24/0,12/-1,36/-1
+       vfd     25/0,11/-1,36/-1
+       vfd     26/0,10/-1,36/-1
+       vfd     27/0,9/-1,36/-1
+       vfd     28/0,8/-1,36/-1
+       vfd     29/0,7/-1,36/-1
+       vfd     30/0,6/-1,36/-1
+       vfd     31/0,5/-1,36/-1
+       vfd     32/0,4/-1,36/-1
+       vfd     33/0,3/-1,36/-1
+       vfd     34/0,2/-1,36/-1
+       vfd     35/0,1/-1,36/-1
+       vfd     36/0,36/-1
+&1&2max_single_value:
+       vfd     37/0,35/-1
+       vfd     38/0,34/-1
+       vfd     39/0,33/-1
+       vfd     40/0,32/-1
+       vfd     41/0,31/-1
+       vfd     42/0,30/-1
+       vfd     43/0,29/-1
+       vfd     44/0,28/-1
+       vfd     45/0,27/-1
+       vfd     46/0,26/-1
+       vfd     47/0,25/-1
+       vfd     48/0,24/-1
+       vfd     49/0,23/-1
+       vfd     50/0,22/-1
+       vfd     51/0,21/-1
+       vfd     52/0,20/-1
+       vfd     53/0,19/-1
+       vfd     54/0,18/-1
+       vfd     55/0,17/-1
+       vfd     56/0,16/-1
+       vfd     57/0,15/-1
+       vfd     58/0,14/-1
+       vfd     59/0,13/-1
+       vfd     60/0,12/-1
+       vfd     61/0,11/-1
+       vfd     62/0,10/-1
+       vfd     63/0,9/-1
+       vfd     64/0,8/-1
+       vfd     65/0,7/-1
+       vfd     66/0,6/-1
+       vfd     67/0,5/-1
+       vfd     68/0,4/-1
+       vfd     69/0,3/-1
+       vfd     70/0,2/-1
+       vfd     71/0,1/-1
+"
+&1&2blanks:    oct     040040040040,040040040040
+       oct     000040040040,040040040040
+       oct     000000040040,040040040040
+       oct     000000000040,040040040040
+       oct     000000000000,040040040040
+       oct     000000000000,000040040040
+       oct     000000000000,000000040040
+       oct     000000000000,000000000040
+"
+&1&2ptr_mask:  oct     077777000077,777777077077 mask for use in ptr comparisions
+"
+"      operator to convert single fixed to double fixed
+"
+       even
+&1&2fx1_to_fx2:
+       llr     36
+       lrs     36
+"
+"      operators to convert fixed to float
+"
+       odd
+&1&2fx1_to_fl2:
+       xed     &1&2fx1_to_fx2
+"
+       even
+&1&2fx2_to_fl2:
+       ife     &2,hfp_
+       lde     =18b25,du               EAQ = unnormalized 2*float(number)
+       fad     P0.0H,du                EAQ = 2*float(number)
+       fmp     P0.5H,du                EAQ = float(number)
+       tra     sp|tbp,*x0      return
+       ifend
+
+       ine     &2,hfp_
+       lde     =71b25,du
+       fad     =0.,du
+       tra     sp|tbp,*0
+       ifend
+"
+"      operator to reset next stack pointer
+"
+       even
+&1&2reset_stack:
+       ldx0    sp|5
+       stx0    sp|stack_frame.next_sp+1
+"
+"      operators to convert indicators into relations
+"
+&1&2r_l_a:     tmi     true
+       lda     0,dl
+       tra     sp|tbp,*0
+"
+&1&2r_g_s:     tze     2,ic
+       trc     true
+       lda     0,dl
+       tra     sp|tbp,*0
+"
+&1&2r_g_a:     tze     2,ic
+       tpl     true
+       lda     0,dl
+       tra     sp|tbp,*0
+"
+&1&2r_l_s:     tnc     true
+       lda     0,dl
+       tra     sp|tbp,*0
+"
+&1&2r_e_as:    tze     true
+       lda     0,dl
+       tra     sp|tbp,*0
+"
+&1&2r_ne_as:   tnz     true
+       lda     0,dl
+       tra     sp|tbp,*0
+"
+&1&2r_le_a:    tmi     true
+       tze     true
+       lda     0,dl
+       tra     sp|tbp,*0
+"
+&1&2r_ge_s:    trc     true
+       lda     0,dl
+       tra     sp|tbp,*0
+"
+&1&2r_ge_a:    tpl     true
+       lda     0,dl
+       tra     sp|tbp,*0
+"
+&1&2r_le_s:    tnc     true
+       tze     true
+       lda     0,dl
+       tra     sp|tbp,*0
+"
+&1&2true:      lda     =o400000,du
+       tra     sp|tbp,*0
+"
+"      operator to set stack ptr to that of block N static
+"      levels above the current block.  Entered with N in q.
+"      (should not be called with N = 0, but will work anyway.)
+"
+&1&2set_stack:
+       tsx1    display_chase   get ptr to proper frame
+       eppsp   bp|0            into sp
+       tra     set_stack_extend        do three more instructions (added later
+"                              and since compiled code knows offsets in this
+"                              area, couldn't add the code inline)
+"
+"      tables to convert to bit offset ready to be ORed into pointer
+"
+&1&2mod2_tab:  dec     0,18b26
+"
+&1&2mod4_tab:  dec     0,9b26,18b26,27b26
+"
+"      transfer vector for operators not referenced directly
+"      by the pl/1 program.  new operators may be added at the
+"      end of the list only.
+"
+&1&2op_vector:
+       tra     alloc_char_temp 0
+       tra     alloc_bit_temp  1
+       tra     alloc_temp      2
+       tra     realloc_char_temp       3
+       tra     realloc_bit_temp        4
+       tra     save_string     5       obsolete
+       tra     pk_to_unpk      6
+       tra     unpk_to_pk      7
+       tra     move_chars      8       obsolete
+       tra     move_chars_aligned      9       obsolete
+       tra     move_bits               10      obsolete
+       tra     move_bits_aligned       11      obsolete
+       tra     chars_move      12      obsolete
+       tra     chars_move_aligned      13      obsolete
+       tra     bits_move               14      obsolete
+       tra     bits_move_aligned       15      obsolete
+       tra     move_not_bits   16      obsolete
+       tra     move_not_bits_aligned 17        obsolete
+       tra     ext_and_1               18
+       tra     ext_and_2               19
+       tra     comp_bits               20
+       tra     cpbs3           21      obsolete
+       tra     cpbs3_aligned   22      obsolete
+       tra     cpbs4           23      obsolete
+       tra     cpcs_ext1               24
+       tra     cpcs_ext2               25
+       tra     cpbs_ext1               26
+       tra     cpbs_ext2               27
+       tra     store_string    28
+       tra     cat_realloc_chars       29
+       tra     cat_realloc_bits        30
+       tra     cp_chars                31      obsolete
+       tra     cp_chars_aligned        32      obsolete
+       tra     cp_bits         33      obsolete
+       tra     cp_bits_aligned 34      obsolete
+       tra     enter_begin_block       35
+       tra     leave_begin_block       36
+       tra     call_ent_var_desc       37
+       tra     call_ent_var    38
+       tra     call_ext_in_desc        39
+       tra     call_ext_in     40
+       tra     call_ext_out_desc       41
+       tra     call_ext_out    42
+       tra     call_int_this_desc      43
+       tra     call_int_this   44
+       tra     call_int_other_desc     45
+       tra     call_int_other  46
+       tra     begin_return_mac        47
+       tra     return_mac      48
+       tra     cat_move_chars  49      obsolete
+       tra     cat_move_chars_aligned 50       obsolete
+       tra     cat_move_bits   51      obsolete
+       tra     cat_move_bits_aligned 52        obsolete
+       tra     cat_chars               53      obsolete
+       tra     cat_chars_aligned       54      obsolete
+       tra     cat_bits                55      obsolete
+       tra     cat_bits_aligned        56      obsolete
+       tra     set_chars               57      obsolete
+       tra     set_chars_aligned       58      obsolete
+       tra     set_bits                59      obsolete
+       tra     set_bits_aligned        60      obsolete
+       tra     and_bits                61      obsolete
+       tra     and_bits_aligned        62      obsolete
+       tra     or_bits         63      obsolete
+       tra     or_bits_aligned 64      obsolete
+       tra     move_label_var  65
+       tra     make_label_var  66
+       tra     &2fl2_to_fx1    67
+       tra     &2fl2_to_fx2    68
+       tra     longbs_to_fx2   69
+       tra     tra_ext_1               70
+       tra     tra_ext_2               71
+       tra     alloc_auto_adj  72
+       tra     longbs_to_bs18  73
+       tra     stac_mac                74
+       tra     sign_mac                75
+       tra     bound_ck_signal 76
+       tra     trans_sign_fx1  77
+       tra     trans_sign_fl   78
+       tra     copy_words      79      obsolete
+       tra     mpfx2           80
+       tra     mpfx3           81
+       tra     copy_const      82      obsolete
+       tra     copy_const_vt   83      obsolete
+       tra     sr_check                84      obsolete
+       tra     chars_move_vt   85      obsolete
+       tra     chars_move_vta  86      obsolete
+       tra     bits_move_vt    87      obsolete
+       tra     bits_move_vta   88      obsolete
+       tra     &2mdfl1         89
+       tra     &2mdfl2         90
+       tra     mdfx1           91
+       tra     mdfx2           92
+       tra     mdfx3           93
+       tra     mdfx4           94
+       tra     copy_double     95      obsolete
+       tra     string_store    96      obsolete
+       tra     get_chars               97      obsolete
+       tra     get_bits                98      obsolete
+       tra     pad_chars               99
+       tra     pad_bits                100
+       tra     signal_op               101
+       tra     enable_op               102
+       tra     index_chars     103     obsolete
+       tra     index_chars_aligned     104     obsolete
+       tra     index_bits      105     obsolete
+       tra     index_bits_aligned      106     obsolete
+       tra     exor_bits               107     obsolete
+       tra     exor_bits_aligned       108     obsolete
+       tra     set_bits_co     109     obsolete
+       tra     set_bits_ho     110     obsolete
+       tra     set_chars_co    111     obsolete
+       tra     set_chars_ho    112     obsolete
+       tra     string_store_co 113     obsolete
+       tra     string_store_ho 114     obsolete
+       tra     get_chars_co    115     obsolete
+       tra     get_chars_ho    116     obsolete
+       tra     get_bits_co     117     obsolete
+       tra     get_bits_ho     118     obsolete
+       tra     and_bits_co     119     obsolete
+       tra     and_bits_ho     120     obsolete
+       tra     or_bits_co      121     obsolete
+       tra     or_bits_ho      122     obsolete
+       tra     exor_bits_co    123     obsolete
+       tra     exor_bits_ho    124     obsolete
+       tra     cat_move_bits_co        125     obsolete
+       tra     cat_move_bits_ho        126     obsolete
+       tra     move_not_bits_co        127     obsolete
+       tra     move_not_bits_ho        128     obsolete
+       tra     move_bits_co    129     obsolete
+       tra     move_bits_ho    130     obsolete
+       tra     move_chars_co   131     obsolete
+       tra     move_chars_ho   132     obsolete
+       tra     cat_move_chars_co       133     obsolete
+       tra     cat_move_chars_ho       134     obsolete
+       tra     cat_chars_co    135     obsolete
+       tra     cat_chars_ho    136     obsolete
+       tra     cat_bits_co     137     obsolete
+       tra     cat_bits_ho     138     obsolete
+       tra     io_signal               139
+       tra     index_cs_1      140     obsolete
+       tra     index_cs_1_aligned      141     obsolete
+       tra     &2fort_mdfl1    142
+       tra     rfb1_to_cflb1   143
+       tra     &2rfb2_to_cflb1 144
+       tra     mpcfl1_1                145
+       tra     mpcfl1_2                146
+       tra     dvcfl1_1                147
+       tra     dvcfl1_2                148
+       tra     chars_move_vt_co        149     obsolete
+       tra     chars_move_vt_ho        150     obsolete
+       tra     chars_move_co   151     obsolete
+       tra     chars_move_ho   152     obsolete
+       tra     bits_move_vt_co 153     obsolete
+       tra     bits_move_vt_ho 154     obsolete
+       tra     bits_move_co    155     obsolete
+       tra     bits_move_ho    156     obsolete
+       tra     cp_chars_co     157     obsolete
+       tra     cp_chars_ho     158     obsolete
+       tra     cp_bits_co      159     obsolete
+       tra     cp_bits_ho      160     obsolete
+       tra     cpbs3_co                161     obsolete
+       tra     cpbs3_ho                162     obsolete
+       tra     shorten_stack   163
+       tra     zero_bits               164     obsolete
+       tra     zero_bits_aligned       165     obsolete
+       tra     zero_bits_co    166     obsolete
+       tra     zero_bits_ho    167     obsolete
+       tra     blank_chars     168     obsolete
+       tra     blank_chars_aligned     169     obsolete
+       tra     blank_chars_co  170     obsolete
+       tra     blank_chars_ho  171     obsolete
+       tra     index_chars_co  172     obsolete
+       tra     index_chars_ho  173     obsolete
+       tra     index_bits_co   174     obsolete
+       tra     index_bits_ho   175     obsolete
+       tra     index_cs_1_co   176     obsolete
+       tra     index_cs_1_ho   177     obsolete
+       tra     index_bs_1      178     obsolete
+       tra     index_bs_1_aligned      179     obsolete
+       tra     index_bs_1_co   180     obsolete
+       tra     index_bs_1_ho   181     obsolete
+       arg     shift_bo                182     obsolete
+       tra     return_words    183
+       tra     return_bits     184     obsolete
+       tra     return_bits_co  185     obsolete
+       tra     return_bits_ho  186     obsolete
+       tra     return_bits_al  187     obsolete
+&1&2entry_operators:
+       tra     &1ext_entry             188
+       tra     &1ext_entry_desc        189
+       tra     int_entry               190
+       tra     int_entry_desc  191
+       tra     val_entry               192
+       tra     val_entry_desc  193
+       tra     get_chars_aligned       194     obsolete
+       tra     get_bits_aligned        195     obsolete
+       tra     fetch_chars     196
+       tra     fetch_bits      197
+       tra     get_terminate   198
+       tra     <put_format_>|[put_terminate]   199
+       tra     put_data_aligned        200     obsolete
+       tra     get_list_aligned        201     obsolete
+       tra     get_edit_aligned        202     obsolete
+       tra     put_list_aligned        203     obsolete
+       tra     put_edit_aligned        204     obsolete
+       tra     <put_format_>|[stream_prep]     205
+       tra     <record_io_>|[record_io]                206
+       tra     open_file               207
+       tra     close_file      208
+       tra     put_data                209     obsolete
+       tra     put_data_co     210     obsolete
+       tra     put_data_ho     211     obsolete
+       tra     get_list                212     obsolete
+       tra     get_list_co     213     obsolete
+       tra     get_list_ho     214     obsolete
+       tra     get_edit                215     obsolete
+       tra     get_edit_co     216     obsolete
+       tra     get_edit_ho     217     obsolete
+       tra     put_list                218     obsolete
+       tra     put_list_co     219     obsolete
+       tra     put_list_ho     220     obsolete
+       tra     put_edit                221     obsolete
+       tra     put_edit_co     222     obsolete
+       tra     put_edit_ho     223     obsolete
+       tra     suffix_cs               224     obsolete
+       tra     suffix_bs               225     obsolete
+       tra     &2fl2_to_fxscaled       226
+       tra     trunc_fx1               227
+       tra     trunc_fx2               228
+       tra     ceil_fx1                229
+       tra     ceil_fx2                230
+       tra     &2ceil_fl               231
+       tra     floor_fx1               232
+       tra     floor_fx2               233
+       tra     &2floor_fl      234
+       tra     &2trunc_fl      235
+       tra     round_fx1               236
+       tra     round_fx2               237
+       tra     repeat          238
+       tra     make_bit_table  239     obsolete
+       tra     make_bit_table_al       240     obsolete
+       tra     make_bit_table_co       241     obsolete
+       tra     make_bit_table_ho       242     obsolete
+       tra     verify          243     obsolete
+       tra     verify_al               244     obsolete
+       tra     verify_co               245     obsolete
+       tra     verify_ho               246     obsolete
+       tra     const_verify    247     obsolete
+       tra     const_verify_al 248     obsolete
+       tra     const_verify_co 249     obsolete
+       tra     const_verify_ho 250     obsolete
+       tra     reverse_cs      251
+       tra     reverse_bs      252
+       tra     form_bit_table  253     obsolete
+       tra     form_bit_table_co       254     obsolete
+       tra     form_bit_table_ho       255     obsolete
+       tra     form_bit_table_al       256     obsolete
+       tra     chars_move_ck   257     obsolete
+       tra     chars_move_ck_co        258     obsolete
+       tra     chars_move_ck_ho        259     obsolete
+       tra     chars_move_ck_al        260     obsolete
+       tra     bits_move_ck    261     obsolete
+       tra     bits_move_ck_co 262     obsolete
+       tra     bits_move_ck_ho 263     obsolete
+       tra     bits_move_ck_al 264     obsolete
+       tra     size_check_fx1  265
+       tra     size_check_fx2  266
+       tra     signal_stringsize       267
+       tra     suffix_cs_ck    268     obsolete
+       tra     suffix_bs_ck    269     obsolete
+       tra     pointer_hard    270
+       tra     alm_call                271     special for alm
+       tra     alm_push                272     special for alm
+       tra     alm_return      273     special for alm
+       tra     alm_return_no_pop       274     special for alm
+       tra     &1alm_entry             275     special for alm
+       tra     packed_to_bp    276     obsolete
+       tra     return_chars    277     obsolete
+       tra     return_chars_co 278     obsolete
+       tra     return_chars_ho 279     obsolete
+       tra     return_chars_aligned 280        obsolete
+       tra     rpd_odd_lp_bp   281     obsolete
+       tra     rpd_odd_bp_lp   282     obsolete
+       tra     rpd_even_lp_bp  283     obsolete
+       tra     rpd_even_bp_lp  284     obsolete
+       tra     offset_easy     285
+       tra     offset_easy_pk  286
+       tra     offset_hard     287
+       tra     offset_hard_pk  288
+       tra     pointer_hard_pk 289
+       tra     pointer_easy    290
+       tra     pointer_easy_pk 291
+       tra     round_fl                292
+       tra     enable_file     293
+       tra     revert_file     294
+       tra     alloc_block     295
+       tra     free_block      296
+       tra     push_ctl_data   297
+       tra     push_ctl_desc   298
+       tra     pop_ctl_data    299
+       tra     pop_ctl_desc    300
+       tra     allocation      301
+       tra     set_chars_eis   302
+       tra     set_bits_eis    303
+       tra     index_chars_eis 304
+       tra     index_bits_eis  305
+       tra     index_cs_1_eis  306
+       tra     index_bs_1_eis  307
+       tra     return_chars_eis        308
+       tra     return_bits_eis 309
+       tra     put_data_eis    310
+       tra     <put_format_>|[put_edit_eis]    311
+       tra     put_list_eis    312
+       tra     <put_format_>|[get_edit_eis]    313
+       tra     get_list_eis    314
+       tra     verify_eis      315
+       tra     search_eis      316
+       tra     fortran_read    317
+       tra     fortran_write   318
+       tra     fortran_manip   319
+       tra     fortran_scalar_xmit     320
+       tra     fortran_array_xmit      321
+       tra     fortran_terminate       322
+       tra     <any_to_any_>|[real_to_real_round_]     323
+       tra     <any_to_any_>|[real_to_real_truncate_]  324
+       tra     <any_to_any_>|[any_to_any_round_]       325
+       tra     <any_to_any_>|[any_to_any_truncate_]    326
+       tra     unpack_picture  327
+       tra     pack_picture    328
+       tra     divide_fx1      329
+       tra     divide_fx2      330
+       tra     divide_fx3      331
+       tra     divide_fx4      332
+       tra     scaled_mod_fx1  333
+       tra     scaled_mod_fx2  334
+       tra     scaled_mod_fx3  335
+       tra     scaled_mod_fx4  336
+       tra     translate_2     337
+       tra     translate_3     338
+       tra     <square_root_>|[&2square_root_]         339
+       tra     <sine_>|[&2sine_radians_]               340
+       tra     <sine_>|[&2sine_degrees_]               341
+       tra     <sine_>|[&2cosine_radians_]             342
+       tra     <sine_>|[&2cosine_degrees_]             343
+       tra     <tangent_>|[&2tangent_radians_] 344
+       tra     <tangent_>|[&2tangent_degrees_] 345
+       tra     <arc_sine_>|[&2arc_sine_radians_]       346
+       tra     <arc_sine_>|[&2arc_sine_degrees_]       347
+       tra     <arc_sine_>|[&2arc_cosine_radians_]     348
+       tra     <arc_sine_>|[&2arc_cosine_degrees_]     349
+       tra     <arc_tangent_>|[&2arc_tangent_radians_] 350
+       tra     <arc_tangent_>|[&2arc_tangent_degrees_] 351
+       tra     <logarithm_>|[&2log_base_2_]            352
+       tra     <logarithm_>|[&2log_base_e_]            353
+       tra     <logarithm_>|[&2log_base_10_]           354
+       tra     <exponential_>|[&2exponential_]         355
+       tra     <double_square_root_>|[&2double_square_root_]   356
+       tra     <double_sine_>|[&2double_sine_radians_] 357
+       tra     <double_sine_>|[&2double_sine_degrees_] 358
+       tra     <double_sine_>|[&2double_cosine_radians_]       359
+       tra     <double_sine_>|[&2double_cosine_degrees_]       360
+       tra     <double_tangent_>|[&2double_tangent_radians_]   361
+       tra     <double_tangent_>|[&2double_tangent_degrees_]   362
+       tra     <double_arc_sine_>|[&2double_arc_sine_radians_] 363
+       tra     <double_arc_sine_>|[&2double_arc_sine_degrees_] 364
+       tra     <double_arc_sine_>|[&2double_arc_cosine_radians_]       365
+       tra     <double_arc_sine_>|[&2double_arc_cosine_degrees_]       366
+       tra     <double_arc_tangent_>|[&2double_arc_tan_radians_]       367
+       tra     <double_arc_tangent_>|[&2double_arc_tan_degrees_]       368
+       tra     <double_logarithm_>|[&2double_log_base_2_]      369
+       tra     <double_logarithm_>|[&2double_log_base_e_]      370
+       tra     <double_logarithm_>|[&2double_log_base_10_]     371
+       tra     <double_exponential_>|[&2double_exponential_]   372
+       tra     <arc_tangent_>|[&2arc_tangent_radians_2_]       373
+       tra     <arc_tangent_>|[&2arc_tangent_degrees_2_]       374
+       tra     <double_arc_tangent_>|[&2double_arc_tan_radians_2_]     375
+       tra     <double_arc_tangent_>|[&2double_arc_tan_degrees_2_]     376
+       tra     <power_>|[&2integer_power_single_]      377
+       tra     <power_>|[&2integer_power_double_]      378
+       tra     <power_>|[&2double_power_single_]       379
+       tra     <power_>|[&2double_power_double_]       380
+       tra     <power_integer_>|[&2double_power_integer_]      381
+       tra     <power_>|[&2single_power_single_]       382
+       tra     <power_integer_>|[&2single_power_integer_]      383
+       tra     <integer_power_integer_>|[integer_power_integer_]       384
+       tra     signal_size     385
+       tra     &1ss_ext_entry  386
+       tra     &1ss_ext_entry_desc     387
+       tra     ss_int_entry    388
+       tra     ss_int_entry_desc       389
+       tra     ss_val_entry    390
+       tra     ss_val_entry_desc       391
+       tra     <cplx_dec_ops_>|[mpcdec]        392
+       tra     <cplx_dec_ops_>|[dvcdec]        393
+       tra     <cplx_dec_ops_>|[dvrcdec]       394
+       tra     <dec_ops_>|[ceil]       395
+       tra     <dec_ops_>|[floor]      396
+       tra     <dec_ops_>|[sign]       397
+       tra     <cplx_dec_ops_>|[cabs]  398
+       tra     <dec_ops_>|[truncate]   399
+       tra     <dec_ops_>|[mod]                400
+       tra     set_support     401
+       tra     div_4_cplx_ops  402
+       tra     fetch_chars_eis 403
+       tra     signal_stringrange      404
+       tra     ss_enter_begin_block    405
+       tra     <put_field_>|[put_field]                406      
+       tra     <put_field_>|[put_field_chk]            407
+       tra     <put_field_>|[put_control]      408
+       tra     <alloc_>|[op_alloc_]    409
+       tra     alloc_storage           410
+       tra     <alloc_>|[op_freen_]    411
+       tra     <alloc_>|[op_empty_]    412
+       tra     <fort_math_ops_>|[&2cabs]               413     fortran only
+       tra     <fort_math_ops_>|[&2ccos]               414     fortran only
+       tra     <fort_math_ops_>|[&2cexp]               415     fortran only
+       tra     <fort_math_ops_>|[&2clog]               416     fortran only
+       tra     <fort_math_ops_>|[&2csin]               417     fortran only
+       tra     <fort_math_ops_>|[&2csqrt]              418     fortran only
+       tra     <fort_math_ops_>|[&2tanh]               419     fortran only
+       tra     <fort_math_ops_>|[&2dmod]               420     fortran only (obsolete)
+       tra     <fort_math_ops_>|[&2cmpx_p_cmpx]        421     fortran only
+       tra     &2get_math_entry        422     fortran only
+       tra     fortran_pause   423     fortran only
+       tra     fortran_stop    424     fortran only
+       tra     fortran_chain   425     fortran only
+       tra     long_profile    426
+       tra     index_before_cs 427
+       tra     index_before_bs 428
+       tra     index_after_cs  429
+       tra     index_after_bs  430
+       tra     index_before_bs_1       431
+       tra     index_after_bs_1        432
+       tra     verify_for_ltrim        433
+       tra     verify_for_rtrim        434
+       tra     stacq_mac               435
+       tra     clock_mac               436
+       tra     vclock_mac      437
+       tra     ftn_open_element        438     fortran only
+       tra     ftn_get_area_ptr        439     fortran only
+       tra     stop            440
+       tra     return_main     441
+       tra     set_main_flag   442
+       tra     begin_return_main       443
+       tra     size_check_uns_fx1      444
+       tra     size_check_uns_fx2      445
+       tra     fortran_end     446     fortran only
+       tra     &2fort_dmod     447     fortran only
+       tra     ix_rev_chars    448
+       tra     verify_rev_chars        449
+       tra     search_rev_chars        450
+       tra     shorten_stack_protect_ind       451
+       tra     save_stack_quick        452
+       tra     restore_stack_quick     453
+       tra     <fort_math_ops_>|[&2dtanh]      454     fortran only
+       tra     <fort_math_ops_>|[&2sinh]       455     fortran only
+       tra     <fort_math_ops_>|[&2dsinh]      456     fortran only
+       tra     <fort_math_ops_>|[&2cosh]       457     fortran only
+       tra     <fort_math_ops_>|[&2dcosh]      458     fortran only
+       tra     &2nearest_whole_number  459     fortran only
+       tra     &2nearest_integer       460     fortran only
+       tra     ftn_inquire_element     461     fortran only
+       tra     mpy_overflow_check      462     fortran only
+       tra     fort_return_mac 463     fortran only
+       tra     fort_cleanup    464     fortran only
+       tra     fort_storage    465     fortran only
+       tra     &1enter_BFP_mode        466
+       tra     &1enter_HFP_mode        467
+       tra     unimp           468     future expansion
+       tra     unimp           469     future expansion
+       tra     unimp           470     future expansion
+       tra     unimp           471     future expansion
+       tra     unimp           472     future expansion
+       tra     unimp           473     future expansion
+       tra     unimp           474     future expansion
+       tra     unimp           475     future expansion
+       tra     unimp           476     future expansion
+       tra     unimp           477     future expansion
+       tra     unimp           478     future expansion
+       tra     unimp           479     future expansion
+       tra     unimp           480     future expansion
+       &end
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+"      END OF MACROS
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"\f
+begin_pl1_operators:
+       transfer_vector
+
+"
+"      The following section is not referenced directly by
+"      the compiled pl/1 program and may be changed as
+"      desired.
+"
+"      THE FOLLOWING CONVENTIONS APPLY TO STRING OPERATORS
+"              1. Unless specified otherwise, a unit size is in the q register
+"              2. Operators whose names end in "_aligned" or "vta" deal
+"                 with aligned strings having no fractional offset.
+"              3. Operators whose names end in "_co" have a character offset in x7.
+"              4. Operators whose names end in "_ho" have a half-word offset in x7.
+"              5. If not one of the above, the offset is a bit offset in x7.
+"              6. A pointer to the string is transmitted in the bp.
+"              7. If name of operator ends in "_eis", the bit offset is correct in bp
+"                 and index register 7 is not used.
+"
+"      allocation operators
+"      The char and bit allocation operators reserve two extra words
+"      the temporary is stored in the second of these.
+"
+alloc_char_temp:
+       stq     sp|char_lg1     save char length
+       stz     sp|bit_or_char  indicate char temp
+       adq     3+8,dl          compute number of words with 2 more
+       qrs     2
+       tsx1    alloc           allocate space
+       ldq     sp|char_lg1     restore char length
+"
+act:   eppbp   bp|2            skip over extra 2 words
+       stq     bp|-1           save length of temp
+abt:   spribp  sp|temp_pt      save pointer to temp
+       tra     sp|tbp,*0               and return to pl/1 program
+"
+alloc_bit_temp:
+       stq     sp|bit_lg1      save bit length
+       stc1    sp|bit_or_char  indicate bit temp
+       adq     35+72,dl                compute number of words (2 extra)
+       div     36,dl
+       tsx1    alloc           allocate space
+       ldq     sp|bit_lg1      restore bit length
+       tra     act             and go fill in length
+"
+alloc_temp:
+       eax1    abt             alloc N words and go save ptr
+"                              fall into alloc coding
+"
+"      routine to allocate N words at end of stack.
+"      entered with N in ql.
+"
+alloc: qls     18              shift number to qu
+       stq     sp|temp_size    save number of words
+       get_stack_offset
+       eppbp   sp|stack_header.stack_end_ptr,au* get ptr to extension
+       adlq    15,du           make size a multiple of 16
+       anq     =o777760,du     ..
+       stq     sp|extend_size
+       adlq    sp|stack_frame.next_sp+1        compute new end of stack frame
+       stq     sp|stack_frame.next_sp+1        bump next ptr
+       stq     sp|stack_header.stack_end_ptr+1,au      bump stack end pointer
+       tra     0,1             return to operator
+"
+"      reallocation operators
+"      allowance is made for the two words at the head of the string
+"
+cat_realloc_bits:
+       lda     sp|bit_lg1      set up for concatenation
+       sta     sp|cat_lg1
+       stq     sp|bit_lg1      set new bit length
+       adq     35+72,dl                compute new length of temp
+       div     36,dl
+       lda     sp|bit_lg1      restore bit length
+       tsx1    realloc         extend stack again
+       tra     sp|tbp,*0               an return to caller
+"
+realloc_bit_temp:
+       sta     sp|bit_lg1      set new length
+       adq     35+72,dl                compute new word length
+       div     36,dl
+       lda     sp|bit_lg1      restore bit length
+       tsx1    realloc         extend stack
+       tra     zero_it         and go zero new space
+"
+cat_realloc_chars:
+       lda     sp|char_lg1     set up for concatenation
+       sta     sp|cat_lg1
+"
+realloc_char_temp:
+       stq     sp|char_lg1     set new char length
+       adq     3+8,dl          compute new word length
+       qrs     2
+       lda     sp|char_lg1     restore char lenth
+       tsx1    realloc         extend stack
+       tra     sp|tbp,*0               and exit
+"
+realloc:       stx1    sp|save_x01
+       ldx1    sp|temp_size    save end position of current temp
+       eppbp   sp|temp_pt,*    get ptr to temp
+       sta     bp|-1
+       lda     sp|save_x01     restore return offset
+       qls     18              shift word size to qu
+       stq     sp|temp_size    set new size of temp
+       sblq    sp|extend_size  subtract size of extension
+       tmi     0,au            return if no extension needed
+       adlq    15,du           make increment a multiple of 16
+       anq     =o777760,du     ..
+       stq     sp|temp         save increment momentarily
+       adlq    sp|extend_size  update extension size
+       stq     sp|extend_size  ..
+       get_stack_offset
+       ldq     sp|temp         get extension increment
+       adlq    sp|stack_frame.next_sp+1        compute new end of stack frame
+       stq     sp|stack_frame.next_sp+1        bump next sp pointer
+       stq     sp|stack_header.stack_end_ptr+1,au      bump stack end pointer
+       lda     sp|save_x01     restore return offset
+       tra     0,au            return to caller
+"
+"      this operator shortens the stack frame to its original length
+"
+shorten_stack:
+       epbpab  sp|0            get ptr to base of stack
+       ldx1    sp|5
+       stx1    sp|stack_frame.next_sp+1
+       stx1    ab|stack_header.stack_end_ptr+1
+
+       tra     sp|tbp,*0
+"
+"      This operator is the same as shorten_stack above, but does not change the indicators.
+"
+shorten_stack_protect_ind:
+       sti     sp|temp         Save indicators
+       epbpap  sp|0            Get ptr to base of stack
+       ldx1    sp|5
+       stx1    sp|stack_frame.next_sp+1
+       stx1    ab|stack_header.stack_end_ptr+1
+       ldi     sp|temp         Restore indicators
+
+       tra     sp|tbp,*0
+"
+"      This operator makes the current extension permanent,
+"      and returns the old permanent extent  in the q.
+"
+save_stack_quick:
+       ldq     sp|5            Get permanent extent
+       ldx1    sp|stack_frame.next_sp+1
+       stx1    sp|5            Change it
+       tra     sp|tbp,*0
+"
+"      This operator is the inverse of save_stack_quick above.
+"      It takes a stack offset in the Q, and makes it the permanent
+"      stack extent.
+"
+restore_stack_quick:
+       stq     sp|5            Change permanent extent
+       tra     sp|tbp,*0
+"
+"      code added here to handle 2 extra instructions needed at set_stack
+"
+set_stack_extend:
+       get_stack_offset
+       eppbp   sp|stack_frame.next_sp,* set up stack end ptr correctly
+       spribp  sp|stack_header.stack_end_ptr,au ..
+       tra     sp|tbp,*0               and return to pl1 program
+"
+"      operator to save the string in the aq in stack so it is
+"      accessable to long string operators.  entered with bit_size
+"      in x6 and string in aq
+"
+save_string:
+       staq    sp|double_temp  save the string
+       eppbp   sp|double_temp  load ptr to string
+       eaq     0,6             move bit size to ql
+       qrl     18
+       spribp  sp|temp_pt      save ptr to string
+       stq     sp|bit_lg1      save bit length
+       div     9,dl            compute char length
+       stq     sp|char_lg1     and save that
+       tra     sp|tbp,*0
+"
+"      operators to save info about a string in the stack.
+"
+set_chars_eis:
+       stq     sp|char_lg1     save char length
+       stz     sp|bit_or_char  indicate char string
+       spribp  sp|temp_pt      save ptr (with bit offset)
+       tra     sp|tbp,*0               and return
+"
+set_chars:
+       eax1    0,7             get bit offset
+       tra     sca
+"
+set_chars_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     sca
+"
+set_chars_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     sca
+"
+set_chars_aligned:
+       eax1    0               get zero offset
+sca:   stq     sp|char_lg1     save char length
+       stz     sp|bit_or_char  indicate char string
+"
+sca1:  spribp  sp|temp_pt      save ptr to string
+       lxl1    shift_bo,1      shift bit offset to left
+       sxl1    sp|temp_pt+1    and overwrite former bit offset
+       tra     sp|tbp,*0
+"
+set_bits_eis:
+       stq     sp|bit_lg1      save bit length
+       stc1    sp|bit_or_char  indicate bit string
+       spribp  sp|temp_pt      save ptr (with bit offset)
+       tra     sp|tbp,*0               and return
+"
+set_bits:
+       eax1    0,7             get bit offset
+       tra     sba
+"
+set_bits_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     sba
+"
+set_bits_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     sba
+"
+set_bits_aligned:
+       eax1    0               get zero offset
+"
+sba:   stq     sp|bit_lg1      save bit length
+       stc1    sp|bit_or_char  indicate bit temp
+       tra     sca1
+"
+"      operator to store a string when size+offset > 72
+"      entered with string to be stored in aq, bit_size+offset-72 in x6,
+"      bit offset in x7, and ptr to destination in bp
+"
+store_string:
+       stq     sp|temp         save right part of string
+       lrl     0,7             shift to proper position
+       era     bp|0            insert in first two words
+       stq     bp|1            of destination
+       ana     mask_bit_one,7  mask has no trailing zeros
+       ersa    bp|0
+       lda     sp|temp         get right part of string
+       ldq     0,dl            clear q register
+       lrl     0,7             shift into position
+       erq     bp|2            insert into third word
+       anq     bit_mask_one,6  mask has no leading zeros
+       ersq    bp|2
+       tra     sp|tbp,*0               return to pl1 program
+"
+"      operator to store a string with an adjustable bit offset.
+"      entered with bit size in x6.
+"
+string_store:
+       eax1    0,7             bit offset to x1
+       tra     ss_0
+"
+string_store_co:
+       eax1    0,7             char offset to x1
+       cmpx1   4,du            is offset >= 36 bits
+       tmi     3,ic            no
+       eppbp   bp|1            yes, adjust destination pointer
+       eax1    -4,1            and offset
+       ldx1    co_to_bo,1      convert to bit offset
+       tra     ss_0
+"
+string_store_ho:
+       eax1    0,7             half word offset to x1
+       cmpx1   2,du            is offset >= 36 bits
+       tmi     3,ic            no
+       eppbp   bp|1            yes, adjust destination pointer
+       eax1    -2,1            and offset
+       ldx1    ho_to_bo,1      convert to bit offset
+"
+ss_0:  adwpbp  0,du            erase bit offset
+       staq    sp|double_temp  save in aligned temp
+       csl     (ar+rl),(ar+rl+x1),bool(move)   move into target
+       descb   sp|double_temp,x6
+       descb   bp|0,x6
+       tra     sp|tbp,*0
+"
+"      operator to return in aq the first 72 bits of the char string
+"      specified by string_aq.  if the length if less than 72 bits, string is padded
+"      with blanks
+"
+fetch_chars:
+       ldq     sp|char_lg1     load char length
+       eppap   sp|temp_pt,*    get ptr to temp
+       tra     gc_1            join common case
+"
+"      operator to return in aq the first 72 bits of an adjustable char
+"      string. if length is less than 72 bits, string is padded.
+"      note: compiled code expects bp not to be changed
+"
+get_chars:
+       eax1    0,7             load offset
+       tra     gc_0
+"
+get_chars_co:
+       ldx1    co_to_bo,7      convert offset to bits
+       tra     gc_0
+"
+get_chars_ho:
+       ldx1    ho_to_bo,7      convert offset to bits
+       tra     gc_0
+"
+get_chars_aligned:
+       eax1    0               get zero offset
+"
+gc_0:  eppap   bp|0            copy ptr to string
+       adwpap  0,du            erase bit offset
+       abd     ap|0,1          add new bit offset
+"
+gc_1:  mlr     (ar+rl),(ar),fill(blank)        move to aligned temp
+       desc9a  ap|0,ql
+       desc9a  sp|temp,8
+       eppap   sp|stack_frame.operator_ptr,*
+       ldaq    sp|temp
+       tra     sp|tbp,*0
+"
+"      operator to return in aq the first 72 bits of the char string
+"      specified by string aq.  if the length is less than 72 bits, string 
+"      is padded with binary zeroes.
+"
+fetch_chars_eis:
+       ldq     sp|char_lg1     load char length
+       eppap   sp|temp_pt,*    get ptr to temp
+       mlr     (ar+rl),(ar),fill(0)    move to aligned temp
+       desc9a  ap|0,ql
+       desc9a  sp|temp,8
+       eppap   sp|stack_frame.operator_ptr,*
+       ldaq    sp|temp
+       tra     sp|tbp,*0
+"
+"      operator to return in aq the first 72 bits of the bit string
+"      specified by string_aq.  if length is less than 72 bits,
+"      string is padded.
+"
+fetch_bits:                    "eis comes here, too
+       eppap   sp|temp_pt,*    get ptr to temp
+       ldq     sp|bit_lg1      get bit length
+       eax1    0               use 0 bit offset
+       tra     gb_1
+"
+"      operator to return in aq the first 72 bits of an adjustable bit
+"      string. if length is less than 72 bits, string is padded.
+"      note: compiled code expects bp not to be changed
+"
+get_bits:
+       eax1    0,7             load offset
+       tra     gb_0
+"
+get_bits_co:
+       ldx1    co_to_bo,7      convert offset to bits
+       tra     gb_0
+"
+get_bits_ho:
+       ldx1    ho_to_bo,7      convert offset to bits
+       tra     gb_0
+"
+get_bits_aligned:
+       eax1    0               get zero offset
+"
+gb_0:  eppap   bp|0            copy ptr to string
+       adwpap  0,du            erase bit offset
+"
+gb_1:  csl     (ar+rl+x1),(ar),bool(move)      move to aligned temp
+       descb   ap|0,ql
+       descb   sp|temp,72
+       eppap   sp|stack_frame.operator_ptr,*
+       ldaq    sp|temp
+       tra     sp|tbp,*0
+"
+"      operator to pad the char string temporary to 8 chars.
+"
+pad_chars:
+       ldq     8,dl            compute number of chars left
+       sbq     sp|char_lg1
+       tmoz    sp|tbp,*0
+       lda     sp|char_lg1     get offset
+       eppap   sp|temp_pt,*    get ptr to temp
+       mlr     (0),(ar+rl+a),fill(blank)       put fill(blank)s at end
+       vfd     36/0
+       desc9a  ap|0,ql
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+"      operator to pad the bit string temporary to 72 bits.
+"
+pad_bits:
+       ldq     sp|bit_lg1      get bit length of temp
+       cmpq    73,dl           is it already long enough
+       trc     sp|tbp,*0               yes, return
+       adq     sp|bit_lg1      no, form 2*bit_length
+       eax1    1,ql            and place in index reg
+       ldaq    sp|temp_pt,*    mask string
+       anaq    bit_mask,1
+       staq    sp|temp_pt,*    replace padded string
+       tra     sp|tbp,*0               and return to pl/1 program
+"
+"      operators to AND a string into the string
+"      temporary pointed at by sp|temp_pt.  the string being ANDED
+"      is guaranteed to be no bigger than the space in the stack.
+"
+and_bits:
+       eax1    0,7             load offset
+       tra     and_1
+"
+and_bits_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     and_1
+"
+and_bits_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     and_1
+"
+and_bits_aligned:
+       eax1    0
+"
+and_1: lda     ana_op          pickup logical function to do
+       tra     logical         join common section
+"
+"      operators to OR a string into the string
+"      temporary pointed at by sp|temp_pt.  the string being ORED
+"      is guaranteed to be no bigger and the space in the stack.
+"
+or_bits:
+       eax1    0,7             load offset
+       tra     or_1
+"
+or_bits_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     or_1
+"
+or_bits_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     or_1
+"
+or_bits_aligned:
+       eax1    0               zero offset
+"
+or_1:  lda     ora_op          pickup logical function to do
+       tra     logical         join common section
+"
+"      operators to EXCLUSIVE OR a string into the string
+"      temporary pointed at by sp|temp_pt.  the string being EXORed
+"      is guaranteed to be no bigger than the space in the stack.
+"
+exor_bits:
+       eax1    0,7             load offset
+       tra     exor_1
+"
+exor_bits_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     exor_1
+"
+exor_bits_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     exor_1
+"
+exor_bits_aligned:
+       eax1    0               zero offset
+"
+exor_1:        lda     era_op          pickup logical function to do
+       tra     logical         join common section
+"
+"      operators to MOVE a string into the string
+"      temporary pointed at by sp|temp_pt.  the string being MOVED
+"      is guaranteed to be no bigger than the space in the stack.
+"      since this operator is always followed by concatenation, no
+"      padding is done.
+"
+cat_move_bits:
+       eax1    0,7             load offset
+       tra     cmb_1
+"
+cat_move_bits_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     cmb_1
+"
+cat_move_bits_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     cmb_1
+"
+cat_move_bits_aligned:
+       eax1    0               zero bit offset
+"
+cmb_1: stq     sp|cat_lg1      save for later cat operator
+       cmpq    0,dl            return if nothing to move (prevent IPR)
+       tze     sp|tbp,*0
+       adwpbp  0,du            clear bit offset
+       eppap   sp|temp_pt,*    get ptr to target
+       csl     (ar+rl+x1),(ar+rl),bool(move)   move source into temp
+       descb   bp|0,ql
+       descb   ap|0,ql
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+"      operators to MOVE the COMPLEMENT of astring into
+"      the string temporary pointed at by sp|temp_pt.  the string
+"      being moved is guaranteed to be the same size as the
+"      destination.
+"
+move_not_bits:
+       eax1    0,7             load offset
+       tra     move_not_1
+"
+move_not_bits_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     move_not_1
+"
+move_not_bits_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     move_not_1
+"
+move_not_bits_aligned:
+       eax1    0               zero offset
+"
+move_not_1:
+       lda     not_op          pickup logical function to do
+       tra     logical         join common section
+"
+"      operators to MOVE a string into the string
+"      temporary pointed at by sp|temp_pt.  the string being MOVED
+"      is guaranteed to be no bigger than the size of the destination.
+"
+move_bits:
+       eax1    0,7             load offset
+       tra     mb_1
+"
+move_bits_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     mb_1
+"
+move_bits_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     mb_1
+"
+move_bits_aligned:
+       eax1    0               zero offset
+"
+mb_1:  lda     nop_op          pickup logical function to do
+"
+logical:       sta     sp|bit_op               save operator to perform
+       lda     sp|bit_lg1      get length of temp
+       tze     sp|tbp,*0               exit if zero (prevent IPR)
+       adwpbp  0,du            clear bit offset
+       eppap   sp|temp_pt,*    get ptr to temp
+       xec     sp|bit_op               do the operation
+       descb   bp|0,ql
+       descb   ap|0,al
+log_exit:
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+"      logical functions...
+"
+nop_op:        csl     (ar+rl+x1),(ar+rl),bool(move)
+ana_op:        csl     (ar+rl+x1),(ar+rl),bool(and)
+ora_op:        csl     (ar+rl+x1),(ar+rl),bool(or)
+era_op:        csl     (ar+rl+x1),(ar+rl),bool(xor)
+not_op:        csl     (ar+rl+x1),(ar+rl),bool(invert)
+"
+"      operators to MOVE a string into the string
+"      temporary pointed at by sp|temp_pt.  the string being MOVED
+"      is guaranteed to be no bigger than the space in the stack.
+"      if this is cat_move_chars, no padding will be done since
+"      operator is always followed by concat.
+"
+move_chars:
+       eax1    0,7             load offset
+       tra     mc_1
+"
+move_chars_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     mc_1
+"
+move_chars_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     mc_1
+"
+move_chars_aligned:
+       eax1    0
+"
+mc_1:  adwpbp  0,du            clear bit offset
+       abd     bp|0,1          add new bit offset
+       lda     sp|char_lg1     get length of target
+       tze     sp|tbp,*0               exit if zero (prevent IPR)
+       eppap   sp|temp_pt,*    get ptr to target
+       mlr     (ar+rl),(ar+rl),fill(blank)
+       desc9a  bp|0,ql
+       desc9a  ap|0,al
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+cat_move_chars:
+       eax1    0,7             load offset
+       tra     cmc_1
+"
+cat_move_chars_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     cmc_1
+"
+cat_move_chars_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     cmc_1
+"
+cat_move_chars_aligned:
+       eax1    0               zero bit offset
+"
+cmc_1: adwpbp  0,du            clear bit offset
+       abd     bp|0,1          add new bit oofset
+       stq     sp|cat_lg1      save for following cat
+       cmpq    0,dl            exit if nothing to move (prevent IPR)
+       tze     sp|tbp,*0
+       eppap   sp|temp_pt,*    get ptr to target
+       mlr     (ar+rl),(ar+rl)
+       desc9a  bp|0,ql
+       desc9a  ap|0,ql
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+"      operator to AND a single length bit string into the string
+"      temporary pointed at by sp|temp_pt.  words 1,2,3,... of the
+"      temporary are cleared.
+"
+ext_and_1:
+       ldq     0,dl            clear q and join ext_and_2
+"
+"      operator to AND a double length bit string into the string
+"      temporary pointed at by sp|temp_pt.  words 2,3,... of the
+"      temporary are cleared.
+"
+ext_and_2:
+       eppbp   sp|temp_pt,*    get ptr to string
+       ansa    bp|0            AND in the string
+       ansq    bp|1            ..
+       eax1    2               clear starting at word 2
+"
+"      routine to zero rest of string temp
+"      this routine returns directly to pl/1 program
+"      at entry:
+"              bp|0,1  points at first word to be cleared
+"              sp|temp_size holds total size of temporary
+"
+zero_it:       eaa     0,1             get current position
+       era     mask_bit_one    form 2's complement of whole a-reg
+       adla    1,dl            w/o overflow
+       adla    sp|temp_size    ..
+       tmoz    sp|tbp,*0               return if none
+       eppbp   bp|0,1          get ptr to starting pos
+       arl     18-2            get number of chars
+       mlr     (0),(ar+rl)             clear the area
+       vfd     36/0
+       desc9a  bp|0,al
+       eppbp   sp|temp_pt,*    restore ptr to tem (just in case)
+       tra     sp|tbp,*0               return to pl/1 program
+"
+"
+"      operator to complement the bit string temporary pointed
+"      at by sp|temp_pt
+"
+comp_bits:
+       ldq     sp|bit_lg1      get bit length
+       tze     sp|tbp,*0               exit if zero length (prevent IPR)
+       eppbp   sp|temp_pt,*    get ptr to temp
+       csl     (ar+rl),(ar+rl),bool(invert)    negate
+       descb   bp|0,ql
+       descb   bp|0,ql
+       tra     log_exit
+"
+"      operator to move string_1 into string_2
+"      source string_1 was previously setup
+"
+chars_move_vt:
+       stq     bp|-1           store size of string
+"
+chars_move:
+       eax1    0,7             load offset
+       tra     cm_1
+"
+chars_move_vt_co:
+       stq     bp|-1           store size of string
+"
+chars_move_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     cm_1
+"
+chars_move_vt_ho:
+       stq     bp|-1           store size of string
+"
+chars_move_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     cm_1
+"
+chars_move_vta:
+       stq     bp|-1           store size of string
+"
+chars_move_aligned:
+       eax1    0               zero offset
+"
+cm_1:  cmpq    0,dl            return if target zero length
+       tze     sp|tbp,*0
+       adwpbp  0,du            clear bit offset
+       abd     bp|0,1
+       eppap   sp|temp_pt,*    get ptr to source
+       lda     sp|char_lg1     get length of source
+       mlr     (ar+rl),(ar+rl),fill(blank)
+       desc9a  ap|0,al
+       desc9a  bp|0,ql
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+bits_move_vt:
+       stq     bp|-1           store size of string
+"
+bits_move:
+       eax1    0,7             load offset
+       tra     bm_1
+"
+bits_move_vt_co:
+       stq     bp|-1           store size of string
+"
+bits_move_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     bm_1
+"
+bits_move_vt_ho:
+       stq     bp|-1           store size of string
+"
+bits_move_ho:
+       ldx1    ho_to_bo,7
+       tra     bm_1
+"
+bits_move_vta:
+       stq     bp|-1           store siqe of string
+"
+bits_move_aligned:
+       eax1    0               zero bit offset
+"
+bm_1:  cmpq    0,dl            return if zerolength target
+       tze     sp|tbp,*0
+       adwpbp  0,du            clear target bit offset
+       abd     bp|0,1          add new bit offset
+       eppap   sp|temp_pt,*    get ptr to source
+       lda     sp|bit_lg1
+       csl     (ar+rl),(ar+rl),bool(move)
+       descb   ap|0,al
+       descb   bp|0,ql
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+"      operators to move string_1 into string_2
+"      when the size prefix is enabled
+"
+chars_move_ck:
+       eax1    0,7             get offset
+       tra     cmk_1
+"
+chars_move_ck_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     cmk_1
+"
+chars_move_ck_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     cmk_1
+"
+chars_move_ck_al:
+       eax1    0               zero offset
+"
+cmk_1: adwpbp  0,du            erase bit offset
+       abd     bp|0,1          add new offset
+       eppap   sp|temp_pt,*    get ptr to source
+       lda     sp|char_lg1     get length of source
+       mlr     (ar+rl),(ar+rl),fill(blank),enablefault
+       desc9a  ap|0,al
+       desc9a  bp|0,ql
+       tra     log_exit
+"
+bits_move_ck:
+       eax1    0,7             get offset
+       tra     bmk_1
+"
+bits_move_ck_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     bmk_1
+"
+bits_move_ck_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     bmk_1
+"
+bits_move_ck_al:
+       eax1    0               zero offset
+"
+bmk_1: adwpbp  0,du            erase bit offset
+       abd     bp|0,1          add new offset
+       eppap   sp|temp_pt,*    get ptr to source
+       lda     sp|bit_lg1      get length of source
+       csl     (ar+rl),(ar+rl),bool(move),enablefault
+       desc9a  ap|0,al
+       desc9a  bp|0,ql
+       tra     log_exit
+"
+"      operators to perform concatenation.  this is done by moving
+"      the second string into the stack just after the first string.
+"      length of first string is given by sp|cat_lg1 which is set
+"      by a previous cat_move_... operator or by a previous cat_realloc_...
+"
+cat_chars:
+       eax1    0,7             save offset
+       tra     cat_chars_aligned+1
+"
+cat_chars_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     cat_chars_aligned+1
+"
+cat_chars_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     cat_chars_aligned+1
+"
+cat_chars_aligned:
+       eax1    0               zero offset
+       cmpq    0,dl            return if nothing to concat
+       tze     cat_done
+       adwpbp  0,du            clear bit offset
+       abd     bp|0,1          add new bit offset
+       lda     sp|cat_lg1      get offset for concat
+       eppap   sp|temp_pt,*    get ptr to temp
+       mlr     (ar+rl),(ar+rl+a)
+       desc9a  bp|0,ql
+       desc9a  ap|0,ql
+       eppap   sp|stack_frame.operator_ptr,*
+cat_done:
+       eppbp   sp|temp_pt,*
+       tra     sp|tbp,*0
+"
+cat_bits:
+       eax1    0,7             save offset
+       tra     cat_bits_aligned+1
+"
+cat_bits_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     cat_bits_aligned+1
+"
+cat_bits_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     cat_bits_aligned+1
+"
+cat_bits_aligned:
+       eax1    0               zero offset
+       cmpq    0,dl
+       tze     cat_done                return if none to concat
+       adwpbp  0,du            erase bit offset
+       lda     sp|cat_lg1      get offset in temp
+       eppap   sp|temp_pt,*    get ptr to temp
+       csl     (ar+rl+x1),(ar+rl+a),bool(move)
+       descb   bp|0,ql
+       descb   ap|0,ql
+       tra     cat_done-1
+"
+"      operator to perform repeat function (copy builtin) on char string in the string AQ.
+"      entered with number of copies desired in q
+"
+repeat:
+       cmpq    0,dl            take max(n_copies,0)
+       tpl     2,ic
+       ldq     0,dl
+       stq     sp|count                save number of copies desired
+       eppap   sp|temp_pt,*    get ptr to string
+       szn     sp|bit_or_char  which case is this
+       tnz     repeat_bs
+       ldq     sp|char_lg1     get length of string
+       mpy     sp|count                compute length of result
+       stq     sp|lg2          and save for later
+       adq     3+8,dl          compute number of words (2 extra)
+       qrs     2
+       tsx1    alloc           allocate new temp
+       eppbp   bp|2            skip over 2 words at front
+       spribp  sp|temp_pt      save ptr to result
+       lxl1    sp|count                init loop
+       tze     repeat_exit+1   skip if nothing to do
+       ldq     sp|char_lg1     get back length of input
+       tze     repeat_exit+2   skip if nothing to do
+repeat_cs_loop:
+       mlr     (ar+rl),(ar+rl) move string
+       desc9a  ap|0,ql
+       desc9a  bp|0,ql
+       a9bd    bp|0,ql         add char length
+       sbx1    1,du
+       tnz     repeat_cs_loop  repeat  until done
+repeat_exit:
+       eppbp   sp|temp_pt,*    get ptr to result
+       ldq     sp|lg2          get length of result
+       stq     bp|-1           save
+       stq     sp|char_lg1
+       stq     sp|bit_lg1
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0               and return
+"
+"      operator to perform repeat function (copy builtin) on bit string in the string AQ.
+"      entered with number of copies desired in q
+"
+repeat_bs:
+       ldq     sp|bit_lg1      get length of string
+       mpy     sp|count                compute length of result
+       stq     sp|lg2          and save for later
+       adq     35+72,dl                compute number of words (2 extra)
+       div     36,dl
+       tsx1    alloc           allocate new temp
+       eppbp   bp|2            skip over 2 extra words
+       spribp  sp|temp_pt      save ptr to result
+       lxl1    sp|count                init loop
+       tze     repeat_exit+1   skip if nothing to do
+       ldq     sp|bit_lg1      get back length of input
+       tze     repeat_exit+2   exit now if nothing to do
+repeat_bs_loop:
+       csl     (ar+rl),(ar+rl),bool(move)
+       descb   ap|0,ql
+       descb   bp|0,ql
+       abd     bp|0,ql         add bit length of string
+       sbx1    1,du            repeat until done
+       tnz     repeat_bs_loop
+       tra     repeat_exit
+"
+"      operator to reverse bit string in the string AQ.
+"
+reverse_bs:
+       eppap   sp|temp_pt,*    get ptr to source
+       ldq     sp|bit_lg1      get bit length
+       adq     35+72,dl                compute word length needed (2 extra)
+       div     36,dl
+       tsx1    alloc           extend stack
+       eppbp   bp|2            skip over 2 words at front
+       spribp  sp|temp_pt      save ptr to result
+       ldq     sp|bit_lg1      get back bit length
+       stq     bp|-1           save
+       tze     log_exit                exit if nothing to do
+       lda     0,dl            init offset
+reverse_bs_loop:
+       sbq     1,dl
+       tmi     reverse_bs_exit done, exit
+       csl     (ar+q),(ar+a),bool(move)        move 1 bit
+       descb   ap|0,1
+       descb   bp|0,1
+       ada     1,dl            update offset
+       tra     reverse_bs_loop
+reverse_bs_exit:
+       ldq     sp|bit_lg1      get back length
+       tra     log_exit
+"
+"      operator to reverse character string in the string AQ.
+"
+reverse_cs:
+       eppap   sp|temp_pt,*    get ptr to source
+       ldq     sp|char_lg1     get char length
+       adq     3+8,dl          compute word length needed (2 extra)
+       qrs     2
+       tsx1    alloc           extend stack
+       eppbp   bp|2            skip over 2 words at front
+       spribp  sp|temp_pt      save ptr to result
+       ldq     sp|char_lg1     get back char length
+       stq     bp|-1           save
+       tze     log_exit                return if nothing to do
+       lda     0,dl            init offset
+reverse_cs_loop:
+       sbq     1,dl
+       tmi     reverse_cs_exit done, exit
+       mlr     (ar+q),(ar+a)   move 1 char
+       desc9a  ap|0,1
+       desc9a  bp|0,1
+       ada     1,dl            update offset
+       tra     reverse_cs_loop
+reverse_cs_exit:
+       ldq     sp|char_lg1
+       tra     log_exit
+"
+"      operator to suffix the string previously set up to a varying string.
+"      entered with pointer to varying string in bp, max length in q
+"
+suffix_cs:
+       sbq     bp|-1           get number of chars left in string
+       tze     sp|tbp,*0               return if string is full
+       cmpq    sp|char_lg1     get min(number left,number set up)
+       tmi     2,ic
+suffix_cs_1:
+       ldq     sp|char_lg1     get length of suffix
+       tze     sp|tbp,*0               exit if zero (prevent IPR)
+       eppap   sp|temp_pt,*    get ptr to suffix
+       lda     bp|-1           get offset of end
+       mlr     (ar+rl),(ar+rl+a)       suffix string
+       desc9a  ap|0,ql
+       desc9a  bp|0,ql
+       asq     bp|-1           update string length
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0               and return
+"
+"      operator to suffix to varying bit string.
+"
+suffix_bs:
+       sbq     bp|-1           get number of bits left in string
+       tze     sp|tbp,*0               return if string full
+       cmpq    sp|bit_lg1      get min(number left,number set up)
+       tmi     2,ic
+suffix_bs_1:
+       ldq     sp|bit_lg1      get length of suffix
+       tze     sp|tbp,*0               exit if zero (prevent IPR)
+       eppap   sp|temp_pt,*    get ptr to suffix
+       lda     bp|-1           get offset of last bit available
+       csl     (ar+rl),(ar+rl+a),bool(move)
+       descb   ap|0,ql
+       descb   bp|0,ql
+       asq     bp|-1           update string length
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0               and return
+"
+"      operators to suffix the string previously set up to a varying string
+"      when the stringsize condition is enabled.  entered with pointer
+"      to string in bp, max length in q
+"
+suffix_cs_ck:
+       sbq     bp|-1           get number of chars left
+       tze     3,ic
+       cmpq    sp|char_lg1     get min(number left,number set up)
+       tpl     suffix_cs_1
+       eaa     suffix_cs_1     error, signal stringsize
+"
+suffix_error:
+       sxl0    sp|stack_frame.operator_ret_ptr no, signal stringsize
+       spribp  sp|double_temp
+       staq    sp|temp
+       eppbp   stringsize_name
+       eax6    stringsize_length
+       ldq     =702,dl         get oncode value
+       tsx1    call_signal_
+       lxl0    sp|stack_frame.operator_ret_ptr
+       eppbp   sp|double_temp,*
+       ldaq    sp|temp
+       tra     1,au            join standard section
+"
+suffix_bs_ck:
+       sbq     bp|-1
+       tze     3,ic
+       cmpq    sp|bit_lg1
+       tpl     suffix_bs_1
+       eaa     suffix_bs_1
+       tra     suffix_error
+"
+"      operator to compare string_2 with previously setup string_1
+"
+cp_chars:
+       eax1    0,7             save offset
+       tra     cp_chars_aligned+1
+"
+cp_chars_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     cp_chars_aligned+1
+"
+cp_chars_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     cp_chars_aligned+1
+"
+cp_chars_aligned:
+       eax1    0               zero offset
+       adwpbp  0,du
+       abd     bp|0,1          add new bit offset
+cpcs_1:        eppap   sp|temp_pt,*    get ptr to string_1
+       lda     sp|char_lg1     get length(string_1)
+       cmpc    (ar+rl),(ar+rl),fill(blank)
+       desc9a  bp|0,ql         string_2
+       desc9a  ap|0,al         string_1
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+cp_bits:
+       eax1    0,7             save offset
+       tra     cp_bits_aligned+1
+"
+cp_bits_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     cp_bits_aligned+1
+"
+cp_bits_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     cp_bits_aligned+1
+"
+cp_bits_aligned:
+       eax1    0               zero ofset
+       adwpbp  0,du            erase bit offset
+cpbs_1:        eppap   sp|temp_pt,*    get ptr to string_1
+       lda     sp|bit_lg1
+       cmpb    (ar+rl+x1),(ar+rl)
+       descb   bp|0,ql         string_2
+       descb   ap|0,al         string 1
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+"      operators to compare single (double) word string in a-reg (aq_reg)
+"      with string previously setup
+"
+cpcs_ext1:
+       ldq     blanks          convert to double length string
+"
+cpcs_ext2:
+       staq    sp|double_temp  save string in aq
+       ldq     8,dl            get length
+       eppbp   sp|double_temp  get ptr to string
+       tra     cpcs_1
+"
+cpbs_ext1:
+       ldq     0,dl            convert to double length string
+"
+cpbs_ext2:
+       staq    sp|double_temp  save string in aq
+       ldq     72,dl
+       eppbp   sp|double_temp
+       tra     cpbs_1
+"
+"      operator to check an unaligned string for any non-zero bits.
+"
+cpbs3:
+       eax1    0,7             load offset
+       tra     cpbs3a
+"
+cpbs3_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     cpbs3a
+"
+cpbs3_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     cpbs3a
+"
+"      operator to check the aligned string temp pointed at by
+"      temp_pt for any non_zero bits
+"
+cpbs4: ldq     sp|bit_lg1      get bit length
+       eppbp   sp|temp_pt,*    get ptr to string
+"
+cpbs3_aligned:
+       eax1    0               zero offset
+"
+cpbs3a:        adwpbp  0,du            erase bit offset
+       cmpb    (ar+rl+x1),(0)
+       descb   bp|0,ql
+       vfd     36/0
+       tra     sp|tbp,*0
+"
+"      operators to blank out a character string
+"
+blank_chars:
+       eax1    0,7             get offset
+       tra     bc_1
+"
+blank_chars_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     bc_1
+"
+blank_chars_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     bc_1
+"
+blank_chars_aligned:
+       eax1    0               zero offset
+"
+bc_1:  cmpq    0,dl            return if string zero length
+       tze     sp|tbp,*0
+       adwpbp  0,du            erase bit offset
+       abd     bp|0,1          add new offset
+       mlr     (0),(ar+rl),fill(blank)
+       vfd     36/0
+       desc9a  bp|0,ql
+       tra     sp|tbp,*0
+"
+"      operators to zero out a bit string
+"
+zero_bits:
+       eax1    0,7             get bit offset
+       tra     zb_1
+"
+zero_bits_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     zb_1
+"
+zero_bits_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     zb_1
+"
+zero_bits_aligned:
+       eax1    0               get zero offset
+"
+zb_1:  cmpq    0,dl            return if string zero length
+       tze     sp|tbp,*0
+       adwpbp  0,du            erase bit offset
+       csl     (0),(ar+rl+x1),bool(move)
+       descb   bit_mask,0      (avoid csl bug by using real address)
+       descb   bp|0,ql
+       tra     sp|tbp,*0
+"
+"      operators to copy a constant into a temporary of the same size
+"      entered with destination in bp, length in q, and text location of
+"      constant in x1
+"
+copy_const_vt:
+       stq     bp|-1           set size
+"
+copy_const:
+       eppap   sp|tbp,*1               get ptr to constant
+       mlr     (ar+rl),(ar+rl)
+       desc9a  ap|0,ql
+       desc9a  bp|0,ql
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+"      operator to compute index(str1,str2).  entered with str1 specified
+"      by previous set operator.
+"
+"
+index_chars:
+       eax1    0,7             get bit offset
+       tra     ixc
+"
+index_chars_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     ixc
+"
+index_chars_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     ixc
+"
+index_chars_aligned:
+       eax1    0               get zero offset
+"
+ixc:   adwpbp  0,du            erase bit offset
+       abd     bp|0,1          add new bit offset
+
+"      General entry
+
+index_chars_eis:
+ixc2:  eppap   sp|temp_pt,*    get ptr to string_1
+       lda     sp|char_lg1     Get length 1
+       cmpq    sp|char_lg1     Too long?
+       tpnz    zix
+       cmpq    1,dl            are we looking for single char
+       tpnz    ixcs_long               Big string
+       tmi     zix             0-length is failure.
+ixc1:  scm     (ar+rl),(ar)
+       desc9a  ap|0,al
+       desc9a  bp|0,0
+       arg     sp|temp
+       ttn     zix             tally runout means not found
+ixc_ret_ok:
+       ldq     sp|temp         get index
+       adq     1,dl            convert to pl1 index value
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+"      index failed
+"
+zix:   ldq     0,dl
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+"      string_2 is more than 1 character
+"
+ixcs_long:
+       stq     sp|lg2          save length of string_2
+       lrl     36              l(string1) =>q, 0 => a
+       sblq    sp|lg2          Don't search last l(string2)
+       stq     sp|t2           save lg(s1) - lg (s2)
+ixcs_loop:
+       adlq    2,dl            ok to match 2 more
+       scd     (ar+rl+a),(ar)  Look for prefix
+       desc9a  ap|0,ql
+       desc9a  bp|0
+       arg     sp|temp
+       ttn     zix             Fails.
+"
+"      See if string really won.
+"
+       adla    1,dl            add 1 both for pl1 result and new offs
+       adla    sp|temp         This gonna be real offset.
+       sta     sp|temp         Leave in a and temp
+       ldq     sp|lg2          Compare whole string
+       cmpc    (ar+rl+a),(ar+rl)
+       desc9a  ap|-1(3),ql     ql = length
+       desc9a  bp|0,ql         string 2 length
+       tze     ixc_ret_ok_1    answer in a
+       ldq     sp|t2           charlg1 - lg2
+       sblq    sp|temp
+       tpl     ixcs_loop
+       tra     zix             Nothing left to search
+
+ixc_ret_ok_1:
+       lrl     36
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+
+"      Operator to compute index (rev(string1),rev(string2))
+"      Same conventions as ix_chars.
+
+ix_rev_chars:
+       cmpq    sp|char_lg1     String 2 bigger than 1?
+       tpnz    zix             Quick failure.
+       eppap   sp|temp_pt,*    Get searchee ptr
+       lda     sp|char_lg1     Load up searchee length
+       cmpq    1,dl            Search for 0, 1, or 2?
+       tmi     zix             Immediate failure for 0.
+       tpnz    ix_rev_long     2 or more chars
+
+"      Search for 1 char.  Searchee guaranteed to be at least 1 long.
+"
+"      ap = ptr to string1
+"      bp = ptr to string2
+"      a = length(string1)
+"      q = length(string2) = 1
+"      x0 = return offset
+
+       scmr    (pr,rl),(pr)
+       desc9a  ap|0,al
+       desc9a  bp|0
+       arg     sp|temp
+       ttn     zix             " Was string2 found in string1?
+       tra     ixc_ret_ok      " Yes: return 1-origin index
+
+"      Now known to be 2 or more characters to search for
+"      in string guaranteed 2 or more long.  Note that a leading
+"      prefix of the searchee of length (length (searchstring)-2)
+"      need not be searched.
+"
+ix_rev_long:
+       stq     sp|lg2          length (searchstring)
+       sbla    sp|lg2          Deduct l(ss)-2 from searchable len
+       adla    2,dl
+ix_rev_loop:
+       scdr    (ar+rl+q),(ar+q)        q is l(searchstring)
+       desc9a  ap|-1(2),al     a is searchable length of searchee
+       desc9a  bp|-1(2)                Gets last 2 chars
+       arg     sp|temp         Answer
+       ttn     zix             Clear and present failure
+"
+"      See if we really found the string.  This algebra
+"      really, really works.
+"
+       sbla    2,dl
+       sbla    sp|temp
+"
+"      Compare the full string.  Length still in q, offset now in a.
+"
+       cmpc    (ar+rl+a),(ar+rl)
+       desc9a  ap|0,ql
+       desc9a  bp|0,ql
+       tnz     ix_rev_more     Nope. Try some more.
+"
+"      String found.  Find how many chars left on other side.
+"
+       adla    sp|lg2          length(searchstring)
+       sbla    sp|char_lg1     this is negative
+       neg     0
+       adla    1,dl            for PL/I convention
+       lrl     36
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0               return.
+ix_rev_more:
+       adla    1,dl            This is right.
+       cmpa    2,dl            Still left to search?
+       tmi     zix             Search fails if not
+       tra     ix_rev_loop     New stuff in a.
+"
+"      Bit index operators
+"
+
+index_bits_eis:
+       cmpq    0,dl            exit now if string_2 zero length
+       tze     sp|tbp,*0
+       tra     ixb2            join common case
+"
+index_bits:
+       eax1    0,7             get bit offset
+       tra     ixb
+"
+index_bits_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     ixb
+"
+index_bits_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     ixb
+"
+index_bits_aligned:
+       eax1    0               get zero offset
+"
+ixb:   cmpq    0,dl            exit if string 2 zero length
+       tze     sp|tbp,*0
+       adwpbp  0,du            erase bit offset
+       abd     bp|0,1          use new bit offset
+ixb2:  eppap   sp|temp_pt,*    get ptr to string_1
+ixb1:  stq     sp|lg2          save length of string_2
+       ldq     0,dl            init loop
+ixbs_loop:
+       stq     sp|count
+       lda     sp|bit_lg1      compute number of remaining bits in 1
+       sba     sp|count
+       cmpa    sp|lg2          must be >= length 2
+       tmi     zix
+       lda     sp|lg2          get length 2
+       adq     1,dl            convert skip count to pl1 index
+       cmpb    (ar+rl),(ar+rl+q)
+       descb   bp|0,al
+       descb   ap|-1(35),al
+       tnz     ixbs_loop               failed, try next value
+       cmpq    0,dl            set indicators
+       eppap   sp|stack_frame.operator_ptr,*   index in q, exit
+       tra     sp|tbp,*0
+"
+"      operator to compute index(str1,str2) when str2 is a single char.
+"      entered with value of str2 in a register.
+"
+index_cs_1_eis:
+       cmpq    0,dl            exit now if string 1 zero length
+       tze     sp|tbp,*0
+       tra     ixcs1_b         join common cae
+index_cs_1:
+       eax1    0,7             convert to bit offset
+       tra     ixcs1_a         join common section
+"
+index_cs_1_co:
+       ldx1    co_to_bo,7      get bit offset
+       tra     ixcs1_a
+"
+index_cs_1_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     ixcs1_a
+"
+index_cs_1_aligned:
+       eax1    0               get zero offset
+"
+ixcs1_a:       cmpq    0,dl            return immediately if string 1 zero length
+       tze     sp|tbp,*0
+       adwpbp  0,du            clear bit offset
+       abd     bp|0,1          use new bit offset
+ixcs1_b:       eppap   bp|0            put ptr to string 1 in proper register
+       sta     sp|temp2                save the character
+       eppbp   sp|temp2                get ptr to it as string 2
+       lls     36              Needed in a
+       tra     ixc1
+"
+"      operators to search a bit string for a single bit
+"
+index_bs_1_eis:
+       cmpq    0,dl            exit now if string 1 zero length
+       tze     sp|tbp,*0
+       tra     ixbs1_b         join common case
+"
+index_bs_1:
+       eax1    0,7             save bit offset
+       tra     ixbs1_a
+"
+index_bs_1_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     ixbs1_a
+"
+index_bs_1_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     ixbs1_a
+"
+index_bs_1_aligned:
+       eax1    0               get zero offset
+"
+ixbs1_a:       cmpq    0,dl            return immediately if string 1 zero length
+       tze     sp|tbp,*0
+       adwpbp  0,du            clear bit offset
+       abd     bp|0,1          add new bit offset
+ixbs1_b:       eppap   bp|0            put ptr to string 1 in proper register
+       stq     sp|bit_lg1      save length of string_1
+       sta     sp|temp2                save the bit
+       eppbp   sp|temp2                get ptr to it as string 2
+       ldq     1,dl            get length of string 2
+       tra     ixb1
+"
+"      index operators used with before and after.  entered
+"      with str1 specified by previous set operator
+"
+index_before_cs:
+       cmpq    0,dl            exit now if str2 zero length
+       tze     sp|tbp,*0
+       eax1    0               set flag
+       tra     ixba
+"
+index_after_cs:
+       cmpq    0,dl            exit now if str2 zero length
+       tze     sp|tbp,*0
+       eax1    1               set flag
+ixba:  eppap   sp|temp_pt,*    get ptr to str1
+       cmpq    1,dl            are we looking for single char
+       tnz     ixba_long               no, skip
+       ldq     sp|char_lg1     get length of str1
+       scm     (ar+rl),(ar)
+       desc9a  ap|0,ql
+       desc9a  bp|0,1
+       arg     sp|temp
+       ttn     ixba_fail+1
+       ldq     sp|temp         get result
+       xec     nop_adq_dl,1
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+"      index failed
+"
+ixba_fail:
+       ldq     sp|char_lg1
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+ixba_bs_fail:
+       ldq     sp|bit_lg1
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+nop_adq_dl:
+       nop     0,dl            before
+       adq     1,dl            after
+"
+"      str2 is more than 1 char
+"
+ixba_long:
+       stq     sp|lg2          save length(str2)
+       ldq     0,dl            init loop
+ixba_loop:
+       stq     sp|count
+       lda     sp|char_lg1     get number remaining in str1
+       sba     sp|count
+       cmpa    sp|lg2          failed if < length(str2)
+       tmi     ixba_fail
+       scd     (ar+rl+q),(ar)  check for first 2 chars of str2
+       desc9a  ap|0,al
+       desc9a  bp|0,2
+       arg     sp|temp
+       ttn     ixba_fail               tally runout means failure
+       sba     sp|temp         compute length of hit
+       cmpa    sp|lg2          must be >= length(str2)
+       tmi     ixba_fail
+       adq     sp|temp         update
+       adq     1,dl            prepare to bump past hit
+       lda     sp|lg2          check full str2
+       cmpc    (ar+rl+q),(ar+rl)
+       desc9a  ap|-1(3),al
+       desc9a  bp|0,al
+       tnz     ixba_loop
+       sbq     1,dl            we want offset, NOT pl1 index
+       xec     nop_adq,1
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+nop_adq:
+       nop     0,dl            before
+       adq     sp|lg2          after
+"
+index_before_bs:
+       cmpq    0,dl            exit now if str2 zero length
+       tze     sp|tbp,*0
+       eax1    0
+       tra     ixba_bs
+"
+index_after_bs:
+       cmpq    0,dl            exit now if str2 zero length
+       tze     sp|tbp,*0
+       eax1    1
+ixba_bs:       eppap   sp|temp_pt,*    get ptr to str1
+ixba_bs1:      stq     sp|lg2          save length(str2)
+       ldq     0,dl            init loop
+ixba_bs_loop:
+       stq     sp|count
+       lda     sp|bit_lg1      compute remaining bits in str1
+       sba     sp|count
+       cmpa    sp|lg2          must be >= length(str2)
+       tmi     ixba_bs_fail
+       lda     sp|lg2          get length(str2)
+       adq     1,dl            prepare to skip past the bit
+       cmpb    (ar+rl),(ar+rl+q)
+       descb   bp|0,al
+       descb   ap|-1(35),al
+       tnz     ixba_bs_loop
+       sbq     1,dl            want offset, not pl1 index
+       xec     nop_adq,1
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+index_before_bs_1:
+       cmpq    0,dl            exit now if str1 zero len
+       tze     sp|tbp,*0
+       eax1    0
+       tra     ixba_bs2
+"
+index_after_bs_1:
+       cmpq    0,dl            exit now if str1 zero length
+       tze     sp|tbp,*0
+       eax1    1
+ixba_bs2:      eppap   bp|0            put ptr to str1 in proper register
+       stq     sp|bit_lg1      save length(str1)
+       sta     sp|temp2                save the bit
+       eppbp   sp|temp2                get ptr to it as str2
+       ldq     1,dl            get length of str2
+       tra     ixba_bs1
+"
+"      operators to make bit table for use with verify operator.
+"      entered with pointer to string in bp, offset in x7, size in q, and
+"      stack offset of bit table in au.
+"
+make_bit_table:
+       eax1    0,7             get offset
+       tra     mbt
+"
+make_bit_table_co:
+       ldx1    co_to_bo,7      convert offset to bits
+       tra     mbt
+"
+make_bit_table_ho:
+       ldx1    ho_to_bo,7      convert offset to bits
+       tra     mbt
+"
+make_bit_table_al:
+       eax1    0               zero offset
+"
+mbt:   epbpap  sp|0            get ptr to base of stack
+       eawpap  0,au            get ptr to bit table
+       stq     sp|char_lg1     save - length of string
+       fld     0,dl            zero out the bit table
+       staq    ap|0
+       staq    ap|2
+       lcq     sp|char_lg1
+       tze     log_exit                return if zero length string
+       stq     sp|char_lg1
+mbt_1: ldq     bp|0            get current word of string
+       lls     4,1             shift char to straddle aq, i.e. 00xx|yyyyy
+       qrl     4+9             put 5 bit index in qu
+       ana     3,dl            get 2 bit word index in al
+       ldq     single_bit,qu   get single bit at right position
+       orsq    ap|0,al         insert in bit table
+       aos     sp|char_lg1     count down
+       tze     log_exit                zero means we're done
+       adx1    9,du            update offset
+       cmpx1   36,du           do we need another word
+       tmi     mbt_1           no, finish this one
+       eax1    0               yes, set offset to zero
+       eppbp   bp|1            update for next word
+       tra     mbt_1           and repeat
+"
+"      operators to make bit table for use by search builtin function
+"      entered with point to string in bp, offset in x7, size in q, and
+"      stack offset of bit table in au.  The bit table constructed by
+"      these operators are the complement of that constructed by
+"      the make_bit_temp operator.
+"
+form_bit_table:
+       eax1    0,7             get offset
+       tra     fbt
+"
+form_bit_table_co:
+       ldx1    co_to_bo,7      convert offset to bits
+       tra     fbt
+"
+form_bit_table_ho:
+       ldx1    ho_to_bo,7      convert offset to bits
+       tra     fbt
+"
+form_bit_table_al:
+       eax1    0               zero offset
+"
+fbt:   epbpap  sp|0            get ptr to base of stack
+       eawpap  0,au            get ptr to bit table
+       stq     sp|char_lg1     save - length of string
+       ldaq    mask_bit
+       staq    ap|0            init table to all 1s
+       staq    ap|2
+       lcq     sp|char_lg1
+       tze     log_exit                return of zero length string
+       stq     sp|char_lg1
+fbt_1: ldq     bp|0            get current word of string
+       lls     4,1             shift char to straddle aq, i.e. 00xx|yyyyy
+       qrl     4+9             put 5 bit index in qu
+       ana     3,dl            get 2 bit word index in al
+       ldq     single_bit,qu   get single 1 bit at right position
+       erq     ones            convert to single 0 in right position
+       ansq    ap|0,al         erase bit in bit table
+       aos     sp|char_lg1     cont down
+       tze     log_exit                zero means done
+       adx1    9,du            update offset
+       cmpx1   36,du           do we need another word
+       tmi     fbt_1           no, ifnish this one
+       eax1    0               yes, set offset to zero
+       eppbp   bp|1            update for next word
+       tra     fbt_1           and repeat
+"
+"      operators to verify|search a string with bit table stored in stack.
+"      entered with pointer to string in bp, offset in x7, size in q,
+"      and tack offset of bit table in au.
+"
+verify:        eax1    0,7             get offset
+       tra     ver_1
+"
+verify_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     ver_1
+"
+verify_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     ver_1
+"
+verify_al:
+       eax1    0               zero offset
+ver_1: epbpap  sp|0            get ptr to bit table
+       eawpap  0,au            ..
+       tra     ver_3           join common section
+"
+"      operators to verify|search a string with constant bit table.
+"      entered with pointer to string in bp, offset in x7, size in q,
+"      and text offset of bit table in au.
+"
+const_verify:
+       eax1    0,7             get offset
+       tra     ver_2
+"
+const_verify_co:
+       ldx1    co_to_bo,7      convert to bit offset
+       tra     ver_2
+"
+const_verify_ho:
+       ldx1    ho_to_bo,7      convert to bit offset
+       tra     ver_2
+"
+const_verify_al:
+       eax1    0               zero offset
+ver_2: eppap   sp|tbp,*au      get ptr to bit table
+"
+ver_3: stq     sp|char_lg1     save - length of string
+       lcq     sp|char_lg1
+       tze     log_exit                return zero if zero length
+       stq     sp|lg2
+ver_4: ldq     bp|0            get current word of string
+       lls     4,1             shift char to straddle aq, i.e. 00xx|yyyyy
+       qrl     4+9             put 5 bit index yyyyy in qu
+       ana     3,dl            get 2 bit word index in al
+       lda     ap|0,al         get word from bit table
+       als     0,qu            shift to get bit into sign position
+       tpl     ver_fail                plus means char from string not in class
+       aos     sp|lg2          char ok, update for next
+       tze     ver_done
+       adx1    9,du            update shift amount
+       cmpx1   36,du           do we need another word
+       tmi     ver_4           no, repeat
+       eax1    0               yes, zero shift
+       eppbp   bp|1            update word pointer
+       tra     ver_4           and repeat
+ver_done:      ldq     0,dl            all chars in class, return zero
+       tra     log_exit
+ver_fail:      eppap   sp|stack_frame.operator_ptr,*   restore ptr to operator table
+       ldq     sp|lg2          exit with index of char that failed
+       adq     sp|char_lg1
+       adq     1,dl
+       tra     sp|tbp,*0
+"
+"      operators to do search|verify(s1,s2)
+"      entered with bp -> s1, ab -> s2, length(s1) in q, length(s2) in a
+"
+search_eis:
+       eax1    0               set to do ttf
+       stq     sp|char_lg1     save length of s1
+       ldq     1,dl            init loop
+search_loop:
+       cmpq    sp|char_lg1     are we done
+       tpnz    search_fail     yes, return
+       scm     (ar+rl),(ar+q)
+       desc9a  ab|0,al
+       desc9a  bp|-1(3),0
+       arg     sp|t4
+       xec     ttf_ttn,1               did we hit char
+       adq     1,dl            keep looking
+       tra     search_loop
+search_fail:
+       ldq     0,dl            return 0
+       tra     sp|tbp,*0
+search_done:
+       cmpq    0,dl            set indicators
+       tra     sp|tbp,*0               and exit
+"
+ttf_ttn:
+       ttf     search_done
+       ttn     search_done
+"
+verify_eis:
+       eax1    1
+       tra     search_eis+1
+"
+"      Reverse versions of above
+"
+verify_rev_chars:
+       eax1    1
+       tra     *+2
+search_rev_chars:
+       eax1    0
+       stq     sp|lg2          for later computation
+search_rev_loop:
+       sblq    1,dl
+       tmi     search_fail
+       scm     (ar+rl),(ar+q)
+       desc9a  ab|0,al
+       desc9a  bp|0
+       arg     sp|t4
+       xec     rev_ttf_ttn,1
+       tra     search_rev_loop
+
+rev_ttf_ttn:
+       ttf     rev_search_done
+       ttn     rev_search_done
+rev_search_done:
+       stq     sp|temp
+       ldq     sp|lg2
+       sblq    sp|temp
+       tra     sp|tbp,*0
+"
+"      verify operators for trim bifs entered as above
+"
+verify_for_ltrim:              "returns offset of 1st char not in str2 scanning from left
+       stq     sp|char_lg1     save length of str1
+       ldq     0,dl            init loop (we want offset, rather than pl1 verify index)
+vfl_loop:
+       cmpq    sp|char_lg1     are we done?
+       tpl     search_done     yes, return
+       scm     (ar+rl),(ar+q)
+       desc9a  ab|0,al
+       desc9a  bp|0,1
+       arg     sp|t4
+       ttn     search_done     are we past chars to be trimmed?
+       adq     1,dl            no, keep looking
+       tra     vfl_loop
+"
+verify_for_rtrim:              "equivalent to verify_for_ltrim(reverse(...
+       cmpq    0,dl            exit if zero
+       tze     sp|tbp,*0
+       stq     sp|char_lg1     save length(str1)
+vfr_loop:
+       scm     (ar+rl),(ar+q)
+       desc9a  ab|0,al
+       desc9a  bp|-1(3),1
+       arg     sp|t4
+       ttn     vfr_done                have we gone past chars to be trimmed?
+       sbq     1,dl            no, keep looking
+       tpnz    vfr_loop
+vfr_done:
+       erq     ones            subtract from length(str1)
+       adq     1,dl            ..
+       adq     sp|char_lg1     ..
+       tra     sp|tbp,*0
+"
+"      operator to perform translate(s,r) with string s previously set up
+"      entered with pr2 -> r and length(r) in q
+"
+translate_2:
+       stq     sp|temp         save length of r
+       spri3   sp|temp2
+       epp3    bp|0            save ptr to r
+       ldq     sp|char_lg1     get length(s)
+       adq     3+8,dl          allocate temp of proper size
+       qrs     2
+       tsx1    alloc
+       eppap   sp|temp_pt,*    get ptr to s
+       eppbp   bp|2            skip over temp header
+       spribp  sp|temp_pt      save ptr to temp
+       ldq     sp|char_lg1     get length(s)
+trans2_loop:
+       sbq     1,dl            do next char (backwards)
+       tmi     trans_done      exit if done
+       mrl     (ar+ql),(ar)    isolate next character with leading zeros
+       desc9a  ap|0,1
+       desc9a  sp|num,4
+       lda     sp|num          get character from s
+       cmpa    sp|temp         check against length of r
+       tpl     trans2_blank    use blank if out of string
+       mlr     (ar+al),(ar+ql) move replacement to target
+       desc9a  bb|0,1
+       desc9a  bp|0,1
+       tra     trans2_loop
+trans2_blank:
+       mlr     (0),(ar+ql),fill(blank) move in fill(blank)
+       zero
+       desc9a  bp|0,1
+       tra     trans2_loop
+trans_done:
+       epp3    sp|temp2,*
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+"      operator to perform translate(s,r,p) with string s previously set up
+"      entered with pr1 -> p, pr2 -> r, length(p) in a, and length(r) in q
+"
+translate_3:
+       staq    sp|temp         save lengths
+       spri3   sp|temp2
+       epp3    bp|0            save ptr to r
+       ldq     sp|char_lg1     get length(s)
+       adq     3+8,dl          allocate temp of proper size
+       qrs     2
+       tsx1    alloc
+       eppap   sp|temp_pt,*    get ptr to s
+       eppbp   bp|2            skip over temp header
+       spribp  sp|temp_pt      save ptr to temp
+       ldq     sp|char_lg1     get length(s)
+trans3_loop:
+       sbq     1,dl            do next char (backwards)
+       tmi     trans_done      exit if done
+       lda     sp|temp         get length(p)
+       scm     (ar+rl),(ar+ql) is this char of s in p?
+       desc9a  ab|0,al
+       desc9a  ap|0,0
+       arg     sp|num
+       ttn     trans3_same     tally on means not found, use same char
+       lda     sp|num          get number of chars skipped
+       cmpa    sp|temp+1               check against length(r)
+       tpl     trans3_blank    use blank if out of range
+       mlr     (ar+al),(ar+ql) replace with char from r
+       desc9a  bb|0,1
+       desc9a  bp|0,1
+       tra     trans3_loop
+trans3_blank:
+       mlr     (0),(ar+ql),fill(blank) move in fill(blank)
+       zero
+       desc9a  bp|0,1
+       tra     trans3_loop
+trans3_same:
+       mlr     (ar+ql),(ar+ql) move in char from s
+       desc9a  ap|0,1
+       desc9a  bp|0,1
+       tra     trans3_loop
+"
+"      operator to implement return(*) for unpacked values
+"      entered with pointer to return value in bp, number of
+"      words to return in q, and number of begin blocks to
+"      skip over in x0
+"
+return_words:
+       tsx2    return_pop      pop stack back
+"
+"      the sp has now been put back to old frame to which we are returning,
+"      ap points at the destination of the data being returned.  The old stack
+"      frame has been extended to include the stack frame from which we are
+"      returning.
+"
+rw_0:  qls     2               get number of chars to move
+       tze     rw_1            skip if zero (prevent IPR)
+       mlr     (ar+rl),(ar+rl)
+       desc9a  bp|0,ql
+       desc9a  ap|0,ql
+rw_1:  ldq     sp|count                get back number of words
+       qls     18              in upper
+       adlq    17,du           make a multiple of 16 (allow for extra words)
+       anq     =o777760,du
+       eax0    ap|-2,qu                get offset of end of stack
+       stx0    sp|stack_frame.next_sp+1 and update old frame
+       stx0    sb|stack_header.stack_end_ptr+1 and stack end ptr
+       eppap   sp|stack_frame.operator_ptr,* reset pointer to caller's operators
+       ldi     sp|stack_frame.return_ptr+1 restore indicators
+       rtcd    sp|stack_frame.return_ptr now return to old procedure
+"
+"      operator to implement return(*) for packed values and bit strings
+"      entered with pointer to return value in bp, number of
+"      bits to move in q, and offset in x7, and number of begin
+"      blocks to skip over in x0
+"
+return_bits:
+       eax1    0,7             get bit offset
+       tra     rba
+"
+return_bits_co:
+       ldx1    co_to_bo,7      get bit offset
+       tra     rba
+"
+return_bits_ho:
+       ldx1    ho_to_bo,7      get bit offset
+       tra     rba
+"
+return_bits_al:
+       eax1    0               get zero offset
+"
+rba:   adwpbp  0,du            erase bit offset
+       abd     bp|0,1          add new bit offset
+"
+return_bits_eis:
+       stq     sp|bit_lg1      save number of bits to move
+       adq     35,dl           compute number of words
+       div     36,dl
+       lda     sp|bit_lg1      get number of units moved
+       tsx2    return_pop      pop stack back
+"
+"      the sp now points at stack frame to which we are returning, this frame
+"      has been extended to include the frame we are leaving.  ap points at
+"      destination of return value.
+"
+       ldq     ap|-1           get back bit length
+       tze     rw_1            skip if zero (prevent IPR)
+       csl     (ar+rl),(ar+rl),bool(move)
+       descb   bp|0,ql
+       descb   ap|0,ql
+       tra     rw_1
+"
+"      operator to implement return(*) for char strings
+"      entered with pointer to return value in bp, number of chars in q,
+"      offset in x7, and number of begin blocks to skip over in x0
+"
+return_chars:
+       eax1    0,7             get bit offset
+       tra     rca
+"
+return_chars_co:
+       ldx1    co_to_bo,7      get bit offset
+       tra     rca
+"
+return_chars_ho:
+       ldx1    ho_to_bo,7      get bit offset
+       tra     rca
+"
+return_chars_aligned:
+       eax1    0               get zero offset
+"
+rca:   adwpbp  0,du            erase bit offset
+       abd     bp|0,1          add neew bit offset
+"
+return_chars_eis:
+       stq     sp|char_lg1     save number of chars to move
+       adq     3,dl            compute number of words
+       qrs     2
+       lda     sp|char_lg1     get number of units moved
+       tsx2    return_pop
+       ldq     ap|-1           get back number of chars
+       tra     rw_0+1          and go move them
+"
+"      subroutine to reset stack frame for return(*) operators
+"      entered with number of words in q
+"      and number of units (bits|chars) in a
+"
+return_pop:
+       epplp   sp|0            get ptr to frame of proc from which
+       cmpx0   0,du            we are returning
+       tze     4,ic
+       epplp   lp|stack_frame.prev_sp,*
+       sbx0    1,du
+       tpnz    -2,ic
+"
+       eppab   lp|stack_frame.arg_ptr,* get ptr to our arglist
+       ldx3    ab|0            get head, 2*n_args
+"
+       eppab   ab|0,3*         get ptr to return arg
+"
+       epplp   lp|stack_frame.prev_sp,*        get ptr to frame to which we are going
+"
+       stq     sp|count                save # words in old frame
+       eppap   lp|stack_frame.next_sp,*        get ptr to destination
+       eppap   ap|2            skip 2 words to allow for varying return value
+       spriap  ab|0            set return ptr for last arg
+       sta     ap|-1           set varying length
+       epaq    sp|0            get seg no of current stack
+       sta     sp|temp         save it
+       epaq    lp|0            get seg no of stack we are returning to
+       cmpa    sp|temp         same stack?
+       tze     same_stack      yes
+       lda     sp|count                get # of words to move
+       als     18              in upper
+       adla    17,du           make 0 mod 16 (allow for 2 extra words)
+       ana     =o777760,du     ..
+       eax0    ap|-2,au                get offset of new stack frame end
+       stx0    lp|stack_frame.next_sp+1 update next sp of the frame
+       epbplb  lp|0            get pointer to base of stack we are returning to
+       stx0    lb|stack_header.stack_end_ptr+1 update stack end pointer
+       tra     different_stack join rest of code
+same_stack:
+       ldaq    sp|stack_frame.next_sp get next ptr of frame we're leaving
+       staq    lp|stack_frame.next_sp set next of old to include all of this frame
+different_stack:
+       ldq     sp|count                get back # of words to move
+       eppsp   lp|0            pop stack
+       epbpsb  sp|0            set up stack base in case we switched stacks
+       stq     sp|count                save of words in new stack frame
+       tra     0,2             return with ap -> dest, # units in q
+
+"
+"      operator to leave a begin block.
+"
+leave_begin_block:
+       odd
+       epbpsb  sp|0            get ptr to base of stack
+       even                    "see note at label 'alm_return'
+       sprisp  sb|stack_header.stack_end_ptr reset stack end ptr
+       eppsp   sp|stack_frame.prev_sp,* pop the stack
+       tra     sp|tbp,*0               return to pl1 program
+"
+"      operator to free fortran storage and then do a procedure return
+"
+fort_return_mac:
+       spri6   sp|double_temp  save sp as owner to fortran_storage_manager_
+       epp2    sp|double_temp
+       spri2   sp|arg_list+2   argument 1 - stack pointer
+       lda     2,du            nargs = 1, quick call (no enviptr)
+       ldq     0,dl            no descriptors
+       staq    sp|arg_list
+       epp0    sp|arg_list     get argument list header
+       epp2    return_mac      return to return
+       spri2   sp|stack_frame.return_ptr       save return point
+       tsx1    get_our_lp
+       callsp  fortran_storage_manager_$free
+"
+"      operator to do a procedure return from inside a begin block.
+"      entered with number of nested begin blocks in ql.
+"
+begin_return_mac:
+       tze     return_mac      skip if begin block is quick
+       epbpsb  sp|0            get ptr to base of stack
+       inhibit on
+       sprisp  sb|stack_header.stack_end_ptr keep updating end ptr
+       eppsp   sp|stack_frame.prev_sp,* pop stack
+       inhibit off
+       sbq     1,dl            count down number of blocks
+       tnz     -3,ic           repeat until all done
+"
+"      operator to do a procedure return
+"
+return_mac:
+       epbpsb  sp|0            get ptr to base of stack
+       inhibit on
+       sprisp  sb|stack_header.stack_end_ptr reset stack end pointer
+       eppsp   sp|stack_frame.prev_sp,* pop stack
+       inhibit off
+       epbpsb  sp|0            set sb up in case we just switched stacks
+       eppap   sp|stack_frame.operator_ptr,* set up operator pointer
+       ldi     sp|stack_frame.return_ptr+1     restore indicators for caller
+       rtcd    sp|stack_frame.return_ptr continue execution after call
+"
+"      operators to call an entry variable
+"      entered with pointer to entry in bp and number
+"      of arguments in position in a, offset of arg list is in x1
+"
+call_ent_var_desc:
+       eaq     0,au            there are descriptors
+"
+call_ent_var:
+       sti     sp|stack_frame.return_ptr+1     save indicators
+       ora     8,dl            insert pl1 code
+       epbpsb  sp|0            get ptr to base of stack
+       staq    sb|0,1          save at head of list
+       stx0    sp|stack_frame.return_ptr+1 set offset of return point
+       epplp   bp|2,*          get display pointer
+       eppbp   bp|0,*          and ptr to entry
+save_display:
+       eppap   sb|0,1          get ptr to arg list
+       sprilp  ap|2,au         store display ptr at end
+       epplp   sp|linkage_ptr,*        restore ptr to linkage segment
+var_call:
+       callsp  bp|0            and transfer to entry
+"
+"      operator to call an external procedure (same or diff seg).
+"      entered with pointer to entry in bp and number of args
+"      in position in a, offset of arg list is in x1
+"
+call_ext_in_desc:
+call_ext_out_desc:
+       eaq     0,au            there are descriptors
+"
+call_ext_in:
+call_ext_out:
+       sti     sp|stack_frame.return_ptr+1     save indicators
+       epbpsb  sp|0            get ptr to base of stack
+       ora     4,dl            insert pl1 code (do this for now)
+       staq    sb|0,1          save at head of list
+       stx0    sp|stack_frame.return_ptr+1 set offset of return point
+       eppap   sb|0,1          get pointer to arg list
+       epplp   sp|linkage_ptr,*        reload ptr to linkage segment
+"
+"      This label is 'segdef'ed but is never transfered to directly. The segdef is
+"      merely to allow default_error_handler to see if a fault occured as a result
+"      of this particular instruction so that it can print a more informative
+"      error message.
+"
+forward_call:
+       callsp  bp|0            transfer to entry
+"
+"      operator to call an internal procedure defined in the
+"      same block as the call.  entered with pointer to entry in
+"      bp and number of args in position in a.
+"
+call_int_this_desc:
+       eaq     0,au            there are descriptors
+"
+call_int_this:
+       sti     sp|stack_frame.return_ptr+1     save indicators
+       ora     8,dl            insert pl1 code
+       epbpsb  sp|0            get ptr to base of stack
+       staq    sb|0,1          save at head of list
+       stx0    sp|stack_frame.return_ptr+1 save offset of return point
+       eppap   sb|0,1          get pointer to arg list
+       sprisp  ap|2,au         save display pointer
+       tra     bp|0            transfer to entry
+"
+"      operator to call an interal procedure defined K blocks
+"      above the call.  entered with pointer to entry in bp,
+"      K in x7, and number of args in position in aq.
+"
+call_int_other_desc:
+       eaq     0,au            there are descriptors
+"
+call_int_other:
+       sti     sp|stack_frame.return_ptr+1     save indicators
+       ora     8,dl            insert pl1 code
+       epbpsb  sp|0            get ptr to base of stack
+       staq    sb|0,1          save at head of list
+       stx0    sp|stack_frame.return_ptr+1 save return point
+       epplp   sp|display_ptr,*        walk back K levels
+       eax7    -1,7            ..
+       tze     save_display    then go save display
+       epplp   lp|display_ptr,*        take another step
+       tra     -3,ic           and check again
+"
+"      operator to move the label variable pointed at by sp|temp_pt
+"      into the label variable pointed at by bp
+"
+move_label_var:
+       ldaq    sp|temp_pt,*    move first two words
+       staq    bp|0            ..
+       eax1    2               and second two words
+       ldaq    sp|temp_pt,*1   ..
+       staq    bp|2            ..
+       tra     sp|tbp,*0               return to pl1 program
+"
+"      operator to make a label variable in the stack.  entered
+"      with pointer to label in bp, number of static blocks to walk
+"      back in q.  sp|temp_pt is set to point to the label variable
+"
+make_label_var:
+       spribp  sp|label_var    save pointer to label
+       tsx1    display_chase   get pointer to stack frame
+       spribp  sp|label_var+2  and save in label var
+       eppbp   sp|label_var    get pointer to label var
+       spribp  sp|temp_pt      set temp_pt
+       tra     sp|tbp,*0               return to pl1 program
+"
+"      subroutine to walk N levels back along the display chain.
+"      entered with N in q register, exit with pointer in bp.
+"      NB: indicators must be set from q register at time of entry.
+"
+display_chase:
+       eppbp   sp|0            get pointer to current frame
+       tze     0,1             return if N = 0
+       eppbp   bp|display_ptr,*        take a step back the chain
+       sbq     1,dl            and decrease count
+       tra     -3,ic           and check again
+"
+"      operator to form mod(fx1,fx1)
+"      entered with first arg in q, bp pointing at second
+"
+mdfx1: szn     bp|0            if divisor is zero, return with dividend
+       tze     search_done     go set indicators from q and exit
+       stq     sp|temp         save first arg
+       div     bp|0            get remainder
+       tnz     3,ic            skip if quotient non-zero
+       ldq     sp|temp         zero quotient, set q to sign of
+       erq     bp|0            quotient
+       tpl     mdfx1a          skip if quotient sign +
+       cmpa    0,dl            don't correct if remainder 0
+       tze     mdfx1a
+       ada     bp|0            negative quotient, correct remainder
+mdfx1a:        lrs     36              shift remainder to q
+       tra     sp|tbp,*0               and return
+"
+"      operator to form mod(fx1,fx2)
+"      entered with first arg in q, bp pointing at second
+"
+mdfx2: lls     36              convert to double precision
+       lrs     36              and join mdfx4
+"
+"      operator to form mod(fx2,fx2)
+"      entered with first arg in q, bp pointing at second
+"
+mdfx4: sreg    sp|save_regs    save registers including aq
+       ldaq    bp|0            return 1st arg if second is zero
+       tze     use_first
+       spri1   sp|temp_pt      save ab
+       epp1    sp|save_regs+4  get ptr to first arg
+       ldq     0,dl            load scaling amount
+       tsx7    divide2         generate remainder
+       cmpx1   0,du            check sign of quotient
+       tze     mdfx4a+1                skip if quotient +
+       ldaq    sp|remainder    correct remainder if it is non-zero
+       tze     2,ic
+       adaq    bp|0
+mdfx4a:        staq    sp|remainder
+       lreg    sp|save_regs    restore registers
+       epp1    sp|temp_pt,*    restore ab
+       ldaq    sp|remainder    get result
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0               and exit
+"
+"      operator to form mod(fx2,fx1)
+"      entered with first arg in q, bp pointing at second
+"
+mdfx3: sreg    sp|save_regs    save registers, including aq
+       lda     bp|0            get divisor
+       tze     use_first               use first arg as result if divisor zero
+       spri1   sp|temp_pt
+       epp1    sp|save_regs+4  get ptr to dividend
+       ldq     0,dl            get scale amount
+       tsx7    divide1         get remainder
+       cmpx1   0,du            check sign of quotient
+       tze     mdfx4a+1
+       ldaq    sp|remainder    correct remainder when quotient neg
+       tze     2,ic            and remainder non-zero
+       adl     bp|0
+       tra     mdfx4a
+"
+"      operator to form mod(fx1,fx2) with non-zero scales
+"      entered with dividend in q, pr2 -> divisor, and
+"      scales following tsx0
+"
+scaled_mod_fx2:
+       lls     36              convert to double precision
+       lrs     36              and join scaled_mod_fx4
+"
+"      operator to form mod(fx2,fx2) with non-zero scales
+"      entered with dividend in aq, pr2 -> divisor, and
+"      scale(dividend) & scale(divisor) following tsx0
+"
+scaled_mod_fx4:
+       adx0    2,du            skip over the two scale words
+       sreg    sp|save_regs    save all registers
+       ldaq    bp|0            get divisor
+       tze     use_first               zero means use dividend as value
+       sprp2   sp|temp_pt+1
+"
+sc_mod_common:
+       sprp1   sp|temp_pt
+       eppap   sp|tbp,*0               get ptr to just after scale words
+       ldq     ap|-1           get scale of divisor
+       sbq     ap|-2           - scale of dividend
+       tmi     scmd3           skip if scale(divisor) < scale(dividend)
+"
+"      scale of dividend <= scale of divisor.  let the divide routine
+"      shift the dividend left by the amount in the q register.
+"
+scmd1: epp1    sp|save_regs+4  get ptr to dividend
+       tsx7    divide2         divide
+       cmpx1   0,du            check quotient sign
+       tze     scmd2           skip if positive
+       ldaq    sp|remainder    dont't correct remainder if it is zero
+       tze     scmd2
+       adaq    bp|0            add divisor to correct remainder
+       staq    sp|remainder
+scmd2: lprp1   sp|temp_pt      restore pointers
+       lprp2   sp|temp_pt+1
+       lreg    sp|save_regs    and registers
+       ldaq    sp|remainder    get remainder from the division
+       tra     log_exit                and exit
+"
+"      scale of divisor < scale of dividend, shift divisor
+"      left by negative of number of places in q register.
+"      if the carry indicator is on at the end of the shift, the
+"      division would yield a zero quotient, so the remainder
+"      is the dividend with appropriate sign consideration.
+"
+scmd3: stq     sp|count                get positive shift amount
+       lcq     sp|count
+       eax1    0,ql
+       ldaq    bp|0            get back the divisor
+       lls     0,1             shift it
+       trc     scmd4           skip if divisor too big
+       staq    sp|bit_lg1      save value temporarily
+       epp2    sp|bit_lg1      get ptr to shifted divisor
+       ldq     0,dl            don't shift dividend
+       tra     scmd1           go do the division
+"
+"      the division (with both args treated as integers since the scales
+"      are now lined up), would give a zero quotient.  if the signs of
+"      the two arguments are the same, the value of the function is the
+"      value of the dividend--otherwise, we have to signal fixedoverflow
+"
+scmd4: era     sp|save_regs+4  check signs of two arguments
+       ana     =o400000,du
+       tze     use_first               zero means signs the same
+       tsx7    signal_overflow
+       tra     use_first
+"
+"      operator to form mod(fx1,fx1) with non-zero scales
+"      entered with dividend in aq, pr2 -> divisor, and scales
+"      following tsx0
+"
+scaled_mod_fx1:
+       lls     36              convert to double precision
+       lrs     36              and join scaled_mod_fx3
+"
+"      operator to form mod(fx2,fx1) with non-zero scales
+"      entered with dividend in q, pr2 -> divisior, and scales
+"      following tsx0
+"
+scaled_mod_fx3:
+       adx0    2,du            skip over the two scale words
+       sreg    sp|save_regs    save all registers
+       lda     bp|0            get divisor
+       tze     use_first               zero means use dividend as value
+       sprp2   sp|temp_pt+1
+       lrs     36              form double precision divisor
+       staq    sp|bit_lg1      save new divisior
+       epp2    sp|bit_lg1      and get ptr to it
+       tra     sc_mod_common
+"
+"      operator to divide single precision by single precision
+"      entered with dividend in q and pr2 -> divisor, and amount
+"      to scale result following tsx0
+"
+divide_fx1:
+       lls     36              convert to double precision
+       lrs     36              and join divide_fx3
+"
+"
+"      operator to divide double precision by single precision
+"      entered with dividend in aq, pr2 -> divisor, and amount
+"      to scale result (+ left, - right) following tsx0
+"
+divide_fx3:
+       sreg    sp|save_regs
+       spri1   sp|temp_pt      save ab
+       epp1    sp|save_regs+4  get ptr to dividend
+       lda     bp|0            load divisor
+       ldq     sp|tbp,*0               load scale amount
+       tsx7    divide1         do the division
+dv_done:
+       staq    sp|save_regs+4  save quotient
+       lreg    sp|save_regs    restore registers
+       adx0    1,du            update return pt
+       epp1    sp|temp_pt,*    restore ab
+       eppap   sp|stack_frame.operator_ptr,*
+       cmpaq   bit_mask                set indicators
+       tra     sp|tbp,*0               and exit
+"
+"      operator to divide single precision by double precision
+"      entered with dividend in q, pr2 -> divisor, and
+"      amount to scale result following tsx0
+"
+divide_fx2:
+       lls     36              convert to double precision
+       lrs     36              and join divide_fx3
+"
+"
+"      operator to divide double precision by double precision
+"      entered with dividend in aq, pr2 -> divisor, and amount
+"      to scale result following tsx0
+"
+divide_fx4:
+       sreg    sp|save_regs
+       spri1   sp|temp_pt      save ab
+       epp1    sp|save_regs+4  get ptr to dividend
+       ldq     sp|tbp,*0
+       tsx7    divide2
+       tra     dv_done
+"
+"      operator to divide double precision by double precision
+"      same calling sequence as divide_fx4 except scale is
+"      in index 1.  Called from fixed_ops_.
+"
+div_4_cplx_ops:
+       sreg    sp|save_regs    save regs
+       epp1    sp|save_regs+4  get ptr to dividend
+       eaq     0,1             get scale into q
+       qrs     18              ""
+       tsx7    divide2         perform division
+       staq    sp|save_regs+4  save quotient
+       lreg    sp|save_regs    restore regs
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+"      internal procedure to divide double precision integer by
+"      single precision integer.  entered with divisor in a,
+"      pr1 -> dividend, and scale in q
+"      returns quotient in aq and remainder in sp|remainder
+"
+divide1:       tsx1    divide_extension        extend stack
+       stq     ap|shift                save scaling amount
+       eax1    0               save sign of divisor
+       lrs     36
+       tpl     3,ic
+       negl    0
+       erx1    1,du
+       tra     div_single
+"
+"      internal procedure to divide two double precision integers
+"      entered with pr1 -> dividend, pr2 -> divisor, scale amount in q
+"      returns quotient in aq and remainder in sp|remainder
+"
+divide2:       tsx1    divide_extension        extend stack
+       stq     ap|shift                save scaling amount
+       eax1    0               assume positive result
+       ldaq    bp|0            get divisor
+       tpl     3,ic
+       negl    0
+       erx1    1,du
+       cmpaq   max_single_value
+       tmoz    div_single
+       cana    =o200000,du     is high bit of divisor on
+       tnz     divisor_3               yes, need 3 words
+"
+"      divisor only needs 2 words
+"
+       sti     sp|temp_indicators      save indicators
+       ldi     0,dl            clear HFP mode if it's set
+       lde     =0,du           count leading zeros
+       fad     =0.0,du
+       ldi     sp|temp_indicators      restore indicators
+       qrl     1               split number into two parts
+       stq     ap|divisor+1
+       sta     ap|divisor+2
+       ste     ap|div_temp     get number of leading zeros
+       lda     ap|div_temp
+       ars     28
+       neg     0               make it positive
+       sba     1,dl
+       eax4    2               set length of number
+       tra     prepare_dividend
+"
+"      divisor requires 3 words
+"
+divisor_3:
+       sta     ap|divisor+3    store high order word
+       lls     34+1            shift other parts 34 bits
+       qrl     1               and save
+       stq     ap|divisor+1
+       ana     max_single_value+1
+       sta     ap|divisor+2
+       lda     34,dl           shift is 34
+       eax4    3               and length is 3
+"
+prepare_dividend:
+       sta     ap|norm_shift   save scaling count
+       asa     ap|shift                update shift by number of leading zeros
+       stx4    ap|divisor      save length of divisor
+       ldaq    ab|0    
+       tpl     3,ic
+       negl    0
+       erx1    1,du
+       tsx3    shift_dividend
+       adx5    1,du
+       stz     ap|dividend,5   add zero chunk at front
+       stx5    ap|dividend     save number of chunks
+       fld     0,dl
+       staq    ap|quotient
+       staq    ap|quotient+2
+       staq    ap|quotient+4
+       eax6    0,5             quotient length =
+       sbx6    ap|divisor      dividend_length - divisor_length
+       tze     done            skip if zero quotient length
+"
+get_qhat:
+       ldx5    ap|dividend     calculate quotient guess
+       lda     ap|dividend,5
+       cmpa    ap|divisor,4
+       tmi     div_less
+       ldq     max_single_value+1      =o377777777777
+       lda     ap|dividend-1,5
+       tra     l3h
+dec_qhat:
+       ldq     ap|qhat
+       sbq     1,dl
+       lda     ap|rhat
+l3h:   stq     ap|qhat
+       adla    ap|divisor,4
+       tmi     got_qhat
+       sta     ap|rhat
+       tra     got_rhat
+div_less:
+       ldq     ap|dividend-1,5
+       qls     1
+       dvf     ap|divisor,4
+       sta     ap|qhat
+       stq     ap|rhat
+got_rhat:
+       ldq     ap|qhat
+       mpy     ap|divisor-1,4
+       lls     1
+       cmpa    ap|rhat
+       tmi     got_qhat
+       tnz     dec_qhat
+       qrl     1
+       cmpq    ap|dividend-2,5
+       tmi     got_qhat
+       tnz     dec_qhat
+got_qhat:
+       eax3    0               do multiply and subtract
+       stz     ap|carry
+       stz     ap|carrya
+       sbx5    ap|divisor
+       epplp   ap|dividend,5
+div_loop:
+       eax3    1,3
+       ldq     ap|divisor,3
+       mpy     ap|qhat
+       adl     ap|carry
+       lls     1
+       qrl     1
+       stq     ap|div_temp
+       sta     ap|carry
+       ldq     lp|-1,3
+       sblq    ap|carrya
+       sblq    ap|div_temp
+       lda     0,dl
+       lls     1
+       qrl     1
+       stq     lp|-1,3
+       sta     ap|carrya
+       cmpx3   ap|divisor
+       tnz     div_loop
+       eax3    1,3
+       ldq     lp|-1,3
+       sblq    ap|carrya
+       sblq    ap|carry
+       lda     0,dl
+       lls     1
+       qrl     1
+       stq     lp|-1,3
+       cmpa    0,dl
+       tze     store_q
+       lcq     1,dl
+       asq     ap|qhat
+       eax3    0
+       lda     0,dl
+div_loop1:
+       eax3    1,3             add back in
+       ldq     lp|-1,3
+       adlq    zero_one,al
+       adlq    ap|divisor,3
+       lda     0,du
+       lls     1
+       qrl     1
+       stq     lp|-1,3
+       cmpx3   ap|divisor
+       tnz     div_loop1
+       eax3    1,3
+       ldq     lp|-1,3
+       adlq    zero_one,al
+       lls     1
+       qrl     1
+       stq     lp|-1,3
+"
+store_q:
+       lda     ap|qhat
+       sta     ap|quotient,6
+       eax3    -1
+       asx3    ap|dividend
+       eax6    -1,6
+       tpnz    get_qhat
+"
+"      done
+"
+done:  ldq     ap|dividend+2   assemble remainder
+       qls     1
+       lda     ap|dividend+3
+       lls     35
+       ldq     ap|dividend+1
+       qls     1
+       lrl     1
+       lxl6    ap|norm_shift   get amount we scaled divisor
+       lrl     0,6             shift back remainder
+l2:    szn     ab|0            set remainder sign to sign of dividend
+       tpl     2,ic
+       negl    0
+       staq    sp|remainder
+       ldq     ap|quotient+4   assemble quotient
+       adq     ap|quotient+5
+       tnz     signal_overflow
+       ldq     ap|quotient+2
+       qls     1
+       lda     ap|quotient+3
+       lls     35
+       trc     signal_overflow
+       ldq     ap|quotient+1
+       qls     1
+       lrl     1
+       xec     sign_change,1
+       epplp   ap|divide_lp,*  restore lp
+       lcx2    sp|qmask                return stack extension
+       ldx3    sp|stack_frame.next_sp+1
+       sblx3   divide_extension_size,du
+       stx3    sp|stack_frame.next_sp+1
+       stx3    sp|stack_header.stack_end_ptr+1,2
+       tra     0,7
+"
+signal_overflow:
+       spribp  sp|double_temp
+       eppbp   overflow_name
+       eax6    overflow_length
+       ldq     =711,dl
+       sxl0    sp|stack_frame.operator_ret_ptr
+       tsx1    call_signal_
+       eppbp   sp|double_temp,*
+       lxl0    sp|stack_frame.operator_ret_ptr
+       stz     sp|stack_frame.operator_ret_ptr
+       ldaq    mask_bit+2
+       tra     0,7
+"
+overflow_name:
+       aci     "fixedoverflow"
+"
+       equ     overflow_length,13
+
+"
+div_single:
+       stq     ap|divisor
+       ldaq    ab|0    
+       tpl     3,ic
+       negl    0
+       erx1    1,du
+       tsx3    shift_dividend
+       fld     0,dl
+       staq    ap|quotient+2
+       staq    ap|quotient+4
+l1:    ldq     ap|dividend,5
+       qls     1
+       dvf     ap|divisor
+       sta     ap|quotient,5
+       eax5    -1,5
+       tze     thru
+       llr     36
+       tra     l1
+thru:  lda     0,dl
+       tra     l2
+"
+"      internal procedure to extend stack for divide operators
+"
+divide_extension:
+       eax2    sp|0            get offset of stack frame
+       stx2    sp|qmask
+       lcx2    sp|qmask                get - offset
+       eppap   sp|stack_header.stack_end_ptr,2*        get ptr to extension
+       eax3    divide_extension_size
+       adlx3   sp|stack_frame.next_sp+1
+       stx3    sp|stack_header.stack_end_ptr+1,2
+       stx3    sp|stack_frame.next_sp+1
+       sprilp  ap|divide_lp    save lp
+       tra     0,1
+"
+" This procedure shifts the dividend left (+) or right (-) the
+" number of places specified by variable shift.  It splits the shifted
+" value into chunks which are stored in dividend+1, dividend+2, ...
+" The number of chunks stored (which can never exceed 5) is returned in x5.
+" The routine is entered with |dividend| in AQ
+"
+shift_dividend:
+       lxl2    ap|shift
+       tmi     right_shift
+       staq    ap|div_temp
+       lls     0,2
+       trc     hard_shift      carry means lost a bit on left
+split: lls     1
+       qrl     1               split into chunks
+       stq     ap|dividend+1
+       eax5    1
+       lrl     35
+       tze     0,3
+       qrl     1
+       stq     ap|dividend+2
+       eax5    2
+       cmpa    0,dl
+       tze     0,3
+       sta     ap|dividend+3
+       eax5    3
+       tra     0,3
+hard_shift:
+       lls     1
+       qrl     1               store lower 2 chunks
+       stq     ap|dividend+1
+       lrl     35
+       qrl     1
+       stq     ap|dividend+2
+       ldaq    ap|div_temp     get back original value
+       sbx2    70,du           shift 70 places fewer
+       tpl     sl
+       stx2    ap|div_temp
+       lcx2    ap|div_temp
+       lrl     0,2
+       tra     sl+1
+sl:    lls     0,2
+       lls     1
+       qrl     1
+       stq     ap|dividend+3   will always be 3rd chunk
+       eax5    3
+       lrl     35
+       tze     0,3
+       qrl     1
+       stq     ap|dividend+4
+       eax5    4
+       cmpa    0,dl
+       tze     0,3
+       sta     ap|dividend+5
+       eax5    5
+       tra     0,3
+right_shift:
+       stx2    ap|div_temp
+       lcx2    ap|div_temp
+       lrl     0,2
+       tra     split
+"
+zero_one:      dec     0,1
+"
+sign_change:
+       nop     0,du
+       negl    0
+"
+"      operator to convert floating to fixed
+"
+fl2_to_fx1:
+fl2_to_fx2:
+       fad     =0.,du
+       tmi     3,ic
+       ufa     =71b25,du
+       tra     sp|tbp,*0
+       fneg
+       ufa     =71b25,du
+       negl
+       tra     sp|tbp,*0
+"
+"      operator to convert float to fixed scaled.  the word following
+"      the tsx0 is the encoded scale of the target
+"
+fl2_to_fxscaled:
+       fad     =0.,du
+       tmi     4,ic
+       ufa     sp|tbp,*0
+       adx0    1,du
+       tra     sp|tbp,*0
+       fneg
+       ufa     sp|tbp,*0
+       negl
+       tra     -5,ic
+"
+"      stac operator.  entered with word in a and pointer
+"      to destination in bp.
+"
+stac_mac:      stac    bp|0            store a conditionally
+       tze     true
+       lda     0,dl            ..
+       tra     sp|tbp,*0               and return
+"
+"      stacq operator.  entered with old value in Q, new value in A,
+"      and pointer to destination in pr2.
+"
+stacq_mac:
+       stacq   pr2|0           store A conditional C(storage) = Q
+       tze     true            stored OK, return "1"b
+       lda     0,dl            not stored, return "0"b
+       tra     sp|tbp,*0               return
+"
+"      clock operator.  no arguments...returns with value of
+"      calendar clock in AQ.
+"
+clock_mac:
+       get_our_lp
+       rccl    sys_info$clock_,*       read clock into AQ
+       cmpaq   bit_mask                set indicators
+       tra     sp|tbp,*0               return
+"
+"      virtual clock operator.  no arguments...returns with value
+"      of virtual cpu time in AQ.
+"
+vclock_mac:
+       get_our_lp
+       stx0    sp|stack_frame.return_ptr+1     setup to return directly to user prog
+       sti     sp|stack_frame.return_ptr+1     save indicators
+       callsp  virtual_cpu_time_op_$virtual_cpu_time_op_       invoke supervisor to do work
+"
+"
+"      stop operator, terminates a run unit by calling stop_run
+"
+stop:
+       eppap   sp|46                   get pointer to argument list
+       fld     0,dl                    create null argument list
+       ora     4,dl                         and insert PL/I code
+       staq    sp|46
+       get_our_lp
+       stcd    sp|stack_frame.return_ptr       store pointer to caller
+       callsp  stop_run$stop_run
+"
+"      return_main - terminates a run unit by calling stop_run  if the procedure is a main procedure,
+"                         otherwise it performs a normal return
+"
+return_main:
+       lda     sp|stack_frame.flag_word
+       ana     stack_frame.main_proc_bit,dl
+       tze     return_mac
+       tra     stop
+"
+"      return from a begin block in a main procedure
+"
+begin_return_main:
+       tze     return_main     skip if begin block is quick
+       epbpsb  sp|0            get ptr to base of stack
+       inhibit on
+       sprisp  sb|stack_header.stack_end_ptr keep updating end ptr
+       eppsp   sp|stack_frame.prev_sp,* pop stack
+       inhibit off
+       sbq     1,dl            count down number of blocks
+       tnz     -3,ic           repeat until all done
+       lda     sp|stack_frame.flag_word
+       ana     stack_frame.main_proc_bit,dl    is this the first main procedure invoked in the run unit?
+       tze     return_mac              no - do a normal return from a begin block
+       tra     stop                    yes - do a stop run
+"
+"      set_main_flag - sets a bit in the stack_frame if this is the first procedure in the run unit and  has options(main)
+"
+set_main_flag:
+       epbp7   sp|0                    pointer to stack_header
+       lxl1    sb|stack_header.main_proc_invoked
+       cmpx1   1,du                    first main procedure in run unit?
+       tnz     zero_main_flag          no
+       orx1    =o400000,du             then this is the first main procedure
+       sxl1    sb|stack_header.main_proc_invoked       indicate main procedure has been invoked
+       lda     stack_frame.main_proc_bit,dl    flag stack frame of first main procedure
+       orsa    sp|stack_frame.flag_word
+       tra     sp|tbp,*0                       return
+zero_main_flag:
+       lca     stack_frame.main_proc_bit+1,dl  generate mask to turn off main_proc bit
+       ansa    sp|stack_frame.flag_word        indicate that this is not the first main procedure
+       tra     sp|tbp,*0                       return
+"
+"      sign operator.  entered with indicators set via load
+
+sign_mac:      tze     sp|tbp,*0               return zero if zero
+       tmi     3,ic            skip if negative
+       ldq     1,dl            return +1
+       tra     sp|tbp,*0               ..
+       lcq     1,dl            return -1
+       tra     sp|tbp,*0               ..
+"
+"      operator to transfer sign of number pointed to by bp to integer in q
+"
+trans_sign_fx1:
+       lls     36              form abs value of Q in A
+       tpl     2,ic
+       neg     0
+       szn     bp|0            if second number is negative
+       tpl     2,ic
+       neg     0               set A negative too
+       lrs     36              shift back to Q
+       tra     sp|tbp,*0               and return
+"
+"      operator to transfer sign of floating number pointed to by bp
+"      to floating number in EAQ
+"
+trans_sign_fl:
+       tpl     2,ic            set first number positive
+       fneg    0
+       fszn    bp|0            if second number is positive
+       tpl     3,ic            value is OK
+       fneg    0               otherwise, set first negative
+       tra     sp|tbp,*0               and return
+       fcmp    =0.0,du         restore indicators
+       tra     sp|tbp,*0               and return
+"
+"      opearator to perform Fortran type mod function
+"
+fort_mdfl1:
+       fszn    bp|0            return if B zero
+       tze     sp|tbp,*0
+       fstr    sp|temp         save A
+       fdv     bp|0            form A/B
+       tmi     3,ic
+       fad     =71b25,du               truncate towards 0
+       tra     4,ic
+       fneg
+       fad     =71b25,du               truncate towards 0
+       fneg
+       fmp     bp|0
+       fneg    0
+       fad     sp|temp         form A - [A/B]*B
+       tra     sp|tbp,*0               and return
+"
+"      Fortran double precision mod
+"      dmod (A,B) = A - INT(A/B) * B
+"      A in eaq, bp|0 -> B, result in eaq
+"
+fort_dmod:
+       fszn    bp|0            this only works on normalized numbers!
+       tze     sp|tbp,*0               return A if B is zero
+       dfstr   sp|temp         save A
+       dfdv    bp|0            form A/B
+       tmi     3,ic
+       dfad    k71b25          truncate toward zero
+       tra     4,ic
+       fneg
+       dfad    k71b25          truncate toward zero
+       fneg
+       dfmp    bp|0            form [A/B]*B
+       fneg
+       dfad    sp|temp         form A-[A/B]*B
+       tra     sp|tbp,*0               and return it
+"
+"      operators to convert from fixed point to single float complex
+"
+rfb1_to_cflb1:
+       lls     36              convert to double fixed first
+       lrs     36
+"
+rfb2_to_cflb1:
+       lde     =71b25,du               convert to float
+       fad     =0.,du
+       fst     sp|temp         and save
+       lda     sp|temp         get real part
+       ldq     =0.,du          and imag part of zero
+       tra     sp|tbp,*0               and return
+"
+"      operator to perform complex multiplication, defined as
+"      (a+ib)*(c+id) -> a*c - b*d +i(b*c + a*d)
+"      entered with bp pointing at multiplier and multiplicand in AQ
+"      or in complex AQ
+"
+mpcfl1_1:      ldaq    sp|complex      get a+ib
+"
+mpcfl1_2:      staq    sp|temp         and save
+       fld     sp|temp+1               form b*d
+       fmp     bp|1
+       fst     sp|complex
+       fld     sp|temp         form a*c
+       fmp     bp|0
+       fsb     sp|complex      form a*c - b * d
+       fst     sp|complex
+       fld     sp|temp         form a*d
+       fmp     bp|1
+       fst     sp|complex+1
+       fld     sp|temp+1               form b*c
+       fmp     bp|0
+       fad     sp|complex+1    form b*c + a*d
+       fst     sp|complex+1
+       tra     sp|tbp,*0               and return
+"
+"      operator to perform complex division entered with
+"      bp pointing at divisor, dividend in AQ or complex AQ.
+"      This code, written by R. A. Barnes, is based on
+"      Algorithm 116 in Collected Algorithms from CACM
+"      written by Robert L. Smith from Stanford University.
+"      Following is the algorithm written in pseudo PL/I
+"      to do (a+ib)/(c+id) = (e+if)
+"
+"      if abs(c) >= abs(d)
+"      then do;
+"           r = d/c;
+"           den = c + r*d;
+"           e = (a + b*r)/den;
+"           f = (b - a*r)/den;
+"           end;
+"      else do;
+"           r = c/d;
+"           den = d + r*c;
+"           e = (a*r + b)/den;
+"           f = (b*r - a)/den;
+"           end;
+"
+dvcfl1_1:      ldaq    sp|complex      get a+ib
+"
+dvcfl1_2:      staq    sp|temp         and save
+       fld     bp|0            get c
+       fcmg    bp|1            compare with d
+       tmi     dvcfl1_else
+"
+       fdi     bp|1            get d/c
+       fst     sp|num          save as r
+       fmp     bp|1            form r*d
+       fad     bp|0            c + r*d
+       fst     sp|temp2                save as den
+       fld     sp|temp+1               get b
+       fmp     sp|num          form b*r
+       fad     sp|temp         a + b*r
+       fdv     sp|temp2                (a + b*r)/den
+       fst     sp|complex      store e
+       fld     sp|temp         get a
+       fmp     sp|num          form a*r
+       fneg    0               - a*r
+       fad     sp|temp+1               b - a*r
+       fdv     sp|temp2                (b - a*r)/den
+       fst     sp|complex+1    store f
+       tra     sp|tbp,*0               return
+"
+dvcfl1_else:
+       fdv     bp|1            get c/d
+       fst     sp|num          save as r
+       fmp     bp|0            form r*c
+       fad     bp|1            d + r*c
+       fst     sp|temp2                save as den
+       fld     sp|temp         get a
+       fmp     sp|num          form a*r
+       fad     sp|temp+1               a*r + b
+       fdv     sp|temp2                (a*r + b)/den
+       fst     sp|complex      store e
+       fld     sp|temp+1               get b
+       fmp     sp|num          form b*r
+       fsb     sp|temp         (b*r - a)
+       fdv     sp|temp2                (b*r - a)/den
+       fst     sp|complex+1    store f
+       tra     sp|tbp,*0               return
+"
+"      operator to perform block copy.  entered
+"      with block size in ql, ptr to destination in sp|temp_pt and ptr
+"      to source in bp.
+"
+copy_words:
+       qls     2               compute number of chars to move
+       tze     sp|tbp,*0               skip if zero (prevent IPR)
+       eppap   sp|temp_pt,*    get ptr to destination
+       mlr     (ar+rl),(ar+rl)
+       desc9a  bp|0,ql
+       desc9a  ap|0,ql
+       eppap   sp|stack_frame.operator_ptr,*
+       tra     sp|tbp,*0
+"
+"      operator to perform block copy from even boundary to even boundary.
+"      same conventions as copy_words.
+"
+copy_double:
+       qls     1               get number of chars
+       tra     copy_words+1    join copy_words case
+"
+"      operator to multiply single precision fixed number in q
+"      by double precision fixed number pointed at by bp
+"
+mpfx2: eax1    0               set for positive sign
+       llr     36              shift multiplier to a
+       tpl     3,ic            skip if positive
+       neg     0               neg, force positive
+       eax1    1               flip sign of result
+       sta     sp|temp         save multiplier
+       ldaq    bp|0            get multiplicand
+       tpl     3,ic            skip if positive
+       negl    0               neg, force positive
+       erx1    1,du            flip sign of answer
+       cana    =o200000,du     remember high order bit
+       tze     2,ic
+       orx1    2,du
+       llr     1               get high order bit of q into q
+       qrl     1               get zero in s bit of q
+       ana     mask_bit+2      and zero in s bit of a
+       sta     sp|t5           save upper half
+       mpy     sp|temp         form lower product
+       staq    sp|lv           save for later
+       ldq     sp|t5           get upper half
+       mpy     sp|temp         form upper product
+       cmpa    0,dl            a should be clear
+       tnz     mult_overflow
+       lls     35              and shift to position
+       adaq    sp|lv           add lower product
+       staq    sp|lv           and save
+       ldaq    bit_mask                multiply lower by high order bit
+       canx1   2,du
+       tze     2,ic
+       ldq     sp|temp
+       lls     70              shift to position (should give only 1 bit)
+       trc     mult_overflow
+       adaq    sp|lv           add back rest of number
+       canx1   1,du            check result of answer
+       tnz     3,ic            jump if -
+       cmpaq   bit_mask                set indicators
+       tra     sp|tbp,*0               return
+       negl    0               negate
+       tra     sp|tbp,*0               and return to pl/1 program
+"
+"      operator to multiply double precison fixed integer in aq
+"      by double precsion fixed number pointed at by bp.
+"
+mpfx3: eax1    0               set positive sign
+       cmpa    0,du            skip if number positive
+       tpl     3,ic
+       negl    0               neg, force positive
+       eax1    1               flip sign of answer
+       cana    =o200000,du     remember high order bit
+       tze     2,ic
+       orx1    2,du
+       llr     1               split into 2 35 bit pos numbers
+       qrl     1
+       ana     mask_bit+2
+       sta     sp|t1           save for later
+       stq     sp|t2
+       ldaq    bp|0            get multplier
+       tpl     3,ic            force positive
+       negl    0
+       erx1    1,du            and set answer sign
+       cana    =o200000,du     remember high order bit
+       tze     2,ic
+       orx1    4,du
+       llr     1               split
+       qrl     1
+       ana     mask_bit+2
+       sta     sp|t3           save for later
+       stq     sp|t4
+       mpy     sp|t2           form lower product
+       staq    sp|lv           and save
+       ldq     sp|t3           form first upper product
+       mpy     sp|t2
+       cmpa    0,dl            a should be clear
+       tnz     mult_overflow
+       lls     35              and add to lower
+       adaq    sp|lv
+       staq    sp|lv           save partial answer
+       ldq     sp|t1           form second upper product
+       mpy     sp|t4
+       cmpa    0,dl
+       tnz     mult_overflow
+       lls     35              shift to position
+       adaq    sp|lv           add previous part
+       staq    sp|lv           and save again
+       ldq     sp|t3           form upper upper product
+       mpy     sp|t1           which may only give one bit
+       canx1   2,du
+       tze     2,ic
+       adq     sp|t4
+       canx1   4,du
+       tze     2,ic
+       adq     sp|t2
+       cmpa    0,dl            a should be clear
+       tnz     mult_overflow
+       lls     70              shift to position
+       trc     mult_overflow
+       adaq    sp|lv           and add it in
+       canx1   1,du            should answer be neg
+       tnz     3,ic            yes, jump
+       cmpaq   bit_mask                set indicators
+       tra     sp|tbp,*0       return
+       negl    0               set minus sign
+       tra     sp|tbp,*0               and return
+"
+mult_overflow:
+       sreg    sp|save_regs
+       tsx7    signal_overflow
+use_first:
+       lreg    sp|save_regs
+       cmpaq   bit_mask                set indicators properly
+       tra     sp|tbp,*0
+"
+"      operator to perform string range check.  entered with
+"              length of string (k) in q
+"              bp|0    pointing at i (2nd arg of substr)
+"              bp|1    pointing at j (3rd arg of substr)
+"      exit with new value of j in q
+"
+sr_check:
+       sxl0    sp|stack_frame.operator_ret_ptr
+       stq     sp|bit_lg1      save k
+       ldq     bp|0            form i' = i - 1
+       sbq     1,dl
+       stq     bp|0            and save
+       tmi     sr_2            signal if i' < 0
+       cmpq    sp|bit_lg1      signal if i' >= k
+       tpl     sr_2
+       ldq     bp|1            get j
+       tmi     sr_3            signal if j < 0
+       cmpq    sp|bit_lg1      signal if j > k
+       tmi     2,ic
+       tnz     sr_3
+       adq     bp|0            form i' + j
+       cmpq    sp|bit_lg1      return if i' + j <= k
+       tze     2,ic
+       tpl     sr_3
+       ldq     bp|1            exit with value of j
+z_done:        lxl0    sp|stack_frame.operator_ret_ptr restore return offset
+       stz     sp|stack_frame.operator_ret_ptr and clear record
+       tra     sp|tbp,*0
+"
+sr_3:  tsx0    string_signal
+       ldq     sp|bit_lg1      get min(k-i+1,j)
+       sbq     bp|0
+       cmpq    bp|1
+       tmi     2,ic
+       ldq     bp|1
+       cmpq    0,dl            use zero if q < 0
+       tpl     2,ic
+       ldq     0,dl
+       tra     z_done          return
+"
+sr_2:  tsx0    string_signal
+       ldq     0,dl            use j = 0
+       tra     z_done          return
+"
+signal_stringrange:
+       sxl0    sp|stack_frame.operator_ret_ptr
+       eax0    z_done          set return ptr and fall into string_signal
+"
+string_signal:
+       stx0    sp|temp         save x0
+       spribp  sp|lv           and bp
+       lxl6    11,dl           get length of condition
+       eppbp   strg            get ptr to condition name
+       ldq     =701,dl         load oncode value
+       tsx1    call_signal_    signal "stringrange"
+       ldx0    sp|temp         restore x0
+       eppbp   sp|lv,*         and bp
+       tra     0,0             and return
+strg:  aci     "stringrange"
+"
+"      non-local transfer operator.  entered with bp pointing
+"      at destination and number of stack levels to pop in x7.
+"
+tra_ext_1:
+       eaq     0,7             move number of levels to ql
+       qrl     18
+       spribp  sp|lv           save ptr to destination
+       tsx1    display_chase   get ptr to stack frame
+       spribp  sp|lv+2         finish the label variable
+       eppbp   sp|lv           fall into unwinder_ call
+"
+"      non-local transfer operator.  entered with bp pointing
+"      at a label variable.
+"
+tra_ext_2:
+       spribp  sp|arg_list+2   save ptr to label var
+       fld     2*1024,dl               there are 2 args
+       staq    sp|arg_list     ..
+       eppap   sp|arg_list     get ptr to arg_list
+       tsx1    get_our_lp      get ptr to our linkage
+       tra     <unwinder_>|[unwinder_] go unwind stack
+"
+"      operator to assign auto adjustable variables at end of stack
+"      frame.  entered with number of words in q, exit with pointer
+"      to storage in bp.
+"
+alloc_auto_adj:
+       eaq     15,ql           make size a multiple of 16
+       anq     =o777760,du     ..
+       get_stack_offset
+       eppbp   sp|4,*          get ptr to storage
+       adlq    sp|5            get new end of stackframe
+       stq     sp|stack_frame.next_sp+1 update next sp ptr
+       stq     sp|stack_header.stack_end_ptr+1,au update stack end ptr also
+       stq     sp|5            and set to remember this storage
+       tra     sp|tbp,*0               return to caller
+"
+"      floating point mod operators entered with x in eaq and
+"      bp pointing at y.  mod(x,y) = if y = 0 then x else x - floor(x/y)*y
+"
+mdfl1: fszn    bp|0            return x if y = 0
+       tze     mdfl1a
+       fst     sp|temp         save x
+       fdv     bp|0            divide x/y
+       tmi     3,ic            get floor
+       fad     =71b25,du
+       tra     5,ic
+       fneg
+       fad     almost_one
+       fad     =71b25,du
+       fneg
+       fmp     bp|0            form floor(x/y)*y
+       fneg
+       fad     sp|temp         form answer
+       tra     sp|tbp,*0               and return
+mdfl1a:        fcmp    =0.0,du         set indicators properly
+       tra     sp|tbp,*0
+"
+mdfl2: dfst    sp|temp         save x
+       dfld    bp|0            get y
+       tze     mdfl2a          return x if y = 0
+       dfdi    sp|temp         divide x/y
+       tmi     3,ic            form floor
+       dfad    k71b25
+       tra     5,ic
+       fneg
+       dfad    almost_one
+       dfad    k71b25
+       fneg
+       dfmp    bp|0            form floor(x/y)*y
+       fneg
+mdfl2a:        dfad    sp|temp         form answer
+       tra     sp|tbp,*0               and return
+"
+"      real truncation operator
+"
+trunc_fl:
+       tmi     3,ic
+       fad     =71b25,du
+       tra     sp|tbp,*0
+       fneg
+       fad     =71b25,du
+       fneg
+       tra     sp|tbp,*0
+"
+"      single precision fixed truncate, entered with scale in x2
+"
+trunc_fx1:
+       cmpq    0,dl
+       tmi     3,ic
+       qrs     0,2
+       tra     sp|tbp,*0
+       stq     sp|temp
+       lcq     sp|temp
+       qrs     0,2
+       stq     sp|temp
+       lcq     sp|temp
+       tra     sp|tbp,*0
+"
+"      double precision fixed truncate, entered with scale in x2
+"
+trunc_fx2:
+       cmpaq   bit_mask
+       tmi     3,ic
+       lrs     0,2
+       tra     sp|tbp,*0
+       negl
+       lrs     0,2
+       negl
+       tra     sp|tbp,*0
+"
+"      operators to do floating point floor and ceiling functions
+"      these use the relations
+"              floor(-x) = -ceil(|x|)
+"              ceil(-x) = -floor(|x|)
+"
+floor_fl:
+       tmi     3,ic
+       fad     =71b25,du
+       tra     sp|tbp,*0
+       fneg
+       dfad    almost_one
+       fad     =71b25,du
+       fneg
+       tra     sp|tbp,*0
+"
+ceil_fl:
+       tmi     4,ic
+       dfad    almost_one
+       fad     =71b25,du
+       tra     sp|tbp,*0
+       fneg
+       fad     =71b25,du
+       fneg
+       tra     sp|tbp,*0
+"
+"      operators to do single precision fixed floor and ceiling functions
+"      entered with argument in q register and scale in index 2
+
+floor_fx1:
+       cmpq    0,dl
+       tmi     3,ic
+       qrs     0,2
+       tra     sp|tbp,*0
+       stq     sp|temp
+       lcq     sp|temp
+       cmpx2   36,du
+       tmoz    3,ic
+       adq     floor_ceil_mask+36
+       tra     2,ic
+       adq     floor_ceil_mask,2
+       qrs     0,2
+       stq     sp|temp
+       lcq     sp|temp
+       tra     sp|tbp,*0
+"
+ceil_fx1:
+       cmpq    0,dl
+       tmi     8,ic
+       cmpx2   36,du
+       tmoz    3,ic
+       adq     floor_ceil_mask+36
+       tra     2,ic
+       adq     floor_ceil_mask,2
+       qrs     0,2
+       tra     sp|tbp,*0
+       stq     sp|temp
+       lcq     sp|temp
+       qrs     0,2
+       stq     sp|temp
+       lcq     sp|temp
+       tra     sp|tbp,*0
+"
+"      operators do double precision fixed floor and ceiling functions
+"      entered with argument in aq register, scale in index 2, and -2*scale
+"      in index 3
+"
+floor_fx2:
+       cmpaq   bit_mask
+       tmi     3,ic
+       lrs     0,2
+       tra     sp|tbp,*0
+       negl
+       cmpx3   -144,du
+       tpl     3,ic
+       adaq    mask_bit
+       tra     2,ic
+       adaq    mask_bit+144,3
+       lrs     0,2
+       negl
+       tra     sp|tbp,*0
+"
+ceil_fx2:
+       cmpaq   bit_mask
+       tmi     8,ic
+       cmpx3   -144,du
+       tpl     3,ic
+       adaq    mask_bit
+       tra     2,ic
+       adaq    mask_bit+144,3
+       lrs     0,2
+       tra     sp|tbp,*0
+       negl
+       lrs     0,2
+       negl
+       tra     sp|tbp,*0
+"
+"      operator to round single fixed binary
+"      entered with (scale - k) in index 7
+"
+round_fx1:
+       cmpq    0,dl            set indicators
+       tmi     round_fx1b      skip if negative
+       eax1    0               remember was positive
+round_fx1a:
+       stq     sp|temp         save abs(arg)
+       ldq     1,dl            form 1/2 at proper scale
+       qls     -1,7
+       adq     sp|temp         add abs(arg)
+       qrs     0,7             drop bits to right
+       cmpx1   0,du            was arg positive
+       tze     sp|tbp,*0               yes, can return
+       stq     sp|temp         arg was negative, negate result
+       lcq     sp|temp
+       tra     sp|tbp,*0               before returning
+round_fx1b:
+       stq     sp|temp         get abs(arg)
+       lcq     sp|temp
+       eax1    1               remember arg was negative
+       tra     round_fx1a      and join positive case
+"
+"      operator to round double fixed binary
+"      entered with (scale - k) in index 7
+"
+round_fx2:
+       cmpaq   bit_mask                set indicators
+       tmi     round_fx2b      skip if negative
+       eax1    0               remember arg was positive
+round_fx2a:
+       staq    sp|temp         save abs(arg)
+       ldaq    one             form 1/2 at proper scale
+       lls     -1,7
+       adaq    sp|temp         add abs(arg)
+       lrs     0,7             drop bits to right
+       xec     sign_change,1   put back proper sign
+       tra     sp|tbp,*0               and return
+round_fx2b:
+       negl    0               take abs(arg)
+       eax1    1               remember arg was negative
+       tra     round_fx2a      join positive case
+"
+"      operator to compute round(x,k) for floating point values.
+"      entered with x in eaq and k immediately following tsx0
+"
+round_fl:
+       eax1    0               assume sign +
+       eppbp   sp|tbp,*0               get ptr to K in lhs
+       fcmp    =0.0,du
+       tze     bp|1            return if 0
+       tpl     3,ic
+       fneg    0               get abs value
+       eax1    1
+       ldx0    bp|0            load k
+       dfst    sp|temp         save value
+       lda     =o200000,du     get bit in proper position
+       ldq     0,dl
+       lrs     0,0             shift
+       dfad    sp|temp         perform rounding
+       adx0    bp|0            get 2*k
+       anaq    bit_mask+2,0    erase low order bits
+       xec     fl_sign_change,1        put back correct sign
+       tra     bp|1            and return
+"
+fl_sign_change:
+       nop     0
+       fneg    0
+"
+"      Operator to round a floating point number to the nearest whole
+"      number.  Entered with value in EAQ and indicators set.  Result in
+"      EAQ.
+"
+nearest_whole_number:
+       tmi     nearest_whole_negative
+       fad     =0.5,du
+       fad     =71b25,du
+       tra     sp|tbp,*0
+
+nearest_whole_negative:
+       fneg
+       fad     =0.5,du
+       fad     =71b25,du
+       fneg
+       tra     sp|tbp,*0
+"
+"      Operator to round a floating point number to the nearest integer.
+"      Entered with value in EAQ and indicators set.  Result in Q.
+"
+nearest_integer:
+       tmi     nearest_integer_negative
+       fad     =0.5,du
+       ufa     =71b25,du
+       tra     sp|tbp,*0
+
+nearest_integer_negative:
+       fneg
+       fad     =0.5,du
+       ufa     =71b25,du
+       negl
+       tra     sp|tbp,*0
+
+"      Operator to convert a long bit string to double precision fixed binary.
+"      Entered with bit string previously setup.
+
+longbs_to_fx2:
+       epp2    sp|temp_pt,*    " pr2 = ptr to string
+       ldq     sp|bit_lg1      " q = length of string in bits
+       stz     sp|temp         " clear high order bit of result
+       csr     (pr,rl),(pr),bool(move),fill(0)
+       descb   pr2|0,ql
+       descb   sp|temp(1),71
+       trtf    longbs_to_fx2_short     " Was string longer than 71 bits?
+       sbq     71,dl           " Yes: Remove last 71 bits from string length
+       cmpb    (pr,rl),(),fill(0)      " Make sure the leading bits are zero.
+       descb   pr2|0,ql
+       descb   0,0
+       tnz     signal_size_condition
+longbs_to_fx2_short:
+       ldaq    sp|temp         " aq = result
+       tra     sp|tbp,*x0      " return
+
+"      Operator to convert a long bit string to bit 18 (used for ptr built-ins).
+"      Entered with bit string previously setup.
+
+longbs_to_bs18:
+       epp2    sp|temp_pt,*    " pr2 = ptr to string
+       lda     sp|bit_lg1      " a = length of string in bits
+       csl     (pr,rl),(pr),bool(move),fill(0)
+       descb   pr2|0,al
+       descb   sp|temp,18
+       lda     sp|temp         " au = first 18 bits of string
+       anaq    bit_mask+2*18   " al, q = 0
+       tra     sp|tbp,*x0      " return
+
+"      operator to convert a packed (single word) ptr to unpacked (its)
+"      enter with packed pointer in q, exit with its pair in aq
+"
+pk_to_unpk:
+       stq     sp|lv           save packed ptr
+       spribp  sp|temp2
+       lprpbp  sp|lv           load packed ptr (get ring no right)
+       spribp  sp|save_regs            store as unpacked ptr
+       ldaq    sp|save_regs            load ITS pair into aq
+       eppbp   sp|temp2,*      restore original bp
+       tra     sp|tbp,*0
+"
+"      operator to convert an unpacked (its) ptr to packed (single word)
+"      enter with its pair in aq, exit with packed pointer in q
+"
+unpk_to_pk:
+       arl     18
+       lls     18
+       qls     3
+       lrl     30
+       qlr     30
+       tra     sp|tbp,*0
+"
+"      operator to load the packed pointer in q register into bp register
+"
+packed_to_bp:
+       stq     sp|temp
+       lprpbp  sp|temp
+       tra     sp|tbp,*0               and return
+"
+"      The following operators are used to move a block of <= 256 elements
+"      They are entered with lp and bp pointing to source and destination
+"      and au holding value for x0 during rpd loop.
+"
+"      Single word items, lp -> source, bp -> destination
+"
+       odd                     "to force rpd odd
+rpd_odd_lp_bp:
+       sxl0    sp|stack_frame.operator_ret_ptr
+       eax0    rpd_bits,au     init rpd loop
+       eax1    0
+       eax2    0
+       rpdx    0,1
+       lda     lp|0,1
+       sta     bp|0,2
+       tra     z_done          return
+"
+"      Single word items, bp -> source, lp -> destination
+"
+       odd                     "to force rpd odd
+rpd_odd_bp_lp:
+       sxl0    sp|stack_frame.operator_ret_ptr
+       eax0    rpd_bits,au
+       eax1    0
+       eax2    0
+       rpdx    0,1
+       lda     bp|0,1
+       sta     lp|0,2
+       tra     z_done          return
+"
+"      Double word items, lp -> source, bp -> destination
+"
+       odd                     "to force rpd odd
+rpd_even_lp_bp:
+       sxl0    sp|stack_frame.operator_ret_ptr
+       eax0    rpd_bits,au     init rpd loop
+       eax1    0
+       eax2    0
+       rpdx    0,2
+       ldaq    lp|0,1
+       staq    bp|0,2
+       tra     z_done          return
+"
+"      Double word items, bp -> source, lp -> destination
+"
+       odd                     "to force rpd odd
+rpd_even_bp_lp:
+       sxl0    sp|stack_frame.operator_ret_ptr
+       eax0    rpd_bits,au     init rpd loop
+       eax1    0
+       eax2    0
+       rpdx    0,2
+       ldaq    bp|0,1
+       staq    lp|0,2
+       tra     z_done          return
+"
+" \f
+"      The following macro is the trace macro.  It contains the calling
+"      sequence to trace.
+"
+       macro   trace
+       ife     &1,trace_
+       epaq    *               get segment number of pl1_operators_
+       lprplp  sb|stack_header.lot_ptr,*au     get our linkage ptr
+       sprpbp  sb|stack_header.stack_end_ptr,* save entry ptr as packed ptr
+       eppbp   sb|stack_header.stack_end_ptr,*
+       sprpab  bp|1            save lisp linkage ptr (might be lisp environment)
+       tspbp   trace_catch_$catch_pl1_
+       eppab   sb|stack_header.stack_end_ptr,*
+       lprpbp  ab|0            restore entry ptr
+       lprpab  ab|1            restore lisp linkage ptr
+ifend
+       &end
+" \f
+" Macro to generate the ALM entry operator with or without the calling sequence for
+" trace_catch_$catch_pl1_.  When the ALM entry operator with the calling sequence for
+" trace is invoked it will allow trace to meter the ALM program and print its arguments
+" on entrance and exit.  (P. Krupp 09/20/77)
+
+          macro     alm_entry_op
+"         BEGIN MACRO alm_entry_op
+&1alm_entry:
+          eppbp     bp|-1               generate pointer to entry structure
+       trace   &1
+       epplp   sb|stack_header.stack_end_ptr,* get a pointer to the next stack frame
+       spribp  lp|stack_frame.entry_ptr
+       epaq    bp|0            get seg no of object in a
+       lprplb  sb|stack_header.isot_ptr,*au get packed ptr to static from isot
+       sprplb  lp|stack_frame.static_ptr save in next stack frame
+       lprplp  sb|stack_header.lot_ptr,*au get packed ptr to linkage from lot
+       tra     bp|1            return to alm prog
+"         END MACRO alm_entry_op
+          &end
+
+"      The following operators are used by ALM
+"      The order of the following operators must be maintained because of
+"      coding of default_error_handler_
+"
+alm_operators_begin:
+alm_call:
+       sprilp  sp|stack_frame.return_ptr save return pointer
+       sti     sp|stack_frame.return_ptr+1     save indicators
+       epplp   sp|stack_frame.lp_ptr,* set up our lp
+       callsp  bp|0            do the call
+"
+alm_push:
+       spribp  sb|stack_header.stack_end_ptr,* save return from operator
+       eppbp   sb|stack_header.stack_end_ptr,* get pointer to new stack frame
+       sprisp  bp|stack_frame.prev_sp save previous ptr in new frame
+       spriap  bp|stack_frame.arg_ptr save argument ptr
+       sprilp  bp|stack_frame.lp_ptr save linkage ptr
+       eppsp   bp|0            move up to new frame
+       eppbp   sp|0,7          get pointer to end of this new frame
+       spribp  sb|stack_header.stack_end_ptr and update stack end pointer
+       spribp  sp|stack_frame.next_sp and set next sp of new frame
+       eax7    1               set ALM translator ID for debugging
+       stx7    sp|stack_frame.translator_id
+       tra     sp|0,*          return to alm program
+"
+          alm_entry_op
+"
+alm_return:
+       inhibit on
+       sprisp  sb|stack_header.stack_end_ptr update stack end ptr
+       eppsp   sp|stack_frame.prev_sp,* pop stack
+       inhibit off
+       epbpsb  sp|0            set up stack base in case we just switched stacks
+       eppap   sp|stack_frame.operator_ptr,* set op ptr of frame being returned to
+       ldi     sp|stack_frame.return_ptr+1     restore indicators for caller
+       rtcd    sp|stack_frame.return_ptr return to calling program
+"
+alm_return_no_pop:
+       epbpsb  sp|0            set up stack base in case returning to outer ring
+       eppap   sp|stack_frame.operator_ptr,* set up operator ptr of frame being returned to
+       ldi     sp|stack_frame.return_ptr+1     restore indicators for caller
+       rtcd    sp|stack_frame.return_ptr return to calling program
+"
+alm_operators_end:
+" \f
+"
+"      operator to check size condition for single fixed binary
+"      entered with number in q and -precision in x7
+"      Registers modified: none
+"
+"      Algorithm: If a number is in range then all of the high order bits
+"      that are in the word but aren't in the precision range should not
+"      contain any useful information. IE they should all be zeros for
+"      positive numbers and all ones for negative numbers.
+"
+"      If we left shift out all of the higher order bits, then the carry
+"      flag is set if any of these bits change.
+"
+size_check_fx1:
+       staq    sp|temp         save AQ
+          sti       sp|temp_indicators  save indicators
+          qls       35,x7              sample upper bits (35-precision)
+"                              C set if removed bits not all 0 or 1
+       tnc     size_ok_fx      restore & return
+
+signal_size_condition:
+       spribp  sp|double_temp
+       eppbp   size_name               get ptr to name of condition
+       stx6    sp|temp2                save x6
+       eax6    size_length     and load size
+       ldq     =703,dl         load oncode value
+ssc:   sxl0    sp|stack_frame.operator_ret_ptr save return offset
+       tsx1    call_signal_
+       ldx6    sp|temp2                restore x6
+       eppbp   sp|double_temp,*        restore bp
+       lxl0    sp|stack_frame.operator_ret_ptr
+       stz     sp|stack_frame.operator_ret_ptr
+size_ok_fx:
+       ldaq    sp|temp         restore AQ
+       ldi     sp|temp_indicators  restore indicators
+       tra     sp|tbp,*0               and return
+"
+"      operator to check size condition for double fixed binary
+"      entered with number in aq and -2*precision in x7
+"      Registers modified: none
+"
+size_check_fx2:
+       staq    sp|temp         save AQ
+       sti     sp|temp_indicators  save indicators
+       stx7    sp|temp_indicators  save -2*precision, want -precision
+       eaa     0,x7            cannot divide an Xreg, so use A
+       ars     1               divide -2*precision by 2
+       eax7    0,au            x7 now contains -precision
+       lda     sp|temp         restore A (original)
+       lls     71,x7           sample upper bits (71-prec)
+"                              C set if removed bits not all 0 or 1
+       ldx7    sp|temp_indicators  restore x7 
+       trc     signal_size_condition   if C set : |num| too big
+       ldaq    sp|temp         restore AQ
+       ldi     sp|temp_indicators  restore indicators
+       tra     sp|tbp,*0               and return
+"
+"      operator to check size condition for unsigned single fixed binary
+"      entered with number in q and -precision in x7
+"      Registers modified: none
+"
+size_check_uns_fx1:
+       staq    sp|temp         save AQ
+       sti     sp|temp_indicators  save indicators
+       cmpq    mask_bit_one+36,x7      check against table of max values
+       tnc     size_ok_fx      magnitude less than max value
+       tnz     signal_size_condition   greater than max value
+       tra     size_ok_fx      equal to max value
+
+"
+"      operator to check size condition for unsigned double fixed binary
+"      entered with number in aq and -2*precision in x7
+"      Registers modified: none
+"
+size_check_uns_fx2:
+       staq    sp|temp         save AQ
+       sti     sp|temp_indicators  save indicators
+       cmpaq   mask_bit+144,x7 check against table of max values
+       tnc     size_ok_fx      magnitude less than max value
+       tnz     signal_size_condition   greater than max value
+       tra     size_ok_fx      equal to max value
+"                              
+"      operator to check if result of an 'mpy' exceeds one word.
+"      entered with result of 'mpy' in AQ.
+"
+mpy_overflow_check:
+       staq    sp|temp         save AQ
+       sti     sp|temp_indicators      save indicators
+       lls     36              sets carry flag if result too big
+       tnc     size_ok_fx      restore & return
+       spribp  sp|double_temp  signal "fixedoverflow"
+       eppbp   overflow_name
+       stx6    sp|temp2
+       eax6    overflow_length
+       ldq     =711,dl
+       tra     ssc
+"
+"      operator to signal "size" condition
+"
+signal_size:
+       staq    sp|temp
+       tra     signal_size_condition
+"
+size_name:
+       aci     "size"
+       equ     size_length,4
+"
+"      operator to signal "stringsize" condition
+"
+signal_stringsize:
+       staq    sp|temp
+       spribp  sp|double_temp
+       stx6    sp|temp2
+       eppbp   stringsize_name
+       eax6    stringsize_length
+       ldq     =702,dl
+       tra     ssc
+"
+stringsize_name:
+       aci     "stringsize"
+       equ     stringsize_length,10
+"
+"      operator to request fortran external storage allocation and/or 
+"           initialization.
+"
+fort_storage:
+       spri6   sp|double_temp  stack frame pointer
+       epp2    sp|double_temp
+       spri2   sp|arg_list+2   argument 1 - stack pointer
+       epp2    sp|linkage_ptr   linkage pointer
+       spri2   sp|arg_list+4   argument 2 - linkage pointer
+       epp2    sp|tbp,*0               text pointer to arg_list
+       spri2   sp|temp_pt
+       epp2    sp|temp_pt
+       spri2   sp|arg_list+6   argument 3 - argument pointer
+       lda     6,du            nargs = 3, quick call (no enviptr)
+       ldq     0,dl            no descriptors
+       staq    sp|arg_list
+       epp0    sp|arg_list     get argument list header
+       adx0    1,du
+       stx0    sp|stack_frame.return_ptr+1     save return point
+       sti     sp|stack_frame.return_ptr+1     save indicators
+       tsx1    get_our_lp
+       callsp  fortran_storage_$create
+"
+"      operator to enable a condition.  calling sequence is:
+"              eppbp   name
+"              lxl6    name_size
+"              tsx0    ap|enable
+"              tra     on_unit_body
+"              arg     on_unit (snap & system flags in RHS if used)
+"              tra     skip_around_body
+"      body of on unit starts here
+"
+       include on_unit
+enable_op:
+       sxl0    sp|stack_frame.operator_ret_ptr
+       epplp   sp|tbp,*0
+       lda     =o100,dl                is there a valid on_unit_list
+       cana    sp|stack_frame.prev_sp check bit 29 of sp|stack_frame.prev_sp
+       tnz     3,ic            non-zero means ok
+       stz     sp|stack_frame.on_unit_rel_ptrs init ptr
+       orsa    sp|stack_frame.prev_sp and set bit
+"
+       ldx1    sp|stack_frame.on_unit_rel_ptrs get rel ptr to first enabled unit
+       tze     add_on          zero means chain empty
+on_1:  cmpx1   lp|1            is this the unit we want
+       tze     have_on         yes, go process
+       ldx1    sp|on_unit.next,1       no, get ptr to next on chain
+       tnz     on_1            and repeat if end not reached
+add_on:        ldx1    lp|1            get rel ptr to new unit
+       ldx0    sp|stack_frame.on_unit_rel_ptrs get rel ptr to first unit
+       stx0    sp|on_unit.next,1       set next ptr of new unit
+       stx1    sp|stack_frame.on_unit_rel_ptrs make new unit first on chain
+have_on:       spribp  sp|on_unit.name,1       set name of new unit
+       sprilp  sp|on_unit.body,1       set ptr to body
+       stz     sp|on_unit.size,1       clear size field
+       sxl6    sp|on_unit.size,1       set size of unit name
+       lxl0    lp|1            get snap & system flags
+       sxl0    sp|on_unit.flags,1      and save in on unit
+       stz     sp|stack_frame.operator_ret_ptr
+       tra     lp|2            return to pl1 program
+"
+"
+"      operator to create and enable a cleanup handler for a fortran
+"      program.  calling sequence is:
+"              tsx0    ap|fort_cleanup
+"              arg     on_unit_body    (snap & system flags in RHS if used)
+"      Uses pr2 (bp) and pr4 (lp) - restores pr4 (lp) from stack
+"
+fort_cleanup:
+       sxl0    sp|stack_frame.operator_ret_ptr
+       eppbp   sp|tbp,*0
+       lda     =o100,dl                is there a valid on_unit_list
+       cana    sp|stack_frame.prev_sp check bit 29 of sp|stack_frame.prev_sp
+       tnz     3,ic            non-zero means ok
+       stz     sp|stack_frame.on_unit_rel_ptrs init ptr
+       orsa    sp|stack_frame.prev_sp and set bit
+"
+       ldx1    sp|stack_frame.on_unit_rel_ptrs get rel ptr to first enabled unit
+       tze     add_fort_cleanup        zero means chain empty
+fort_cleanup_1:
+       cmpx1   bp|0            is this the unit we want
+       tze     have_fort_cleanup       yes, go process
+       ldx1    sp|on_unit.next,1       no, get ptr to next on chain
+       tnz     fort_cleanup_1  and repeat if end not reached
+add_fort_cleanup:
+       ldx1    bp|0            get rel ptr to new unit
+       ldx0    sp|stack_frame.on_unit_rel_ptrs get rel ptr to first unit
+       stx0    sp|on_unit.next,1       set next ptr of new unit
+       stx1    sp|stack_frame.on_unit_rel_ptrs make new unit first on chain
+have_fort_cleanup:
+" Point to our cleanup handler and our name and length
+       epplp   fort_cleanup_name
+       sprilp  sp|on_unit.name,1       set name of new unit
+       get_our_lp                      " need our linkage section
+       epplp   <fort_cleanup_>|[fort_cleanup_]
+       sprilp  sp|on_unit.body,1       set ptr to body
+       epplp   sp|linkage_ptr,*        restore ptr to linkage segment
+       lxl0    fort_cleanup_length,dl
+       stz     sp|on_unit.size,1       clear size field
+       sxl0    sp|on_unit.size,1       set size of unit name
+       lxl0    bp|0            get snap & system flags
+       sxl0    sp|on_unit.flags,1      and save in on unit
+       stz     sp|stack_frame.operator_ret_ptr
+       tra     bp|1            return to fortran program
+
+fort_cleanup_name:
+       aci     "cleanup"
+
+       equ fort_cleanup_length,7
+
+"
+"      operator to signal a condition.  entered with ptr to name in bp
+"      and size of name in x6.
+"
+signal_op:
+       sxl0    sp|stack_frame.operator_ret_ptr
+       ldq     =1000,dl                load oncode value
+       tsx1    call_signal_    call signal_
+       tra     z_done          and return
+"
+"      operator to signal "subscriptrange" condition
+"
+bound_ck_signal:
+       sxl0    sp|stack_frame.operator_ret_ptr
+       stx6    sp|temp         save x6
+       lxl6    14,dl           get size of condition
+       eppbp   subrg           get ptr to name
+       ldq     =704,dl         load oncode value
+       tsx1    call_signal_    call signal_
+       ldx6    sp|temp         restore x6
+       tra     z_done          and return
+subrg: aci     "subscriptrange"
+"
+"      operator to enable a condition with file specified, usage is
+"              eppbp   file
+"              eaa     name    (in text)
+"              ora     flags,dl        snap & system flags (optional)
+"              lxl6    name_size
+"              tsx0    ap|enable_file
+"
+enable_file:
+       sxl0    sp|stack_frame.operator_ret_ptr save return point
+       spribp  sp|temp         save pointer to file
+       eppbp   sp|tbp,*au      get pointer to name
+       sta     sp|double_temp  save snap & system flags
+       lda     =o100,dl                check for existence of condition list
+       cana    sp|stack_frame.condition_word
+       tnz     ef_1            if we have list, go check it
+       stz     sp|stack_frame.on_unit_rel_ptrs no list, initialize it
+       orsa    sp|stack_frame.condition_word ..
+"
+make_unit:
+       get_stack_offset
+       epplp   sp|stack_header.stack_end_ptr,au* get ptr to next stack frame
+       eax0    16              extend stack by 16 words
+       adlx0   sp|stack_frame.next_sp+1        ..
+       stx0    sp|stack_frame.next_sp+1        ..
+       stx0    sp|stack_header.stack_end_ptr+1,au      ..
+       stx0    sp|5            make extension "permanent"
+       eax1    lp|0,au         into x1
+"
+       ldx0    sp|stack_frame.on_unit_rel_ptrs get rel ptr to first unit
+       stx0    sp|on_unit.next,1       and save as next of new unit
+       stx1    sp|stack_frame.on_unit_rel_ptrs make new unit first unit
+"
+       spribp  sp|on_unit.name,1       save ptr to name
+       epplp   sp|temp,*               get back ptr to file
+       ldaq    lp|0            copy file into stack
+       staq    sp|on_unit.file_copy,1
+       ldaq    lp|2
+       staq    sp|on_unit.file_copy+2,1
+       epplp   sp|on_unit.file_copy,1  get ptr to copy of file
+       sprilp  sp|on_unit.file,1       and save as ptr to file
+       stz     sp|on_unit.size,1       clear size field
+"
+init_unit:
+       sxl6    sp|on_unit.size,1       set size of name
+       lxl0    sp|double_temp  get snap & system flags
+       sxl0    sp|on_unit.flags,1      store them
+       lxl0    sp|stack_frame.operator_ret_ptr restore return
+       stz     sp|stack_frame.operator_ret_ptr
+       epplp   sp|tbp,*0               get ptr to entry point of unit
+       sprilp  sp|on_unit.body,1       and save it
+       tra     lp|1            and then return
+"
+ef_1:  tsx0    find_unit               go search for unit
+       tra     init_unit               found it
+       eppbp   sp|temp2,*      restore ptr to name
+       tra     make_unit               not found, must go make it
+"
+"      operator to revert a condition with file specified, usage is
+"              eppbp   file
+"              eaa     name    (in text)
+"              lxl6    name_size
+"              tsx0    ap|revert_file
+"
+revert_file:
+       ldq     =o100,dl                do we have any conditions enabled
+       canq    sp|stack_frame.condition_word
+       tze     sp|tbp,*0               no, return immediately
+       sxl0    sp|stack_frame.operator_ret_ptr yes, save return
+       spribp  sp|temp         save  pointer to file
+       eppbp   sp|tbp,*au      get ptr to name
+       tsx0    find_unit               go search for unit
+       stz     sp|on_unit.size,1       found it, zero size
+       tra     z_done          ok to return now
+"
+"      subroutine to search for enabled condition, entered with
+"              bp      pointing at name in text
+"              x6      holding size of name
+"              sp|temp holding ptr to file
+"      returns 0,0     if condition found
+"              1,0     if condition not found
+"
+"      N.B. we assume that we only have to compare ptrs to check if name
+"      is the same because of constant pooling done by compiler
+"
+find_unit:
+       spribp  sp|temp2                save ptr to name
+       eppbp   sp|temp,*               get ptr to file
+       ldx1    sp|stack_frame.on_unit_rel_ptrs get offset of first unit
+       tra     2,ic            and enter loop
+"
+fu_1:  ldx1    sp|on_unit.next,1       get off of next unit
+       tze     1,0             none means we failed
+       ldaq    sp|on_unit.name,1       get name in on unit
+       cmpaq   sp|temp2                compare with name we want
+       tnz     fu_1            if not same keep looking
+       ldaq    sp|on_unit.file_copy+2,1        get second ptr in file
+       cmpaq   bp|2            compare with file we want
+       tnz     fu_1            keep looking if different
+       tra     0,0             found it
+"
+"      operators for put data
+"      entered with pointer to datum in bp, offset in x7, symtab offset in a
+"
+put_data_eis:
+       eax6    2               set procedure to call
+       tra     plio_eis                join common section
+"
+put_data:
+       eax1    0,7             get offset
+       tra     pd_1
+"
+put_data_co:
+       ldx1    co_to_bo,7      convert offset to bits
+       tra     pd_1
+"
+put_data_ho:
+       ldx1    ho_to_bo,7      convert offset to bits
+       tra     pd_1
+"
+put_data_aligned:
+       eax1    0               zero offset
+"
+pd_1:  eax6    2               set procedure to call
+       tra     plio            join common section
+"
+"      operators for get list
+"      entered with pointer to datum in bp, offset in x7, descriptor in q
+"
+get_list_eis:
+       eax6    3               set procedure to call
+       tra     plio_eis                join common section
+"
+get_list:
+       eax1    0,7             get offset
+       tra     gl_1
+"
+get_list_co:
+       ldx1    co_to_bo,7      convert offset to bits
+       tra     gl_1
+"
+get_list_ho:
+       ldx1    ho_to_bo,7      convert offset to bits
+       tra     gl_1
+"
+get_list_aligned:
+       eax1    0               zero offset
+"
+gl_1:  eax6    3               set procedure to call
+       tra     plio            join common section
+"
+"      operators for get edit
+"      entered with pointer to datum in bp, offset in x7, descriptor in q
+"
+get_edit:
+       eax1    0,7             get offset
+       tra     ge_1
+"
+get_edit_co:
+       ldx1    co_to_bo,7      convert offset to bits
+       tra     ge_1
+"
+get_edit_ho:
+       ldx1    ho_to_bo,7      convert offset to bits
+       tra     ge_1
+"
+get_edit_aligned:
+       eax1    0               zero offset
+"
+ge_1:  eax6    4               set procedure to call
+       tra     plio            join common section
+"
+"
+"
+"      operator for put list
+"      entered with pointer to datum in bp, offset in x7, descriptor in q
+"
+put_list_eis:
+       eax6    5               set procedure to call
+       stq     sp|temp         save descriptor
+       anq     =o374000,du
+       cmpq    =o114000,du     bit_str_desc
+       tze     <put_field_>|[put_field_str]
+       cmpq    =o120000,du     var_bit_str_desc
+       tze     <put_field_>|[put_field_str]
+       cmpq    =o124000,du     char_str_desc
+       tze     <put_field_>|[put_field_str]
+       cmpq    =o130000,du     var_char_str_desc
+       tze     <put_field_>|[put_field_str]
+       ldq     sp|temp
+"
+plio_eis:
+       eppap   sp|ps_ptr,*     get ptr to ps
+       stq     ap|ps.descriptor        set descriptor
+       sta     ap|ps.offset    store offset or picture constant loc
+       spribp  ap|ps.value_p   set ptr to datum
+       tra     plio4
+"
+put_list:
+       eax1    0,7             get offset
+       tra     pl_1
+"
+put_list_co:
+       ldx1    co_to_bo,7      convert offset to bits
+       tra     pl_1
+"
+put_list_ho:
+       ldx1    ho_to_bo,7      convert offset to bits
+       tra     pl_1
+"
+put_list_aligned:
+       eax1    0               zero offset
+"
+pl_1:  eax6    5               set procedure to call
+       tra     plio            join common section
+"
+"      operators for put edit
+"      entered with pointer to datum in bp, offset in x7, descriptor in q
+"
+put_edit:
+       eax1    0,7             get offset
+       tra     pe_1
+"
+put_edit_co:
+       ldx1    co_to_bo,7      convert offset to bits
+       tra     pe_1
+"
+put_edit_ho:
+       ldx1    ho_to_bo,7      convert offset to bits
+       tra     pe_1
+"
+put_edit_aligned:
+       eax1    0               zero offset
+"
+pe_1:  eax6    6               set procedure to call
+"
+plio:  eppap   sp|ps_ptr,*     get ptr to ps
+       stq     ap|ps.descriptor        set descriptor
+       sta     ap|ps.offset    store offset or picture constant loc
+       spribp  ap|ps.value_p   set ptr to datum
+       lxl1    shift_bo,1      shift bit offset to position
+       sxl1    ap|ps.value_p+1 and set bit offset of pointer
+"
+plio4: eppbp   sp|ps_ptr               save pointer to ps as arg
+       spribp  sp|arg_list+2
+       sreg    sp|8            save registers
+       fld     2*1024,dl
+       staq    sp|arg_list
+       eppap   sp|arg_list     get ptr to arg list
+       tsx1    get_our_lp      get ptr to our linkage section
+       epp1    4,ic            store return address and indicators
+       spri1   sp|stack_frame.return_ptr
+       sti     sp|stack_frame.return_ptr+1
+       tra     plio2,6         jump to appropriate proc
+       lreg    sp|8            restore registers
+put_return:
+       eppap   sp|tbp,*                get ptr to object
+       spriap  sp|stack_frame.return_ptr       reset return ptr
+       eppap   sp|stack_frame.operator_ptr,*   restore ptr to operators
+       tra     sp|tbp,*0               and return
+"
+plio2: callsp  <plio2_>|[get_terminate_]
+       callsp  <plio2_>|[put_terminate_]
+       callsp  <plio2_>|[put_value_data_]
+       callsp  <plio2_>|[get_value_list_]
+       tra     signal_error_missing
+       callsp  <plio2_>|[put_value_list_]
+       callsp  <plio2_>|[put_value_edit_]
+       callsp  <plio2_recio_>|[plio2_recio_]
+       callsp  <plio2_>|[open_explicit_]
+       callsp  <plio2_>|[close_]
+       callsp  <plio2_>|[get_prep_]
+       callsp  <plio2_>|[put_prep_]
+       callsp  <fortran_io_>|[read_or_write]
+       callsp  <fortran_io_>|[file_control]
+       callsp  <fortran_io_>|[terminate]
+       callsp  <fortran_io_>|[element]
+       callsp  <plio2_>|[put_field_]
+       tra     signal_error_missing
+       tra     signal_error_missing
+       tra     signal_error_missing
+       tra     signal_error_missing
+       callsp  <plio2_>|[put_blanks_]
+       callsp  <fortran_io_>|[get_io_area_ptr]
+"
+"      operator to terminate a get
+"
+get_terminate:
+       eax6    0               set proc to call
+       tra     plio4
+"
+"      operator to terminate a put
+"
+put_terminate:
+       eax6    1               set proc to call
+       tra     plio4
+"
+"      operator to open a file
+"
+open_file:
+       eax6    8               set proc to call
+       tra     plio4
+"
+"      operator to close a file
+"
+close_file:
+       eax6    9               set proc to call
+       tra     plio4
+"\f
+"      operators for doing FORTRAN I/O
+"
+"              WARNING   WARNING   WARNING   WARNING   WARNING   WARNING
+"
+"           The following code was modified on 19 Dec 1977, by D. Levin to allow
+"      fortran I/O's stack frame to remain active after control returns to the user's
+"      program. This is accomplished by a coordinated effort on the parts of:
+"
+"              1. this operator segment
+"              2. fortran_io_.pl1 (in bound_fort_runtime_)
+"              3. return_to_user.alm (in bound_fort_runtime_)
+"
+"           The first time a user program references fortran_io_ from its stack frame,
+"      the high-order bit of stack_frame.ps_ptr is zero. This implementation takes advantage
+"      of that fact and uses the high-order bit of stack_frame.ps_ptr as a flag to
+"      indicate whether or not a stack frame exists for fortran_io_.
+"
+"           The first time fortran_io_ is referenced from a stack frame, the high-order
+"      bit is zero, so a standard PL/I call is made to the appropriate entry point in
+"      fortran_io_, with the user's stack_frame.return_ptr set to return
+"      to the word after the operator call.  Once within fortran_io_, the
+"      user's stack frame is modified as follows:
+"
+"           1. Copy fortran_io_'s stack_frame|4 to the user's frame. This field is used
+"              by PL/I to determine the true end of the stack frame after a stack
+"              extension.
+"           2. Store a packed ptr to fio_ps at stack_frame.support_ptr. See next
+"              paragraph.
+"           3. Set high-order bit of stack_frame.ps_ptr to "1"b.
+"
+"           The structure "fio_ps" is in fortran_io_'s stack frame and contains all the
+"      necessary fields to allow communication between the user program and fortran_io_.
+"      It includes:
+"           1. The address of a location within fortran_io_ to which control is passed
+"              instead of performing a PL/I call.
+"           2. The address of fortran_io_'s stack frame.
+"           3. The address of a variable in fortran_io_'s stack frame into which the value
+"              of xr7 is stored. This value identifies the entry point desired.
+"
+"           When fortran_io_ returns to the user program, return_to_user$special_return
+"      is called. This routine copies fortran_io_'s stack_frame.next_sp into the user's
+"      stack_frame.next_sp, sets sp to the user's frame, and does a short_return.
+"      Fortran_io_'s stack frame is now part of the user's frame and remains so until
+"      the next I/O operation. Each fortran program frame has its own fortran_io_ frame.
+"      This causes the user frame to "absorb" fortran_io_'s frame.
+"
+"      NOTE - The procedure fortran_io_ must never perform a return_mac or
+"      fortran_io_'s frame will go away although the flag in the user's frame claims
+"      that it is still there.
+"\f
+"      Setup operators entered with unit number in q, job_bits in a. Read previous page
+"      of comments before modifying any FORTRAN I/O operators.
+"
+fortran_read:
+fortran_write:
+       eax6    12
+"
+ft_io: szn     sp|ps_ptr                       " <0 if fortran_io_ already has a stack frame
+       tmi     ft_fast_read_or_write
+       eppap   sp|ps_ptr,*             " load ptr to user's ps
+       stq     ap|ft_ps.unit
+       sta     ap|ft_ps.job_bits
+
+ft_io1:        eppbp   sp|ps_ptr                       " save pointer to ps as arg
+       spribp  sp|arg_list+2
+       sreg    sp|8                    " save registers
+       fld     2*1024,dl
+       staq    sp|arg_list
+       eppap   sp|arg_list             " get ptr to arg list
+       tsx1    get_our_lp              " get ptr to our linkage section
+       stx0    sp|stack_frame.return_ptr+1     " save offset into user's segment
+       sti     sp|stack_frame.return_ptr+1     " save indicators
+       tra     plio2,x6                        " jump to appropriate proc
+"
+ft_fast_read_or_write:
+       lprpbb  sp|stack_frame.support_ptr      " load ptr to fortran_io_'s fio_ps
+       staq    bb|fio_ps.job_bits_and_file
+ft_fast_call:
+       stx0    sp|stack_frame.return_ptr+1     " save offset into user's segment
+       sti     sp|stack_frame.return_ptr+1     " save indicators
+       sreg    sp|8
+       eppbp   bb|fio_ps.stack_frame_p,*       " load ptr to fortran_io_'s static stack frame
+       epp5      sp|stack_frame.next_sp,*      " use parents next_sp
+       spri5     bp|stack_frame.next_sp        " for fortran_io_'s next_sp
+       spri5     bp|4                          " & for fortran_io_'s perm extension
+       spribp  sp|stack_frame.next_sp  " store as next sp for user frame
+       eppsp   bp|0                    " activate fortran_io_'s stack frame
+       sxl6    bb|fio_ps.label_index_addr,*    " store index value for fortran_io_'s transfer
+       ldi     0,dl                    " force binary floating point mode
+       tra     bb|fio_ps.label_addr,*  " transfer directly into fortran_io_
+"
+"      Transmission operators entered with pointer to element in pr2, descriptor in a,
+"      and count in q. Read comments preceding the label "fortran_read" before modifying
+"      this operator.
+"
+
+fortran_scalar_xmit:
+fortran_array_xmit:
+       eax6    15
+
+ft_fast_xmit:
+       lprpbb  sp|stack_frame.support_ptr      " load ptr to fortran_io_'s fio_ps
+       spribp  bb|fio_ps.element_ptr
+       staq    bb|fio_ps.ele_desc_and_count
+       tra     ft_fast_call
+"
+"      File control operator entered with unit number in q, job_bits in a. Read comments
+"      preceding the label "fortran_read" before modifying this operator.
+"
+fortran_manip:
+       eax6    13
+       tra     ft_io
+"
+"      Termination operator, no registers. Read comments preceding the label
+"      "fortran_read" before modifying this operator.
+"
+fortran_terminate:
+       eax6    14
+       lprpbb  sp|stack_frame.support_ptr      " load ptr to fortran_io_'s fio_ps
+       tra     ft_fast_call
+"
+"      fortran open element
+"
+"      Called with:
+"      a-reg   = bit string (boolean value)
+"      q-reg   = integer (string length, etc.)
+"      x1      = case selector
+"      pr2     = string pointer
+"      pr3     = PS.buffer_p
+"
+ftn_open_element:
+       tra     *+1,1*
+       arg     ftn_open_indicators                     " 0
+       arg     ftn_open_status                 " 1
+       arg     ftn_open_io_switch                      " 2
+       arg     ftn_open_attach_desc            " 3
+       arg     ftn_open_filename                       " 4
+       arg     ftn_open_mode                   " 5
+       arg     ftn_open_access                 " 6
+       arg     ftn_open_form                   " 7
+       arg     ftn_open_max_rec_len            " 8
+       arg     ftn_open_binary                 " 9
+       arg     ftn_open_prompt                 " 10
+       arg     ftn_open_carriage                       " 11
+       arg     ftn_open_defer                  " 12
+       arg     ftn_open_blank                  " 13
+
+ftn_open_indicators:
+       sta     pr3|fortran_open_data.specified
+       tra     sp|tbp,*0
+
+       macro   ftn_open_string
+ftn_open_&1:
+       stq     pr3|fortran_open_data.&1
+       lxl1    pr3|fortran_open_data.char_str
+       stx1    pr3|fortran_open_data.&1
+       mlr     (pr,rl),(pr,x1,rl)
+       desc9a  pr2|0,ql
+       desc9a  pr3|fortran_open_data.char_str+1,ql
+       asq     pr3|fortran_open_data.char_str
+       tra     sp|tbp,*0
+       &end
+
+       ftn_open_string status
+
+       ftn_open_string io_switch
+
+       ftn_open_string attach_desc
+
+       ftn_open_string filename
+
+       ftn_open_string mode
+
+       ftn_open_string access
+
+       ftn_open_string form
+
+       ftn_open_string blank
+
+ftn_open_max_rec_len:
+       stq     pr3|fortran_open_data.max_rec_len
+       tra     sp|tbp,*0
+
+       macro   ftn_open_flag
+ftn_open_&1:
+       sta     pr3|fortran_open_data.&1
+       tra     sp|tbp,*0
+       &end
+
+       ftn_open_flag   binary
+
+       ftn_open_flag   prompt
+
+       ftn_open_flag   carriage
+
+       ftn_open_flag   defer
+"
+"
+"      ftn_inquire_element
+"
+"      Called with:
+"      a       = bit mask
+"      q       = string length or unit number
+"      pr2     = data pointer
+"      pr3     = area pointer
+"      x1      = case selector
+"
+ftn_inquire_element:
+       tra     *+1,x1*
+       arg     ftn_inquire_indicators          " 0
+       arg     ftn_inquire_noop                        " 1
+       arg     ftn_inquire_noop                        " 2
+       arg     ftn_inquire_noop                        " 3
+       arg     ftn_inquire_filename            " 4
+       arg     ftn_inquire_noop                        " 5
+       arg     ftn_inquire_access                      " 6
+       arg     ftn_inquire_form                        " 7
+       arg     ftn_inquire_recl                        " 8
+       arg     ftn_inquire_noop                        " 9
+       arg     ftn_inquire_noop                        " 10
+       arg     ftn_inquire_noop                        " 11
+       arg     ftn_inquire_noop                        " 12
+       arg     ftn_inquire_blank                       " 13
+       arg     ftn_inquire_unit                        " 14
+       arg     ftn_inquire_noop                        " 15
+       arg     ftn_inquire_noop                        " 16
+       arg     ftn_inquire_exist                       " 17
+       arg     ftn_inquire_opened                      " 18
+       arg     ftn_inquire_number                      " 19
+       arg     ftn_inquire_named                       " 20
+       arg     ftn_inquire_name                        " 21
+       arg     ftn_inquire_sequential          " 22
+       arg     ftn_inquire_formatted           " 23
+       arg     ftn_inquire_unformatted         " 24
+       arg     ftn_inquire_nextrec                     " 25
+       arg     ftn_inquire_direct                      " 26
+
+
+ftn_inquire_indicators:
+       sta     pr3|ftn_inquire_data.specified
+       tra     sp|tbp,*x0
+
+ftn_inquire_noop:
+       tra     sp|tbp,*x0
+
+ftn_inquire_filename:
+       mlr     (pr,rl),(pr),fill(040)
+       desc9a  pr2|0,ql
+       desc9a  pr3|ftn_inquire_data.filename,168
+       tra     sp|tbp,*x0
+
+ftn_inquire_unit:
+       stq     pr3|ftn_inquire_data.unit
+       tra     sp|tbp,*x0
+
+       macro   ftn_inquire_string
+ftn_inquire_&1:
+       sprp2   pr3|ftn_inquire_data.&1
+       stq     pr3|ftn_inquire_data.&1+1
+       tra     sp|tbp,*x0
+       &end
+
+       ftn_inquire_string      access
+
+       ftn_inquire_string      form
+
+       ftn_inquire_string      blank
+
+       ftn_inquire_string      name
+
+       ftn_inquire_string      sequential
+
+       ftn_inquire_string      formatted
+
+       ftn_inquire_string      unformatted
+
+       ftn_inquire_string      direct
+
+       macro   ftn_inquire_word
+ftn_inquire_&1:
+       sprp2   pr3|ftn_inquire_data.&1
+       tra     sp|tbp,*x0
+       &end
+
+       ftn_inquire_word        recl
+
+       ftn_inquire_word        exist
+
+       ftn_inquire_word        opened
+
+       ftn_inquire_word        number
+
+       ftn_inquire_word        named
+
+       ftn_inquire_word        nextrec
+"
+"
+"      get address of I/O area operator, no registers. Read comments preceding the label
+"      "fortran_read" before modifying this operator.
+"
+ftn_get_area_ptr:
+       eax6    22
+       szn     sp|ps_ptr                       " <0 if fortran_io_ already has a stack frame
+       tpl     ft_io1
+       lprpbb  sp|stack_frame.support_ptr      " load ptr to fortran_io_'s fio_ps
+       tra     ft_fast_call
+\f
+"
+"      operators to do pl1 pointer function, entered with pointer to area in bp
+"      and offset in q.
+"
+pointer_easy:
+pointer_hard:
+       cmpq    nullo           are we converting null offset
+       tnz     4,ic            no, do conversion
+       ldaq    null            yes, get null ptr
+       eppbp   null,*          and in bp
+       tra     sp|tbp,*0               and return
+       spribp  sp|temp
+       adlq    sp|temp+1               add in word and bit offset
+       stq     sp|temp+1               ..
+       eppbp   sp|temp,*               load ptr into bp
+       ldaq    sp|temp         and into aq
+       tra     sp|tbp,*0               and return
+"
+"      operator to do pl1 pointer function when packed ptr should be returned
+"
+pointer_easy_pk:
+pointer_hard_pk:
+       cmpq    nullo           return null if null input
+       tnz     4,ic
+       ldq     null_pk
+       eppbp   null,*
+       tra     sp|tbp,*0
+       spribp  sp|temp
+       adlq    sp|temp+1               add in word and bit offset
+       stq     sp|temp+1               ..
+       eppbp   sp|temp,*               load ptr into bp
+       ldaq    sp|temp         and into aq
+       tra     unpk_to_pk      go return packed value
+"
+"      operators for doing pl1 offset function.  entered with pointer to area in bp
+"      and pointer value in aq or q
+"
+offset_easy:
+offset_hard:
+       anaq    ptr_mask                is input null
+       cmpaq   nullx
+       tnz     3,ic            no, do conversion
+oe:    ldq     nullo           return null offset
+       tra     sp|tbp,*0
+oe1:   stq     sp|temp2                save word and bit offset
+       eaa     bp|0            get offset of area in au
+       era     mask_bit_one    form 2's complement of whole a-reg
+       adla    1,dl            w/o overflow
+       adla    sp|temp2                subtract area origin from word offset
+       lrl     36              shift into q
+       tra     sp|tbp,*0               and return
+"
+offset_easy_pk:
+offset_hard_pk:
+       cmpq    null_pk         is input null
+       tze     oe              yes, go return null offset
+       qlr     6               no, convert to proper form
+       qls     12
+       lls     18
+       qrl     3
+       lrl     18
+       tra     oe1             go subtract area origin
+"
+"      operator to alloc block of N words in the user storage area
+"      as defined by the stack header
+"      entered with N in q, returns with pointer to block
+"      in bp.
+"
+alloc_storage:
+       epbpsb  sp|0
+       eppbp   sb|stack_header.user_free_ptr,*
+       tra     <alloc_>|[op_storage_]
+"
+"      operator to alloc block of N words in user storage area
+"      entered with N in q and bp pointing at where to put ptr
+"
+alloc_block:
+       sxl0    sp|stack_frame.operator_ret_ptr save return
+       eax0    z_done          load index with return
+"
+call_alloc:
+       sreg    sp|8            save registers include size of block in Q
+       spribp  sp|arg_list+6   save address of ptr
+       eppbp   sp|8+5          get address of saved size
+       spribp  sp|arg_list+2   and use as 1st arg
+       epbpsb  sp|0                    get ptr to our stack header
+       eppbp   sb|stack_header.user_free_ptr  and pass user free ptr as 2nd arg
+       spribp  sp|arg_list+4
+       fld     3*2048,dl
+       eppbp   <alloc_>|[storage_]     call alloc_|storage_
+"
+call_alloc_free:
+       staq    sp|arg_list     save head of arg list
+       eppap   sp|arg_list     get ptr to arg list
+       epp1    4,ic            store return address and indicators
+       spri1   sp|stack_frame.return_ptr
+       sti     sp|stack_frame.return_ptr+1
+       callsp  bp|0
+       lreg    sp|8            restore registers
+       eppbp   sp|tbp,*                restore ptr in sp|stack_frame.return_ptr
+       spribp  sp|stack_frame.return_ptr
+       tra     0,0             return to caller
+"
+"      operator to free block pointed at by pointer pointed at by bp
+"
+free_block:
+       ldaq    bp|0            return if there is nothing to free
+       eraq    null
+       anaq    ptr_mask
+       tze     sp|tbp,*0
+       sxl0    sp|stack_frame.operator_ret_ptr save return
+       eax0    z_done          load index with return
+"
+call_free:
+       sreg    sp|8            save registers
+       spribp  sp|arg_list+2   save address of pointer
+       eppbp   <freen_>|[freen_]       get ptr to proc
+       fld     1*2048,dl
+       tra     call_alloc_free go call proc
+"
+"      operator to allocate controlled generation given size of descriptor in q
+"      and pointer to controlled block in bp
+"
+push_ctl_desc:
+       eax1    2               init offset
+       tra     push_ctl_data+1
+"
+"      operator to allocate controlled generation given size of data in q
+"      and pointer to controlled block in bp
+"
+push_ctl_data:
+       eax1    0               init offset
+"
+       sxl0    sp|stack_frame.operator_ret_ptr
+       spribp  sp|temp_pt      save ptr to ctl variable
+       adq     6,dl            add in size of ctl block
+       eppbp   sp|double_temp  get ptr to temp
+       tsx0    call_alloc      go allocate space
+       eppbp   sp|temp_pt,*    get back ptr to ctl block
+       epplp   sp|double_temp,*        get ptr to allocated space
+       ldaq    bp|0            copy current generation
+       staq    lp|0
+       ldaq    bp|2
+       staq    lp|2
+       ldaq    bp|4
+       staq    lp|4
+       sprilp  bp|4            store ptr to old generation
+       epplp   lp|6            get ptr to data|desc
+       sprilp  bp|0,1          store ptr to data|desc
+       tra     z_done          and return
+"
+"      operators to free a controlled generation, entered with
+"      pointer to controlled block in bp
+"
+pop_ctl_data:
+pop_ctl_desc:
+       ldaq    bp|4            return if there is nothing to free
+       eraq    null
+       anaq    ptr_mask
+       tze     sp|tbp,*0
+       sxl0    sp|stack_frame.operator_ret_ptr
+       epplp   bp|4,*          get ptr to previous generation
+       sprilp  sp|temp_pt      save for freeing
+       ldaq    lp|0            copy old generation into current
+       staq    bp|0
+       ldaq    lp|2
+       staq    bp|2
+       ldaq    lp|4
+       staq    bp|4
+       eppbp   sp|temp_pt      get ptr to block to be freed
+       tsx0    call_free               free it
+       tra     z_done          and then return
+"
+"      operator to return number of allocated generation of contrlled
+"      variable specified by bp
+"
+allocation:
+       eax1    0               init count
+       ldaq    bp|4            get ptr to previous generation
+       eraq    null            check for null
+       anaq    ptr_mask
+       tze     allocation_done null means done
+       eppbp   bp|4,*          not null, step backwards
+       adlx1   1,du            update count
+       tra     allocation+1
+allocation_done:
+       eaq     0,1             move count to ql
+       qrl     18
+       tra     sp|tbp,*0               and return
+"
+"      operators for unpacking|packing pictured values
+"      entered with pr1 -> target, pr3 -> picture, pr5 -> source
+"
+unpack_picture:
+       tsx1    get_our_lp
+       eppbp   <unpack_picture_>|[unpack_picture_]
+       tra     picture_common
+"
+pack_picture:
+       tsx1    get_our_lp
+       eppbp   <pack_picture_>|[pack_picture_]
+"
+picture_common:
+       sxl0    sp|stack_frame.operator_ret_ptr
+       eax0    z_done
+       sreg    sp|8
+       spri1   sp|arg_list+2
+       spri3   sp|arg_list+4
+       spri5   sp|arg_list+6
+       fld     3*2048,dl
+       tra     call_alloc_free
+"
+"      internal subroutine to signal a condition.  entered with
+"      bp pointing at name and x6 holding size of name
+"
+call_signal_:
+       sreg    sp|8            save registers for call
+       get_stack_offset
+       eppap   sp|stack_header.stack_end_ptr,au* get ptr to end of stack frame
+       eax0    48              increase stack frame by 48 words
+       adlx0   sp|stack_frame.next_sp+1        ..
+       stx0    sp|stack_frame.next_sp+1
+       stx0    sp|stack_header.stack_end_ptr+1,au adjust stack end pointer too
+       spri    ap|0            save bases
+       eppap   ap|24           get ptr to arg list
+       spribp  ap|2            save ptr to condition name as 1st arg
+       eppbp   null            get ptr to null file
+       spribp  ap|10           save as 5th arg
+signal_common:
+       stq     ap|14           store oncode value
+       eppbp   ap|14           use oncode value
+       spribp  ap|8            as 4th arg
+       stz     ap|15           save string length of condition name
+       sxl6    ap|15
+       eppbp   ap|15           pass name length
+       spribp  ap|4            as 2nd arg
+       lxl7    sp|stack_frame.operator_ret_ptr get ptr to entry into pl1_operators_
+       sbx7    1,du
+       eppbp   sp|tbp,*7               and save for use
+       spribp  ap|12           as 3rd arg
+       eppbp   ap|12
+       spribp  ap|6
+       fld     5*2048,dl               set number of args
+       staq    ap|0
+       tsx1    get_our_lp      get ptr to our linkage
+       epp1    4,ic            store return address and indicators
+       spri1   sp|stack_frame.return_ptr
+       sti     sp|stack_frame.return_ptr+1
+       tra     <pl1_signal_from_ops_>|[pl1_signal_from_ops_]
+       eppap   sp|stack_frame.next_sp,*        point 48 words past stack extension
+       lpri    ap|-48          restore pointer regs
+       get_stack_offset
+          ldx0      sp|stack_frame.next_sp+1 reset the stack frame size
+          sblx0     48,du               by subtracting the 48 words we added.
+       stx0    sp|stack_frame.next_sp+1 update next sp pointer
+       stx0    sp|stack_header.stack_end_ptr+1,au update stack end too
+       lreg    sp|8            restore machine registers
+       epbpap  sp|tbp,*0               restore return word pair
+       spriap  sp|stack_frame.return_ptr segment number
+       eppap   sp|stack_frame.operator_ptr,*   and pointer to operators
+       tra     0,1             and return
+"
+"      Subroutine to load PR4 with a pointer to linkage of
+"      pl1_operators_. Also sets PR7 to stack|0. Calling sequence:
+"              tsx1    get_our_lp
+"
+get_our_lp:
+       get_our_lp
+       tra     0,1             return with lp loaded to our linkage
+"
+"      operator to signal io condition, same as signal except sp|40 holds
+"      pointer to file name.
+"
+io_signal:
+       eax1    z_done          get return_pt for call to signal_common
+       sreg    sp|8            save register for call
+       get_stack_offset
+       sxl0    sp|stack_frame.operator_ret_ptr
+       eppap   sp|stack_header.stack_end_ptr,au* get pointer to end of stack frame
+       eax0    48              increase stack frame by 48 words
+       adlx0   sp|stack_frame.next_sp+1        ..
+       stx0    sp|stack_frame.next_sp+1        ..
+       stx0    sp|stack_header.stack_end_ptr+1,au      don't forget stack end ptr
+       spri    ap|0            store bases
+       eppap   ap|24           get ptr to arg list
+       ldq     =1000,dl                get oncode value
+       spribp  ap|2            store ptr to cond name as 1st arg
+       eppbp   sp|40           store ptr to file
+       spribp  ap|10           as 5th arg
+       tra     signal_common   jump into common section to signal and return
+"
+"      operator to set support bit in stack frame
+"
+set_support:
+       lda     stack_frame.support_bit,dl
+       orsa    sp|stack_frame.flag_word
+       tra     sp|tbp,*0
+"
+get_math_entry:
+       tsx1    get_our_lp
+       xec     fort_math_names-1,2             get entry
+       tra     sp|tbp,*0       return
+
+
+fort_math_names:
+       epp2    <fort_bfp_builtins_>|[exp_]             1
+       epp2    <fort_bfp_builtins_>|[alog_]            2
+       epp2    <fort_bfp_builtins_>|[alog10_]  3
+       epp2    <fort_bfp_builtins_>|[atan_]            4
+       epp2    <fort_bfp_builtins_>|[atan2_]           5
+       epp2    <fort_bfp_builtins_>|[sin_]             6
+       epp2    <fort_bfp_builtins_>|[cos_]             7
+       epp2    <fort_bfp_builtins_>|[tanh_]            8
+       epp2    <fort_bfp_builtins_>|[sqrt_]            9
+       epp2    <fort_bfp_builtins_>|[dmod_]            10
+       epp2    <fort_bfp_builtins_>|[dexp_]            11
+       epp2    <fort_bfp_builtins_>|[dlog_]            12
+       epp2    <fort_bfp_builtins_>|[dlog10_]  13
+       epp2    <fort_bfp_builtins_>|[datan_]           14
+       epp2    <fort_bfp_builtins_>|[datan2_]  15
+       epp2    <fort_bfp_builtins_>|[dsin_]            16
+       epp2    <fort_bfp_builtins_>|[dcos_]            17
+       epp2    <fort_bfp_builtins_>|[dsqrt_]           18
+       epp2    <fort_bfp_builtins_>|[cabs_]            19
+       epp2    <fort_bfp_builtins_>|[cexp_]            20
+       epp2    <fort_bfp_builtins_>|[clog_]            21
+       epp2    <fort_bfp_builtins_>|[csin_]            22
+       epp2    <fort_bfp_builtins_>|[ccos_]            23
+       epp2    <fort_bfp_builtins_>|[csqrt_]           24
+       epp2    <fort_bfp_builtins_>|[cxp2_]            25
+       epp2    <fort_bfp_builtins_>|[tan_]             26
+       epp2    <fort_bfp_builtins_>|[dtan_]            27
+       epp2    <fort_bfp_builtins_>|[asin_]            28
+       epp2    <fort_bfp_builtins_>|[dasin_]           29
+       epp2    <fort_bfp_builtins_>|[acos_]            30
+       epp2    <fort_bfp_builtins_>|[dacos_]           31
+       epp2    <fort_int_builtins_>|[index_]           32
+       epp2    <fort_bfp_builtins_>|[dtanh_]           33
+       epp2    <fort_bfp_builtins_>|[sinh_]            34
+       epp2    <fort_bfp_builtins_>|[dsinh_]           35
+       epp2    <fort_bfp_builtins_>|[cosh_]            36
+       epp2    <fort_bfp_builtins_>|[dcosh_]           37
+       epp2    <fort_bfp_builtins_>|[abs_]             38
+       epp2    <fort_int_builtins_>|[iabs_]            39
+       epp2    <fort_bfp_builtins_>|[dabs_]            40
+       epp2    <fort_bfp_builtins_>|[dim_]             41
+       epp2    <fort_int_builtins_>|[idim_]            42
+       epp2    <fort_bfp_builtins_>|[ddim_]            43
+       epp2    <fort_bfp_builtins_>|[sign_]            44
+       epp2    <fort_int_builtins_>|[isign_]           45
+       epp2    <fort_bfp_builtins_>|[dsign_]           46
+       epp2    <fort_bfp_builtins_>|[aint_]            47
+       epp2    <fort_bfp_builtins_>|[aimag_]           48
+       epp2    <fort_bfp_builtins_>|[conjg_]           49
+       epp2    <fort_int_builtins_>|[len_]             50
+       epp2    <fort_bfp_builtins_>|[dint_]            51
+       epp2    <fort_bfp_builtins_>|[anint_]           52
+       epp2    <fort_bfp_builtins_>|[dnint_]           53
+       epp2    <fort_bfp_builtins_>|[nint_]            54
+       epp2    <fort_bfp_builtins_>|[idnint_]  55
+       epp2    <fort_bfp_builtins_>|[dprod_]           56
+       epp2    <fort_int_builtins_>|[mod_]             57
+       epp2    <fort_bfp_builtins_>|[amod_]            58
+       epp2    <fort_int_builtins_>|[ilr_]             59
+       epp2    <fort_int_builtins_>|[ils_]             60
+       epp2    <fort_int_builtins_>|[irl_]             61
+       epp2    <fort_int_builtins_>|[irs_]             62
+
+fortran_end:
+       ldq     4,dl
+       stq     sp|arg_list
+       stz     sp|arg_list+1
+       epp0    sp|arg_list
+       tsx1    get_our_lp
+       callsp  <fortran_stop_>|[fortran_end]
+
+
+fortran_pause:
+       eax2    0
+       tra     pause_stop
+
+fortran_stop:
+       eax2    1
+
+pause_stop:
+       spri2   sp|arg_list+2   argument 1
+       orq     =o524000,du
+       stq     sp|temp
+       epp2    sp|temp
+       spri2   sp|arg_list+4   descriptor 1
+       fld     1*2048,dl               one argument
+       eaq     0,au            there are descriptors
+       staq    sp|arg_list
+       epp0    sp|arg_list     get argument list header
+       stx0    sp|stack_frame.return_ptr+1     save return point
+       sti     sp|stack_frame.return_ptr+1     save indicators
+       tsx1    get_our_lp
+       xec     pause_stop_names,2
+       callsp  pr2|0
+
+pause_stop_names:
+       epp2    <fortran_pause_>|[fortran_pause_]
+       epp2    <fortran_stop_>|[fortran_stop_]
+
+fortran_chain:
+       spri2   sp|arg_list+2   argument 1
+
+       ldaq    old_sys_name    old system name
+       staq    pr2|43
+
+       tsx1    get_our_lp
+       epp2    <fast_related_data_>|[chain_entry]
+
+       fld     1*2048,dl               one argument
+       staq    sp|arg_list
+       epp0    sp|arg_list     get argument list header
+
+       epp3    pr2|2,*         get display pointer
+       spri3   pr0|2,au                store at the end of the argument list
+
+       stx0    sp|stack_frame.return_ptr+1     save return point
+       sti     sp|stack_frame.return_ptr+1     save indicators
+       callsp  pr2|0,*         make the call
+
+old_sys_name:
+       even
+       aci     "fortran "
+
+"
+"      Function:       enter Binary Floating Point (BFP) mode
+"
+"      Entry:  X0 = offset in caller's text section of return point
+"
+"      Exit:   PR0, (sp|stack_frame.operator_ptr) -> operator_table
+"
+enter_BFP_mode:
+       ldi     0,dl            clear HFP mode if it's set
+       epp0    operator_table  change to BFP operators
+       spri0   sp|stack_frame.operator_ptr
+       tra     sp|tbp,*x0
+
+"
+"      Function:       enter Hexadecimal Floating Point (HFP) mode
+"
+"      Entry:  X0 = offset in caller's text section of return point
+"
+"      Exit:   PR0, (sp|stack_frame.operator_ptr) = hfp_operator_table
+"
+"      Note:   It is not sufficient to just request HFP mode.  We must
+"              check that our request has been honoured, since if HFP
+"              mode has not been enabled (or if it is not supported), a
+"              request to enter HFP mode is simply ignored.  If we find
+"              that our request to enter HFP mode has not been honoured,
+"              we attempt to enable HFP mode.  If we are unsuccessful,
+"              we signal the condition 'cannot_enable_HFP_mode'.  If we
+"              are restarted after signalling this condition, we repeat
+"              all the above steps.
+"
+enter_HFP_mode:
+       ldi     HFP_mask,dl     request HFP mode
+       fld     P1.0H,du                check if request honoured
+       fad     P0.0H,du
+       sba     =o020000,du
+       tze     enter_HFP_mode.entered
+       lda     =o600000,du     try to enable HFP mode
+       tsx1    call_set_hexfp_control
+       ldi     HFP_mask,dl     check if successful
+       fld     P1.0H,du
+       fad     P0.0H,du
+       sba     =o020000,du
+       tze     enter_HFP_mode.entered
+       ldi     =0,dl           clear HFP mode request
+       eppbp   =22acannot_enable_HFP_mode
+       eax6    22
+       ldq     =1000,dl
+       tsx1    call_signal_    signal 'cannot_enable_HFP_mode' condition
+       tra     enter_HFP_mode  try again
+
+enter_HFP_mode.entered:
+       epp0    hfp_operator_table      change to HFP operators
+       spri0   sp|stack_frame.operator_ptr
+       tra     sp|tbp,*x0
+
+"
+"      Function:       call 'hcs_$set_hexfp_control'.
+"
+"      Entry:  A = desired value for 1st argument:
+"                  1b2 => retain current mode
+"                  2b2 => disable HFP mode
+"                  3b2 => enable HFP mode
+"              X1 = offset of return address
+"
+"      Exit:   A = returned value of 2nd argument:
+"                  2b2 => HFP mode was disabled before call
+"                  3b2 => HFP mode was enabled before call
+"              Q = returned value of 3rd argument:
+"                  a standard system status code.
+"
+"      Alters: A, Q, (sp|8:sp|15).
+"
+call_set_hexfp_control:
+       sreg    sp|8            save X0:X7, AQ and E
+       get_stack_offset
+       eppap   sp|stack_header.stack_end_ptr,au* get ptr to end of stack frame
+       eax0    32              increase stack frame by 32 words
+       adlx0   sp|stack_frame.next_sp+1        ..
+       stx0    sp|stack_frame.next_sp+1
+       stx0    sp|stack_header.stack_end_ptr+1,au adjust stack end pointer too
+       spri    ap|0            save PR0:PR7
+       eppap   ap|16           form argument list
+       fld     3*2048,dl
+       staq    ap|0            there are 3 arguments
+       epp1    sp|8+4
+       spri1   ap|2            1st argument is cache for A
+       spri1   ap|4            2nd argument is cache for A
+       epp1    sp|8+5
+       spri1   ap|6            3rd argument is cache for Q
+       tsx1    get_our_lp
+       epp1    4,ic            make the call:
+         spri1   sp|stack_frame.return_ptr
+         sti     sp|stack_frame.return_ptr+1
+         callsp          <hcs_>|[set_hexfp_control]
+       eppap   sp|stack_frame.next_sp,*        point 32 words past stack extension
+       lpri    ap|-32          restore pointer regs
+       get_stack_offset
+       ldx0    sp|5            get offset of original end of frame
+       stx0    sp|stack_frame.next_sp+1 update next sp pointer
+       stx0    sp|stack_header.stack_end_ptr+1,au update stack end too
+       lreg    sp|8            restore machine registers
+       epbpap  sp|tbp,*0               restore return word pair
+       spriap  sp|stack_frame.return_ptr segment number
+       eppap   sp|stack_frame.operator_ptr,*   and pointer to operators
+       tra     0,x1            return
+
+"
+"      this code execute for unimplemented operators
+"
+unimp: spribp  sp|double_temp  save bp
+       stx6    sp|temp2
+       eppbp   error_name      signal error condition
+       eax6    error_length
+       ldq     =710,dl         with oncode = 710
+       tra     ssc
+error_name:
+       aci     "error"
+       equ     error_length,5
+"
+"      Single word mask arrays are used only by operators
+"
+bit_mask_one:
+       vfd     0/-1,36/0
+       vfd     1/-1,35/0
+       vfd     2/-1,34/0
+       vfd     3/-1,33/0
+       vfd     4/-1,32/0
+       vfd     5/-1,31/0
+       vfd     6/-1,30/0
+       vfd     7/-1,29/0
+       vfd     8/-1,28/0
+       vfd     9/-1,27/0
+       vfd     10/-1,26/0
+       vfd     11/-1,25/0
+       vfd     12/-1,24/0
+       vfd     13/-1,23/0
+       vfd     14/-1,22/0
+       vfd     15/-1,21/0
+       vfd     16/-1,20/0
+       vfd     17/-1,19/0
+       vfd     18/-1,18/0
+       vfd     19/-1,17/0
+       vfd     20/-1,16/0
+       vfd     21/-1,15/0
+       vfd     22/-1,14/0
+       vfd     23/-1,13/0
+       vfd     24/-1,12/0
+       vfd     25/-1,11/0
+       vfd     26/-1,10/0
+       vfd     27/-1,9/0
+       vfd     28/-1,8/0
+       vfd     29/-1,7/0
+       vfd     30/-1,6/0
+       vfd     31/-1,5/0
+       vfd     32/-1,4/0
+       vfd     33/-1,3/0
+       vfd     34/-1,2/0
+       vfd     35/-1,1/0
+"
+mask_bit_one:
+       vfd     0/0,36/-1
+       vfd     1/0,35/-1
+       vfd     2/0,34/-1
+       vfd     3/0,33/-1
+       vfd     4/0,32/-1
+       vfd     5/0,31/-1
+       vfd     6/0,30/-1
+       vfd     7/0,29/-1
+       vfd     8/0,28/-1
+       vfd     9/0,27/-1
+       vfd     10/0,26/-1
+       vfd     11/0,25/-1
+       vfd     12/0,24/-1
+       vfd     13/0,23/-1
+       vfd     14/0,22/-1
+       vfd     15/0,21/-1
+       vfd     16/0,20/-1
+       vfd     17/0,19/-1
+       vfd     18/0,18/-1
+       vfd     19/0,17/-1
+       vfd     20/0,16/-1
+       vfd     21/0,15/-1
+       vfd     22/0,14/-1
+       vfd     23/0,13/-1
+       vfd     24/0,12/-1
+       vfd     25/0,11/-1
+       vfd     26/0,10/-1
+       vfd     27/0,9/-1
+       vfd     28/0,8/-1
+       vfd     29/0,7/-1
+       vfd     30/0,6/-1
+       vfd     31/0,5/-1
+       vfd     32/0,4/-1
+       vfd     33/0,3/-1
+       vfd     34/0,2/-1
+       vfd     35/0,1/-1
+"
+single_bit:
+"
+       vfd     0/0,1/1
+       vfd     1/0,1/1
+       vfd     2/0,1/1
+       vfd     3/0,1/1
+       vfd     4/0,1/1
+       vfd     5/0,1/1
+       vfd     6/0,1/1
+       vfd     7/0,1/1
+       vfd     8/0,1/1
+       vfd     9/0,1/1
+       vfd     10/0,1/1
+       vfd     11/0,1/1
+       vfd     12/0,1/1
+       vfd     13/0,1/1
+       vfd     14/0,1/1
+       vfd     15/0,1/1
+       vfd     16/0,1/1
+       vfd     17/0,1/1
+       vfd     18/0,1/1
+       vfd     19/0,1/1
+       vfd     20/0,1/1
+       vfd     21/0,1/1
+       vfd     22/0,1/1
+       vfd     23/0,1/1
+       vfd     24/0,1/1
+       vfd     25/0,1/1
+       vfd     26/0,1/1
+       vfd     27/0,1/1
+       vfd     28/0,1/1
+       vfd     29/0,1/1
+       vfd     30/0,1/1
+       vfd     31/0,1/1
+       vfd     32/0,1/1
+       vfd     33/0,1/1
+       vfd     34/0,1/1
+       vfd     35/0,1/1
+"
+floor_ceil_mask:
+"
+       vfd     36/0,0/-1
+       vfd     35/0,1/-1
+       vfd     34/0,2/-1
+       vfd     33/0,3/-1
+       vfd     32/0,4/-1
+       vfd     31/0,5/-1
+       vfd     30/0,6/-1
+       vfd     29/0,7/-1
+       vfd     28/0,8/-1
+       vfd     27/0,9/-1
+       vfd     26/0,10/-1
+       vfd     25/0,11/-1
+       vfd     24/0,12/-1
+       vfd     23/0,13/-1
+       vfd     22/0,14/-1
+       vfd     21/0,15/-1
+       vfd     20/0,16/-1
+       vfd     19/0,17/-1
+       vfd     18/0,18/-1
+       vfd     17/0,19/-1
+       vfd     16/0,20/-1
+       vfd     15/0,21/-1
+       vfd     14/0,22/-1
+       vfd     13/0,23/-1
+       vfd     12/0,24/-1
+       vfd     11/0,25/-1
+       vfd     10/0,26/-1
+       vfd     9/0,27/-1
+       vfd     8/0,28/-1
+       vfd     7/0,29/-1
+       vfd     6/0,30/-1
+       vfd     5/0,31/-1
+       vfd     4/0,32/-1
+       vfd     3/0,33/-1
+       vfd     2/0,34/-1
+       vfd     1/0,35/-1
+       vfd     0/0,36/-1
+" \f
+"
+"      Entry operators, entered by following sequence in text section
+"
+"              eax7    stack_size
+"              eppbp   sb|stack_header.pl1_operators_ptr,*
+"              tspbp   bp|n    (bp points at segdef operator_table)
+"              vfd     18/n_args,18/unused
+"              vfd     18/link,18/block
+"
+"
+"
+"
+"      The following macro is the ext_entry macro. It conditionally expands the
+"      trace code if the first argument is "trace_".  It conditionally sets
+"      the static ptr if the second argument is "ss_".
+"
+
+       macro   ext_entry
+&1&2ext_entry:
+       eppbp   bp|-3           get correct entry pointer value
+       trace   &1
+       epaq    bp|0            get segment number in a
+       lprplp  sb|stack_header.lot_ptr,*au get seg no, offset of linkage from packed ptr
+       ife     &2,ss_
+       lprplb  sb|stack_header.isot_ptr,*au get seg no, offset of static from packed ptr
+ifend
+       eppbb   sb|stack_header.stack_end_ptr,* get ptr to next stack frame
+       sprisp  bb|stack_frame.prev_sp set back ptr of new frame
+       spriap  bb|stack_frame.arg_ptr save arg pointer
+       eppab   bb|0,7          get pointer to end of new frame
+       spriab  bb|stack_frame.next_sp set next pointer of new frame
+       spriab  sb|stack_header.stack_end_ptr update stack end ptr
+       eppsp   bb|0            update sp
+&1&2save_link:
+       sprilp  sp|linkage_ptr  save ptr to linkage in stack head
+       ife     &2,ss_
+       sprplb  sp|stack_frame.static_ptr save static ptr
+ifend
+       spribp  sp|stack_frame.entry_ptr save ptr to entry point
+&1&2init_stack_join:
+       spbpbp  sp|text_base_ptr        save ptr to base of text segment
+       spbpbp  sp|stack_frame.return_ptr init procedure call return point
+       stz     sp|stack_frame.operator_ret_ptr init operator return offset
+"
+       eppap   &1operator_table        and pointer to operators
+       spriap  sp|stack_frame.operator_ptr save pointer to operator segment
+       spriab  sp|4            save pointer to end of frame for temp extensions
+       ldi     0,dl            reset all indicators (overflow mask in particular)
+       tra     bp|5            and return to user program
+       &end
+
+       ext_entry
+"
+"      The following macro is analogous to ext_entry except for entries which expect
+"      descriptors.
+"
+       macro   ext_entry_desc
+&1&2ext_entry_desc:
+       eppbp   bp|-3           get correct entry pointer value
+       trace   &1
+       epaq    bp|0            get segment number of text
+       lprplp  sb|stack_header.lot_ptr,*au get seg no, offset of linkage from  packed ptr
+       ife     &2,ss_
+       lprplb  sb|stack_header.isot_ptr,*au get seg no, offset of static from packed ptr
+ifend
+       eppbb   sb|stack_header.stack_end_ptr,* get ptr to next stack frame
+       sprisp  bb|stack_frame.prev_sp set back ptr of new frame
+       spriap  bb|stack_frame.arg_ptr save arg pointer
+       eppab   bb|0,7          get pointer to end of new frame
+       spriab  bb|stack_frame.next_sp set next pointer of new frame
+       spriab  sb|stack_header.stack_end_ptr set new stack end ptr
+       eppsp   bb|0            update sp
+"
+&1&2eed:
+       lda     ap|0            get 2*n_args in au, code in al
+       cana    8,dl            is there an extra arg
+       tze     2,ic            no
+       ada     2,du            yes, allow for it
+       eppbb   ap|2,au         get ptr to descriptors
+       spribb  sp|descriptor_ptr       set ptr in stack frame
+       tra     &1&2save_link           join common section
+       &end
+"
+       ext_entry_desc
+
+"
+"      The following macro is the other_entries macro.  It conditionally
+"      sets the static ptr if the first argument is "ss_".
+"
+       macro   other_entries
+&1int_entry:
+       epaq    bp|0            get segment number of text
+       lprplp  sb|stack_header.lot_ptr,*au get seg no, offset of linkage from packed ptr
+       ife     &1,ss_
+       lprplb  sb|stack_header.isot_ptr,*au get seg no, offset of static from packed ptr
+ifend
+       eppbb   sb|stack_header.stack_end_ptr,* get ptr to next stack frame
+       sprisp  bb|stack_frame.prev_sp set back ptr of new frame
+       spriap  bb|stack_frame.arg_ptr save arg pointer
+       eppab   bb|0,7          get pointer to end of new frame
+       spriab  bb|stack_frame.next_sp set next pointer of new frame
+       spriab  sb|stack_header.stack_end_ptr set new stack end ptr
+       eppsp   bb|0            update sp
+"
+       lda     ap|0            get 2*n_args in au
+"
+&1set_display:
+       eppbb   ap|2,au*                get display ptr
+       spribb  sp|display_ptr  and save in stack frame
+       eppbp   bp|-3           set correct entry pointer value
+       tra     &1save_link             join common section
+"
+&1int_entry_desc:
+       epaq    bp|0            get segment number of text
+       lprplp  sb|stack_header.lot_ptr,*au get seg no, offset of linkage from packed ptr
+       ife     &1,ss_
+       lprplb  sb|stack_header.isot_ptr,*au get seg no, offset of static from packed ptr
+ifend
+       eppbb   sb|stack_header.stack_end_ptr,* get ptr to next stack frame
+       sprisp  bb|stack_frame.prev_sp set back ptr of new frame
+       spriap  bb|stack_frame.arg_ptr save arg pointer
+       eppab   bb|0,7          get pointer to end of new frame
+       spriab  bb|stack_frame.next_sp set next pointer of new frame
+       spriab  sb|stack_header.stack_end_ptr set new stack end ptr
+       eppsp   bb|0            update sp
+"
+       lda     ap|0            get 2*n_args in au, code in al
+       eppbb   ap|4,au         get ptr to descriptors
+       spribb  sp|descriptor_ptr       set ptr in stack frame
+       tra     &1set_display   go set display ptr
+"
+&1val_entry_desc:
+       eax0    &1eed           get final destination
+       tra     &1val_entry+1   join common validate code
+"
+&1val_entry:
+       eax0    &1save_link             get final destination
+"
+       spribp  sb|stack_header.stack_end_ptr,* save entry pointer
+       eppbb   sb|stack_header.stack_end_ptr,* get ptr to next stack frame
+       sprisp  bb|stack_frame.prev_sp set back ptr of new frame
+       spriap  bb|stack_frame.arg_ptr save arg pointer
+       eppab   bb|0,7          get pointer to end of new frame
+       spriab  bb|stack_frame.next_sp set next pointer of new frame
+       spriab  sb|stack_header.stack_end_ptr set up new end ptr
+       eppsp   bb|0            update sp
+"
+       epaq    bp|0            get segment number of text
+       lprplp  sb|stack_header.lot_ptr,*au get seg no, offset of linkage
+       ife     &1,ss_
+       lprplb  sb|stack_header.isot_ptr,*au get seg no, offset of static
+ifend
+       eppap   operator_table
+       spriap  sp|stack_frame.operator_ptr
+       eppap   sp|stack_frame.arg_ptr get ptr to arglist
+       spriap  sp|arg_list+2   save as arg of validate call
+       fld     2*1024,dl
+       staq    sp|arg_list
+       eppap   sp|arg_list     get ptr to arglist for validate call
+       sprplp  sp|4            save lp - we need it at save_link
+       ife     &1,ss_
+       sprplb  sp|5            save lb
+ifend
+       stx0    sp|8            save x0 for eventual exit
+       ldx1    bp|2            get link offset of validate proc
+       stcd    sp|stack_frame.return_ptr call the validate proc
+       tra     lp|0,1*
+       ldx0    sp|8            restore x0
+       lprplp  sp|4            and lp
+       ife     &1,ss_
+       lprplb  sp|5            and lb
+ifend
+       eppab   sb|stack_header.stack_end_ptr,*
+       eppap   sp|stack_frame.arg_ptr,* restore argument list pointer
+       eppbp   sp|0,*          restore entry return pointer
+       eppbp   bp|-3           set correct entry pointer value
+       tra     0,0             and re-enter main stream
+       &end
+"
+       other_entries
+"
+       ext_entry               ,ss_
+"
+       ext_entry_desc  ,ss_
+"
+       other_entries   ss_
+"
+"
+"      operator to enter a begin block
+"      calling sequence is:
+"
+"              eax7    stack_size
+"              tspbp   ap|enter_begin_block
+"              vfd     18/link,18/block        for symbol table
+"
+       macro   enter_begin
+&1enter_begin_block:
+       epplp   sp|linkage_ptr,*        get linkage pointer from parent frame
+       ife     &1,ss_
+       lprplb  sp|stack_frame.static_ptr       get static pointer from parent frame
+ifend
+       epbpsb  sp|0            get ptr to base of stack
+       eppbb   sb|stack_header.stack_end_ptr,* get ptr to next stack frame
+       sprisp  bb|stack_frame.prev_sp set back pointer of new frame
+       eppab   bb|0,7          get pointer to end of new frame
+       spriab  bb|stack_frame.next_sp set next pointer of new frame
+       spriab  sb|stack_header.stack_end_ptr set stack end pointer
+       sprisp  bb|display_ptr  set display pointer
+       eppsp   bb|0            update sp
+"
+       ldaq    null            set arg list pointer to null
+       staq    sp|stack_frame.arg_ptr ..
+       sprilp  sp|linkage_ptr  save linkage ptr
+       ife     &1,ss_
+       sprplb  sp|stack_frame.static_ptr       save static ptr
+ifend
+       eppbp   bp|-2
+       spribp  sp|stack_frame.entry_ptr
+       eppbp   bp|-2           get correct entry pointer
+       tra     init_stack_join go init stack frame
+       &end
+"
+       enter_begin
+"
+       enter_begin     ss_
+"
+"
+entry_operators_end:
+       zero    0,*     marks end of entry operators
+"
+"
+       even
+null:  its     -1,1,n
+nullx: oct     077777000043,000001000000
+null_pk:       oct     007777000001
+nullo: oct     777777777777
+one:   dec     0,1
+almost_one:
+hfp_almost_one:
+       oct     000777777777,777777777777
+k71b25:        oct     216000000000,000000000000
+"
+shift_bo:      dec     0b26,1b26,2b26,3b26,4b26,5b26,6b26,7b26,8b26,9b26
+       dec     10b26,11b26,12b26,13b26,14b26,15b26,16b26,17b26,18b26,19b26
+       dec     20b26,21b26,22b26,23b26,24b26,25b26,26b26,27b26,28b26,29b26
+       dec     30b26,31b26,32b26,33b26,34b26,35b26
+
+"
+" The follow line must appear after everything else in text segment
+"
+end_pl1_operators:
+       zero    0,*             marks end of pl1_operators
+"
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"                                                      "
+"              END OF WIRED SECTION                    "
+"                                                      "
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+" \f
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"                                                      "
+"              START OF PAGED SECTION                  "
+"                                                      "
+" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
+"
+" The following code is used when hexadecimal floating point mode has been
+"selected via a call to the 'enter_HFP_mode' operator.
+"
+       transfer_vector ,hfp_
+
+
+"
+"      Function:       ceiling of a float hex (71) number
+"
+"      Entry:  EAQ = number
+"              X0 = offset in caller's text section of return point
+"
+"      Exit:   EAQ = ceil(number)
+"
+hfp_ceil_fl:
+       tmi     6,ic            if number +ve then:
+         dfad    hfp_almost_one          EAQ = number + almost_one
+         fmp     P2.0H,du        EAQ = 2*(number + almost_one)
+         fad     =18b25,du       EAQ = 2*ceil(number)
+         fmp     P0.5H,du        EAQ = ceil(number)
+         tra     sp|tbp,*x0      return
+"                              else:
+         fmp     M2.0H,du        EAQ = 2*abs(number)
+         fad     =18b25,du       EAQ = 2*floor(abs(number))
+         fmp     M0.5H,du        EAQ = -floor(abs(number))
+         tra     sp|tbp,*x0      return
+
+
+"
+"      Function:       convert a float hex (71) number to fixed bin (71)
+"
+"      Entry:  EAQ = number
+"              X0 = offset in caller's text section of return point
+"
+"      Exit:   AQ = fixed (number, 71)
+"
+hfp_fl2_to_fx1:
+hfp_fl2_to_fx2:
+       fad     P0.0H,du
+       tmi     4,ic            if number +ve then:
+         fmp     P2.0H,du        EAQ = 2*number
+         ufa     =18b25,du       AQ = floor(number)
+         tra     sp|tbp,*x0      return
+"                              else:
+         fmp     M2.0H,du        EAQ = 2*abs(number)
+         ufa     =18b25,du       AQ = floor (abs (number))
+         negl    0               AQ = -floor(abs(number))
+         tra     sp|tbp,*x0      return
+
+
+"
+"      Function:       convert a float hex (71) number to fixed bin
+"              (71, scale)
+"
+"      Entry:  EAQ = number
+"              X0 = offset in caller's text section of the word
+"                   containing the scale factor in the format
+"                   8/71-scale,28/0
+"
+"      Exit:   to word after scale factor word with:
+"              AQ = floor(number * 2**scale)
+"
+"      Note:   The format of the word containing the scale factor is the
+"              same as that used when converting float bin (71) to fixed
+"              bin (71, scale).  THIS IS NOT THE BEST FORMAT FOR
+"              CONVERTING HEX NUMBERS.  It is used because that is what
+"              the current PL/I compiler generates.  If float hex is ever
+"              added as a proper 'pl1' data type, it would be wise to
+"              change the format of the scale word to contain the float
+"              hex (27) representation of 2**(scale-1).  This would
+"              shorten the conversion code to:
+"
+"hfp_fl2_to_fxscaled:
+"      fad     P0.0H,du
+"      tmi     4,ic            if number +ve then:
+"        fmp     sp|tbp,*x0      EAQ = 2*number * 2**scale
+"        ufa     =18b25,du       AQ = floor(number * 2**scale)
+"      tra     5,ic            else:
+"        fneg    0               EAQ = abs(number)
+"        fmp     sp|tbp,*x0      EAQ = 2*abs(number) * 2**scale
+"        ufa     =18b25,du       AQ = floor(abs(number) * 2**scale)
+"        negl    0               AQ = -floor(abs(number) * 2**scale)
+"      adx0    =1,du           skip scale word
+"      tra     sp|tbp,*x0      return
+"
+hfp_fl2_to_fxscaled:
+       staq    sp|temp         save mantissa of number
+       lda     sp|tbp,*x0      A = 8/71-scale,28/0
+       ars     28              A = 71-scale
+       neg     0               A = scale-71
+       ada     =72,dl          A = scale+1
+       lrs     2               A = floor((scale+1)/4)
+       qrl     34              Q = (scale+1) - 4*floor((scale+1)/4)
+       eax1    0,ql            X1 = (scale+1) - 4*floor((scale+1)/4)
+       ada     =1,dl           A = floor((scale+1)/4) + 1
+       ldq     =1,dl           Q = 2**0
+       qls     31,x1           Q = 2**(X1+31)
+       lls     28              A = HFP representation of 2**(scale+1)
+       sta     sp|temp2                save scale factor
+       ldaq    sp|temp         restore mantissa of number
+       tmi     4,ic            if number +ve then:
+         fmp     sp|temp2        EAQ = 2*number * 2**scale
+         ufa     =18b25,du       AQ = floor(number * 2**scale)
+       tra     5,ic            else:
+         fneg    0               EAQ = abs(number)
+         fmp     sp|temp2        EAQ = 2*abs(number) * 2**scale
+         ufa     =18b25,du       AQ = floor(abs(number) * 2**scale)
+         negl    0               AQ = -floor(abs(number) * 2**scale)
+       adx0    =1,du           skip scale word
+       tra     sp|tbp,*x0      return
+
+
+
+"
+"      Function:       floor of a float hex (71) number
+"
+"      Entry:  EAQ = number
+"              X0 = offset in caller's text section of return point
+"
+"      Exit:   EAQ = floor(number)
+"
+hfp_floor_fl:
+       tmi     5,ic            if number +ve then:
+         fmp     P2.0H,du        EAQ = 2*number
+         fad     =18b25,du       EAQ = 2*floor(number)
+         fmp     P0.5H,du        EAQ = floor(number)
+         tra     sp|tbp,*x0      return
+"                              else:
+         dfsb    hfp_almost_one          EAQ = -(abs(number) + almost_one)
+         fmp     M2.0H,du        EAQ = 2*(abs(number) + almost_one)
+         fad     =18b25,du       EAQ = 2*ceil(abs(number))
+         fmp     M0.5H,du        EAQ = -ceil(abs(number))
+         tra     sp|tbp,*x0      return
+
+
+"
+"      Function:       FORTRAN float hex (63) modulus: dmod(x, y)
+"
+"      Entry:  EAQ = x
+"              bp|0 -> y
+"              X0 = offset in caller's text section of return point
+
+"      Exit:   EAQ = if y=0 then 0 else x - trunc(x/y)*y
+"
+hfp_fort_dmod:
+       fszn    bp|0            return 0 if y is 0
+       tze     sp|tbp,*x0
+       dfstr   sp|temp         save x
+       dfdv    bp|0            EAQ = x/y
+       tmi     5,ic            if EAQ >= 0 then:
+          fmp     P2.0H,du        EAQ = 2*x/y
+          fad     =18b25,du       EAQ = 2*floor(x/y)
+          fmp     M0.5H,du        EAQ = -trunc(x/y)
+       tra     4,ic            else:
+          fmp     M2.0H,du        EAQ = 2*abs(x/y)
+          fad     =18b25,du       EAQ = 2*floor(abs(x/y))
+          fmp     P0.5H,du        EAQ = -trunc(x/y)
+       dfmp    bp|0            EAQ = -trunc(x/y)*y
+       dfad    sp|temp         EAQ = x - trunc(x/y)*y
+       tra     sp|tbp,*x0      return
+
+
+"
+"      Function:       FORTRAN float hex (27) modulus: amod(x, y)
+"
+"      Entry:  EAQ = x
+"              bp|0 -> y
+"              X0 = offset in caller's text section of return point
+"
+"      Exit:   EAQ = if y=0 then 0 else x - trunc(x/y)*y
+"
+hfp_fort_mdfl1:
+       fszn    bp|0            return 0 if y is 0
+       tze     sp|tbp,*x0
+       fstr    sp|temp         save x
+       fdv     bp|0            EAQ = x/y
+       tmi     5,ic            if EAQ >= 0 then:
+          fmp     P2.0H,du        EAQ = 2*x/y
+          fad     =18b25,du       EAQ = 2*floor(x/y)
+          fmp     M0.5H,du        EAQ = -trunc(x/y)
+       tra     4,ic            else:
+          fmp     M2.0H,du        EAQ = 2*abs(x/y)
+          fad     =18b25,du       EAQ = 2*floor(abs(x/y))
+          fmp     P0.5H,du        EAQ = -trunc(x/y)
+       fmp     bp|0            EAQ = -trunc(x/y)*y
+       fad     sp|temp         EAQ = x - trunc(x/y)*y
+       tra     sp|tbp,*x0      return
+
+
+"
+"      Function:       Get address of a specified FORTRAN intrinsic function.
+"
+"      Entry:  X0 = offset in caller's text section of return point.
+"              X2 = index of the intrinsic function.
+"
+"      Exit:   PR2 = address of entry point of specified intrinsic.
+"
+hfp_get_math_entry:
+       tsx1    get_our_lp
+       xec     hfp_fort_math_names-1,2 get entry
+       tra     sp|tbp,*0       return
+
+
+hfp_fort_math_names:
+       epp2    <fort_hfp_builtins_>|[exp_]             1
+       epp2    <fort_hfp_builtins_>|[alog_]            2
+       epp2    <fort_hfp_builtins_>|[alog10_]  3
+       epp2    <fort_hfp_builtins_>|[atan_]            4
+       epp2    <fort_hfp_builtins_>|[atan2_]           5
+       epp2    <fort_hfp_builtins_>|[sin_]             6
+       epp2    <fort_hfp_builtins_>|[cos_]             7
+       epp2    <fort_hfp_builtins_>|[tanh_]            8
+       epp2    <fort_hfp_builtins_>|[sqrt_]            9
+       epp2    <fort_hfp_builtins_>|[dmod_]            10
+       epp2    <fort_hfp_builtins_>|[dexp_]            11
+       epp2    <fort_hfp_builtins_>|[dlog_]            12
+       epp2    <fort_hfp_builtins_>|[dlog10_]  13
+       epp2    <fort_hfp_builtins_>|[datan_]           14
+       epp2    <fort_hfp_builtins_>|[datan2_]  15
+       epp2    <fort_hfp_builtins_>|[dsin_]            16
+       epp2    <fort_hfp_builtins_>|[dcos_]            17
+       epp2    <fort_hfp_builtins_>|[dsqrt_]           18
+       epp2    <fort_hfp_builtins_>|[cabs_]            19
+       epp2    <fort_hfp_builtins_>|[cexp_]            20
+       epp2    <fort_hfp_builtins_>|[clog_]            21
+       epp2    <fort_hfp_builtins_>|[csin_]            22
+       epp2    <fort_hfp_builtins_>|[ccos_]            23
+       epp2    <fort_hfp_builtins_>|[csqrt_]           24
+       epp2    <fort_hfp_builtins_>|[cxp2_]            25
+       epp2    <fort_hfp_builtins_>|[tan_]             26
+       epp2    <fort_hfp_builtins_>|[dtan_]            27
+       epp2    <fort_hfp_builtins_>|[asin_]            28
+       epp2    <fort_hfp_builtins_>|[dasin_]           29
+       epp2    <fort_hfp_builtins_>|[acos_]            30
+       epp2    <fort_hfp_builtins_>|[dacos_]           31
+       epp2    <fort_int_builtins_>|[index_]           32
+       epp2    <fort_hfp_builtins_>|[dtanh_]           33
+       epp2    <fort_hfp_builtins_>|[sinh_]            34
+       epp2    <fort_hfp_builtins_>|[dsinh_]           35
+       epp2    <fort_hfp_builtins_>|[cosh_]            36
+       epp2    <fort_hfp_builtins_>|[dcosh_]           37
+       epp2    <fort_hfp_builtins_>|[abs_]             38
+       epp2    <fort_int_builtins_>|[iabs_]            39
+       epp2    <fort_hfp_builtins_>|[dabs_]            40
+       epp2    <fort_hfp_builtins_>|[dim_]             41
+       epp2    <fort_int_builtins_>|[idim_]            42
+       epp2    <fort_hfp_builtins_>|[ddim_]            43
+       epp2    <fort_hfp_builtins_>|[sign_]            44
+       epp2    <fort_int_builtins_>|[isign_]           45
+       epp2    <fort_hfp_builtins_>|[dsign_]           46
+       epp2    <fort_hfp_builtins_>|[aint_]            47
+       epp2    <fort_hfp_builtins_>|[aimag_]           48
+       epp2    <fort_hfp_builtins_>|[conjg_]           49
+       epp2    <fort_int_builtins_>|[len_]             50
+       epp2    <fort_hfp_builtins_>|[dint_]            51
+       epp2    <fort_hfp_builtins_>|[anint_]           52
+       epp2    <fort_hfp_builtins_>|[dnint_]           53
+       epp2    <fort_hfp_builtins_>|[nint_]            54
+       epp2    <fort_hfp_builtins_>|[idnint_]  55
+       epp2    <fort_hfp_builtins_>|[dprod_]           56
+       epp2    <fort_int_builtins_>|[mod_]             57
+       epp2    <fort_hfp_builtins_>|[amod_]            58
+       epp2    <fort_int_builtins_>|[ilr_]             59
+       epp2    <fort_int_builtins_>|[ils_]             60
+       epp2    <fort_int_builtins_>|[irl_]             61
+       epp2    <fort_int_builtins_>|[irs_]             62
+
+"
+"      Function:       PL/I float hex (27) modulus: mod(x, y)
+"
+"      Entry:  EAQ = x
+"              bp|0 -> y
+"              X0 = offset in caller's text section of return point
+"
+"      Exit:   EAQ = if y=0 then x else x - floor(x/y)*y
+"
+hfp_mdfl1:
+       fszn    bp|0            return x if y = 0
+       tze     hfp_mdfl1a
+       fst     sp|temp         save x
+       fdv     bp|0            EAQ = x/y
+       tmi     5,ic            if EAQ >= 0 then:
+          fmp     P2.0H,du        EAQ = 2*(x/y)
+          fad     =18b25,du       EAQ = 2*floor(x/y)
+          fmp     M0.5H,du        EAQ = -floor(x/y)
+       tra     5,ic            else:
+          dfsb    hfp_almost_one          EAQ = -(abs(x/y) + almost_one)
+          fmp     M2.0H,du        EAQ = 2*(abs(x/y) + almost_one)
+          fad     =18b25,du       EAQ = 2*floor(abs(x/y) + almost_one)
+          fmp     P0.5H,du        EAQ = -floor(x/y)
+       fmp     bp|0            EAQ = -floor(x/y)*y
+       fad     sp|temp         EAQ = x - floor(x/y)*y
+       tra     sp|tbp,*x0      return
+
+hfp_mdfl1a:
+       fcmp    P0.0H,du                set indicators properly
+       tra     sp|tbp,*x0      return
+
+
+"
+"      Function:       PL/I float hex (63) modulus: mod(x, y)
+"
+"      Entry:  EAQ = x
+"              bp|0 -> y
+"              X0 = offset in caller's text section of return point
+"
+"      Exit:   EAQ = if y=0 then x else x - floor(x/y)
+"
+hfp_mdfl2:
+       dfst    sp|temp         save x
+       dfld    bp|0            load y
+       tze     hfp_mdfl2a      return x if y = 0
+       dfdi    bp|0            EAQ = x/y
+       tmi     5,ic            if EAQ >= 0 then:
+          fmp     P2.0H,du        EAQ = 2*(x/y)
+          fad     =18b25,du       EAQ = 2*floor(x/y)
+          fmp     M0.5H,du        EAQ = -floor(x/y)
+       tra     5,ic            else:
+          dfsb    hfp_almost_one          EAQ = -(abs(x/y) + almost_one)
+          fmp     M2.0H,du        EAQ = 2*(abs(x/y) + almost_one)
+          fad     =18b25,du       EAQ = 2*floor(abs(x/y) + almost_one)
+          fmp     P0.5H,du        EAQ = -floor(x/y)
+       dfmp    bp|0            EAQ = -floor(x/y)*y
+
+hfp_mdfl2a:
+       dfad    sp|temp         EAQ = if y=0 then x else x-floor(x/y)*y
+       tra     sp|tbp,*x0      return
+
+
+"
+"      Function:       round a float hex (71) number to fixed bin (71)
+"
+"      Entry:  EAQ = number
+"              X0 = offset in caller's text section of return point
+"
+"      Exit:   AQ = nearest fixed bin (71) number
+"
+hfp_nearest_integer:
+       tmi     5,ic            if number +ve then:
+         fad     P0.5H,du        EAQ = number + 0.5
+         fmp     P2.0H,du        EAQ = 2*(number + 0.5)
+         ufa     =18b25,du       AQ = floor(number + 0.5)
+         tra     sp|tbp,*x0      return
+"                              else:
+         fad     M0.5H,du        EAQ = -(abs(number) + 0.5)
+         fmp     M2.0H,du        EAQ = 2*(abs(number) + 0.5)
+         ufa     =18b25,du       AQ = floor(abs(number) + 0.5)
+         negl    0               AQ = -floor(abs(number) + 0.5)
+         tra     sp|tbp,*x0      return
+
+
+"
+"      Function:       round off a float hex (71) number
+"
+"      Entry:  EAQ = number
+"              X0 = offset in caller's text section of return point
+"
+"      Exit:   EAQ = nearest whole float hex (71) number
+"
+hfp_nearest_whole_number:
+       tmi     6,ic            if number +ve then:
+         fad     P0.5H,du        EAQ = number + 0.5
+         fmp     P2.0H,du        EAQ = 2*(number + 0.5)
+         fad     =18b25,du       EAQ = 2*floor(number + 0.5)
+         fmp     P0.5H,du        EAQ = floor(number + 0.5)
+         tra     sp|tbp,*x0      return
+"                              else:
+         fad     M0.5H,du        EAQ = -(abs(number) + 0.5)
+         fmp     M2.0H,du        EAQ = 2*(abs(number) + 0.5)
+         fad     =18b25,du       EAQ = 2*floor(abs(number) + 0.5)
+         fmp     M0.5H,du        EAQ = -floor(abs(number) + 0.5)
+         tra     sp|tbp,*x0      return
+
+
+"
+"      Function:       convert a fixed bin (35) number to complex float hex (27)
+"
+"      Entry:  Q = number
+"              X0 = offset in caller's text section of return point
+"
+"      Exit:   EAQ = complex float hex (27) result
+"
+hfp_rfb1_to_cflb1:
+       lls     36              convert to fixed bin (71) first
+       lrs     36
+
+
+"
+"      Function:       convert from fixed bin (71) to complex float hex (27)
+"
+"      Entry:  AQ = number
+"              X0 = offset in caller's text section of return point
+"
+"      Exit:   EAQ = complex float hex (27) result
+"
+hfp_rfb2_to_cflb1:
+       lde     =18b25,du               EAQ = unnormalized 2*float(source)
+       fad     P0.0H,du                EAQ = 2*float(source)
+       fmp     P0.5H,du                EAQ = float(source)
+       fst     sp|temp
+       lda     sp|temp         load real part
+       ldq     P0.0H,du                load imaginary part
+       tra     sp|tbp,*x0      return
+
+
+"
+"      Function:       truncate a float hex (71) number
+"
+"      Entry:  EAQ = number
+"              X0 = offset in caller's text section of return point
+"
+"      Exit:   EAQ = trunc (number)
+"
+hfp_trunc_fl:
+       tmi     5,ic            if number +ve then:
+         fmp     P2.0H,du        EAQ = 2*number
+         fad     =18b25,du       EAQ = 2*trunc(number)
+         fmp     P0.5H,du        EAQ = trunc(number)
+         tra     sp|tbp,*x0      return
+"                              else:
+         fmp     M2.0H,du        EAQ = 2*abs(number)
+         fad     =18b25,du       EAQ = 2*trunc(abs(number))
+         fmp     M0.5H,du        EAQ = trunc(number)
+         tra     sp|tbp,*x0      return
+\f
+"
+" The following code is used by trace to gain control of PL/I and FORTRAN programs.
+"
+       transfer_vector trace_
+
+"
+"      Function:       enter Binary Floating Point (BFP) mode
+"
+"      Entry:  X0 = offset in caller's text section of return point
+"
+"      Exit:   PR0, (sp|stack_frame.operator_ptr) -> operator_table
+"
+trace_enter_BFP_mode:
+       ldi     0,dl            clear HFP mode if it's set
+       epp0    trace_operator_table    change to HFP trace operators
+       spri0   sp|stack_frame.operator_ptr
+       tra     sp|tbp,*x0
+
+"
+"      Function:       enter Hexadecimal Floating Point (HFP) mode
+"
+"      Entry:  X0 = offset in caller's text section of return point
+"
+"      Exit:   PR0, (sp|stack_frame.operator_ptr) = hfp_operator_table
+"
+"      Note:   It is not sufficient to just request HFP mode.  We must
+"              check that our request has been honoured, since if HFP
+"              mode has not been enabled (or if it is not supported), a
+"              request to enter HFP mode is simply ignored.  If we find
+"              that our request to enter HFP mode has not been honoured,
+"              we attempt to enable HFP mode.  If we are unsuccessful,
+"              we signal the condition 'cannot_enable_HFP_mode'.  If we
+"              are restarted after signalling this condition, we repeat
+"              all the above steps.
+"
+trace_enter_HFP_mode:
+       ldi     HFP_mask,dl     request HFP mode
+       fld     P1.0H,du                check if request honoured
+       fad     P0.0H,du
+       sba     =o020000,du
+       tze     trace_enter_HFP_mode.entered
+       lda     =o600000,du     try to enable HFP mode
+       tsx1    call_set_hexfp_control
+       ldi     HFP_mask,dl     check if successful
+       fld     P1.0H,du
+       fad     P0.0H,du
+       sba     =o020000,du
+       tze     trace_enter_HFP_mode.entered
+       ldi     =0,dl           clear HFP mode request
+       eppbp   =22acannot_enable_HFP_mode
+       eax6    22
+       ldq     =1000,dl
+       tsx1    call_signal_    signal 'cannot_enable_HFP_mode' condition
+       tra     trace_enter_HFP_mode    try again
+
+trace_enter_HFP_mode.entered:
+       epp0    hfp_operator_table      change to HFP trace operators
+       spri0   sp|stack_frame.operator_ptr
+       tra     sp|tbp,*x0
+"
+       ext_entry               trace_
+"
+       ext_entry_desc  trace_
+"
+       ext_entry               trace_,ss_
+"
+       ext_entry_desc  trace_,ss_
+"
+trace_entry_operators_end:
+\f
+"
+" The following code is used by trace to gain control of PL/I and FORTRAN
+" programs running in HFP mode.
+"
+       transfer_vector trace_,hfp_
+\f
+"
+" The ALM entry operator used by trace.
+"
+alm_trace_operators_begin:
+       alm_entry_op trace_
+alm_trace_operators_end:
+" \f
+"      operator to update long_profile entry
+"      Calling sequence:
+"
+"      tsx0    ap|long_profile
+"      zero    header_relp,entry_offset
+"
+       include long_profile
+"
+"      NB:  THIS OPERATOR IS NOT ALLOWED TO DESTROY ANY REGISTERS,
+"      INCLUDING A, Q, index registers, pointer registers,
+"      THE INDICATOR OR STRING REGISTERS.  This is part of the
+"      contract of long_profile not to affect the object
+"      code.
+"
+"
+long_profile:
+       sti     sp|temp_indicators              save indicators
+       sreg    sp|8                    save registers
+       get_stack_offset
+       spri    sp|stack_header.stack_end_ptr,au*
+"
+       get_our_lp
+       stcd    sp|stack_frame.return_ptr
+       callsp  <cpu_time_and_paging_op_>|[cpu_time_and_paging_op_]
+"
+       staq    sp|cpu          save virtual cpu time
+       stx0    sp|page         save page faults
+       sxl1    sp|page         ..
+"
+       ldx0    sp|8                    restore x0
+       eppbp   sp|tbp,*0                       pt at arg word
+       spbpbp  sp|stack_frame.return_ptr       restore return ptr
+       epbpsb  sp|0                    sb = stack base
+"
+       ldi     =o004000,dl             mask against overflow (vcpu faults at 19 hrs)
+       epaq    bp|0                    get ptr to static section
+       lprplb  sb|stack_header.isot_ptr,*au
+       ldx1    bp|0                    get header relp
+       epplb   lb|0,1                  point at long_profile_header
+       lxl2    lb|long_profile_header.last_offset      point at profile entry to be updated
+       aos     lb|long_profile_entry.count,2   update
+       ldaq    sp|cpu
+       sblaq   lb|long_profile_header.last_vcpu
+       asq     lb|long_profile_entry.vcpu,2
+       ldq     sp|page
+       sblq    lb|long_profile_header.last_pf
+       asq     lb|long_profile_entry.pf,2
+"
+       ldaq    sp|cpu                  set up for next time
+       staq    lb|long_profile_header.last_vcpu
+       ldq     sp|page
+       stq     lb|long_profile_header.last_pf
+       lxl3    bp|0
+       sxl3    lb|long_profile_header.last_offset
+"
+       lpri    sb|stack_header.stack_end_ptr,* restore regs
+       lreg    sp|8                    ..
+       eax0    1,0                     increment for return
+       ldi     sp|temp_indicators              restore indicators
+       tra     sp|tbp,*0                       return
+signal_error_missing:
+       eppbp   missing_error
+       ldx6    missing_error_length,du
+       tra     signal_op
+missing_error:
+       aci     "missing_pl1_io_operator"
+       equ     missing_error_length,23
+" \f
+" The following code performs an assembly-time cross-check of the consistency
+" of the operator_table region. The location referenced by operator_table itself
+" must be even...if it is not, the compiled code that references it will fail.
+" The following expression will divide-by-zero if operator_table is odd.
+" in PL/I: error1 = 1 / (1 - mod (operator_table - reloc_0, 2));
+"
+       equ     optbl_abs,operator_table-begin_pl1_operators    " kill off relocation
+       equ     error1,1/(1-(optbl_abs-2*(optbl_abs/2)))        " ERROR 1: operator_table on ODD location.
+"
+       end