home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / gnu / gs252b.lzh / GS252B / GP_ATARI.C < prev    next >
C/C++ Source or Header  |  1993-07-30  |  18KB  |  750 lines

  1. /* Copyright (C) 1989, 1992 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* gp_atari.c */
  21. /* Atari-specific routines for Ghostscript */
  22.  
  23. #include "memory_.h"
  24. #include "string_.h"
  25. #include "gx.h"
  26. #include "gp.h"
  27. #include "stat_.h"
  28. #include "time_.h"
  29. #include <stdarg.h>
  30.  
  31. /* popen isn't POSIX-standard, so we declare it here. */
  32. extern FILE *popen();
  33. extern int pclose();
  34.  
  35. /* Do platform-dependent initialization */
  36. void
  37. gp_init()
  38. {
  39. }
  40.  
  41. /* Do platform-dependent cleanup */
  42. void
  43. gp_exit()
  44. {
  45. }
  46.  
  47. /* ------ Date and time ------ */
  48.  
  49. /* Read the current date (in days since Jan. 1, 1980) */
  50. /* and time (in milliseconds since midnight). */
  51. void
  52. gp_get_clock(long *pdt)
  53. {    long secs_since_1970, secs_since_1980;
  54.     struct tm *tm, *localtime();
  55.  
  56.     if ( (secs_since_1970 = time(NULL)) == 0 )
  57.        {    perror("Ghostscript: gettimeofday failed:");
  58.         exit(-1);
  59.        }
  60.  
  61.     /* secs_since_1970 is #secs since Jan 1, 1970 */
  62.  
  63.     /* subtract off number of seconds in 10 years */
  64.     /* leap seconds are not accounted for */
  65.     secs_since_1980 = secs_since_1970 - (long)(60 * 60 * 24 * 365.25 * 10);
  66.  
  67.     /* there is no time zone adjustment for the atari st */
  68.  
  69.     /* adjust for daylight savings time - assume dst offset is 1 hour */
  70.     tm = localtime(&(secs_since_1970));
  71.     if ( tm->tm_isdst )
  72.         secs_since_1980 += (60 * 60);
  73.  
  74.     /* divide secs by #secs/day to get #days (integer division truncates) */
  75.     pdt[0] = secs_since_1980 / (60 * 60 * 24);
  76.     /* modulo * 1000 gives number of millisecs since midnight */
  77.     pdt[1] = (secs_since_1980 % (60 * 60 * 24)) * 1000;
  78. #ifdef DEBUG_CLOCK
  79.     printf("secs_since_1970 = %d  usecs_since_1970 = %d  pdt[0] = %ld\
  80.   pdt[1] = %ld\n", secs_since_1970, pdt[1], pdt[0], pdt[1]);
  81. #endif
  82. }
  83.  
  84. /* ------ Screen management ------ */
  85.  
  86. /* Write a string to the console. */
  87. void
  88. gp_console_puts(const char *str, uint size)
  89. {    fwrite(str, 1, size, stdout);
  90. }
  91.  
  92. /* Make the console current on the screen. */
  93. int
  94. gp_make_console_current(struct gx_device_s *dev)
  95. {    return 0;
  96. }
  97.  
  98. /* Make the graphics current on the screen. */
  99. int
  100. gp_make_graphics_current(struct gx_device_s *dev)
  101. {    return 0;
  102. }
  103.  
  104. /* ------ Printer accessing ------ */
  105.  
  106. /* Open a file or a printing device. If gp_open_printer returns
  107.  * a NULL, the file will be sent directly to the centronics port.
  108.  * This happens if fname = "CEN:" or if gp_open_scratch_file()
  109.  * fails. Usually, GS wants to interpret a NULL return value as
  110.  * an error, so this is slightly incompatible.
  111.  * "|command" opens an output pipe.
  112.  */
  113.  
  114. FILE *
  115. gp_open_printer(char *fname)
  116. {
  117.     if (!strcmp(fname, "CEN:")) {    /* Direct Centronics printing. */
  118.        return NULL;
  119.     }
  120.     else {
  121.        return
  122.          (strlen(fname) == 0 ?
  123.           gp_open_scratch_file(gp_scratch_file_name_prefix, fname, "wb") :
  124.           fname[0] == '|' ?
  125.           popen(fname + 1, "wb") :
  126.           fopen(fname, "wb"));
  127.     }
  128. }
  129.  
  130. /* Close the connection to the printer. */
  131. void
  132. gp_close_printer(FILE *pfile, const char *fname)
  133. {    if ( fname[0] == '|' )
  134.         pclose(pfile);
  135.     else
  136.         fclose(pfile);
  137. }
  138.  
  139. /* ------ File name syntax ------ */
  140.  
  141. /* Define the character used for separating file names in a list. */
  142. char gp_file_name_list_separator = ',';
  143.  
  144. /* Define the default scratch file name prefix. */
  145. const char gp_scratch_file_name_prefix[] = "gs_pr.";
  146.  
  147. /* Define whether case is insignificant in file names. */
  148. const int gp_file_names_ignore_case = 1;
  149.  
  150. /* Define the string to be concatenated with the file mode */
  151. /* for opening files without end-of-line conversion. */
  152. const char gp_fmode_binary_suffix[] = "b";
  153.  
  154. /* Define the file modes for binary reading or writing. */
  155. const char gp_fmode_rb[] = "rb";
  156. const char gp_fmode_wb[] = "wb";
  157.  
  158. /* Create and open a scratch file with a given name prefix. */
  159. /* Write the actual file name at fname. */
  160.  
  161. FILE *
  162. gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
  163. {
  164.     strcpy(fname, prefix);
  165.     strcat(fname, "XXX");
  166.     mktemp(fname);
  167.     return fopen(fname, mode);
  168. }
  169.  
  170. /* Answer whether a file name contains a directory/device specification, */
  171. /* i.e. is absolute (not directory- or device-relative). */
  172. int
  173. gp_file_name_is_absolute(const char *fname, uint len)
  174. {    /* A file name is absolute if it contains a drive specification */
  175.     /* (second character is a :) or if it start with / or \. */
  176.     return ( len >= 1 && (*fname == '/' || *fname == '\\' ||
  177.         (len >= 2 && fname[1] == ':')) );
  178. }
  179.  
  180. /* Answer the string to be used for combining a directory/device prefix */
  181. /* with a base file name.  The file name is known to not be absolute. */
  182. const char *
  183. gp_file_name_concat_string(const char *prefix, uint plen,
  184.                const char *fname, uint len)
  185. {    if ( plen > 0 )
  186.       switch ( prefix[plen - 1] )
  187.        {    case ':': case '/': case '\\': return "";
  188.        };
  189.     return "\\";
  190. }
  191.  
  192. /* ------ File operations ------ */
  193.  
  194. /* If the file given by fname exists, fill in its status and return 1; */
  195. /* otherwise return 0. */
  196. int
  197. gp_file_status(const char *fname, file_status *pstatus)
  198. {    struct stat sbuf;
  199.     /* The RS/6000 prototype for stat doesn't include const, */
  200.     /* so we have to explicitly remove the const modifier. */
  201.     if ( stat((char *)fname, &sbuf) < 0 ) return 0;
  202.     pstatus->size_pages = stat_blocks(&sbuf);    /* st_blocks is */
  203.                     /* missing on some systems, */
  204.                     /* see stat_.h */
  205.     pstatus->size_bytes = sbuf.st_size;
  206.     pstatus->time_referenced = sbuf.st_mtime;
  207.     pstatus->time_created = sbuf.st_ctime;
  208.     return 1;
  209. }
  210.  
  211. /* ------ File enumeration ------ */
  212.  
  213. /****** THIS IS NOT SUPPORTED ON UNIX SYSTEMS. ******/
  214. /* Amazingly enough, there is no standard Unix library routine */
  215. /* for enumerating the files matching a pattern, */
  216. /* or even for enumerating (conveniently) the files in a directory. */
  217.  
  218. struct file_enum_s {
  219.     char *pattern;
  220.     int first_time;
  221.     gs_memory_procs mprocs;
  222. };
  223.  
  224. /* Initialize an enumeration.  NEEDS WORK ON HANDLING * ? \. */
  225. file_enum *
  226. gp_enumerate_files_init(const char *pat, uint patlen,
  227.             proc_alloc_t palloc, proc_free_t pfree)
  228. {    file_enum *pfen = (file_enum *)(*palloc)(1, sizeof(file_enum), "gp_enumerate_files");
  229.     char *pattern;
  230.     if ( pfen == 0 ) return 0;
  231.     pattern = (*palloc)(patlen + 1, 1,
  232.                 "gp_enumerate_files(pattern)");
  233.     if ( pattern == 0 ) return 0;
  234.     memcpy(pattern, pat, patlen);
  235.     pattern[patlen] = 0;
  236.     pfen->pattern = pattern;
  237.     pfen->mprocs.alloc = palloc;
  238.     pfen->mprocs.free = pfree;
  239.     pfen->first_time = 1;
  240.     return pfen;
  241. }
  242.  
  243. /* Enumerate the next file. */
  244. uint
  245. gp_enumerate_files_next(file_enum *pfen, char *ptr, uint maxlen)
  246. {    if ( pfen->first_time )
  247.        {    pfen->first_time = 0;
  248.        }
  249.     return -1;
  250. }
  251.  
  252. /* Clean up the file enumeration. */
  253. void
  254. gp_enumerate_files_close(file_enum *pfen)
  255. {    proc_free_t pfree = pfen->mprocs.free;
  256.     (*pfree)(pfen->pattern, strlen(pfen->pattern) + 1, 1,
  257.          "gp_enumerate_files_close(pattern)");
  258.     (*pfree)((char *)pfen, 1, sizeof(file_enum), "gp_enumerate_files_close");
  259. }
  260.  
  261.  
  262. /*
  263.  * The remainder of this file contains printer output routines, most of
  264.  * which were contributed by Chris Strunk (some of them were written by me).
  265.  * I made some modifications to the following code (with permission), and
  266.  * may have introduced errors not in the original code.
  267.  * Tim Gallivan, 3/92.
  268.  */
  269.  
  270. /*
  271.  * This file is Copyright (C) 1990 Christoph Strunk.
  272.  *
  273.  * You are not allowed to copy or modify it.
  274.  */
  275.  
  276. #define ATARI_TOS    (1)
  277. #define MAKE_VOID    (void *)
  278. #define MAXLEN        (256)
  279.  
  280. void con_flush();
  281. int OutputIsAscii = 0, RTX_Found = 0;
  282. long *old_ssp = NULL;
  283. FILE *OutFile = NULL;
  284.  
  285. #if PC_DOS || ATARI_TOS
  286. #  define DIRECT    1    /* 1 = Direct Centronics port programming */
  287. #endif
  288.  
  289. #if ATARI_TOS || ( PC_DOS && DIRECT )
  290. static short prn_out ( int );
  291. #endif
  292.  
  293. #if ATARI_TOS && LATTICE
  294. #include <dos.h>
  295. #endif
  296.  
  297. #ifdef __GNUC__
  298. #include <osbind.h>
  299. #endif
  300.  
  301. #if PC_DOS && DIRECT
  302. #include <bios.h>
  303. #endif
  304.  
  305. /* output one character */
  306.  
  307. static int fatal_output_error = 0;
  308.  
  309. void
  310. lputc(c)
  311. int c;
  312. {
  313.     static short rc;
  314.     static unsigned char global_count = 0; /* other processes every 256 chars */
  315.     void l_stop(), fatal();
  316.  
  317.     if ( fatal_output_error ) return;
  318.  
  319.     global_count += 1;
  320.  
  321.     c &= 255;            /* New in 2.9.44: avoid signed char problems */
  322.  
  323. #if ATARI_TOS || PC_DOS
  324.     if ( ( c == '\n' ) && OutputIsAscii ) {
  325.       lputc ( '\r' );    /* recursion */
  326.     }
  327. #endif
  328.  
  329.     if ( OutFile ) {
  330.        rc = ( fputc ( c, OutFile ) == EOF );
  331.     } else {
  332. #if ATARI_TOS || ( PC_DOS && DIRECT )
  333.                    rc = prn_out ( c );
  334. #else
  335.                    rc = -1;
  336. #endif
  337.     }
  338.  
  339.     if ( rc ) {
  340.         if ( OutFile ) {
  341.             perror ( "\nlputc" );
  342.             fprintf ( stderr, "\nOutput error -- %s ?\n",
  343.                       "Disk full or printer not ready" );
  344.             fclose ( OutFile );
  345.             OutFile = NULL;
  346.         } else {
  347.             fprintf ( stderr, "\nOutput error -- Printer not ready ?\n" );
  348.         }
  349.         l_stop();
  350.         fatal_output_error = 1;
  351.         fatal ( "Output error" );
  352.     }
  353.  
  354. #if ATARI_TOS
  355.     if ( RTX_Found && ! global_count ) call_yield(); /* allow other processes */
  356. #endif
  357. }
  358.  
  359. /* output a string */
  360.  
  361. void
  362. lputs ( s )
  363. char *s;
  364. {
  365.     while ( *s ) lputc ( *s++ );
  366. }
  367.  
  368. void
  369. lflush()
  370. {
  371.    if ( OutFile ) fflush ( OutFile );
  372. }
  373.  
  374. /* start/stop lputc device */
  375.  
  376. void
  377. l_start()
  378. {
  379.   void l_stop(), fatal();
  380.  
  381. #if ATARI_TOS && DIRECT
  382.   volatile char *gpip = (char *) 0xFFFFFA01L;
  383.   int cnt;
  384.  
  385.   if ( OutFile == NULL && old_ssp == NULL ) {
  386.     old_ssp = (void *) call_super ( NULL );
  387.     cnt = 0;
  388. /*    for ( cnt=0; ( *gpip & 1 ) && ( ++cnt <= 10 ); ) {
  389.      printf("cnt = %d\n", cnt); */
  390.      Ongibit(0x20);                                        /* set strobe bit */
  391. /*    } */
  392.     if ( cnt > 10 ) {
  393.       l_stop();
  394.       puts ( "\n" );
  395.       fatal_output_error = 1;
  396.       fatal ( "Printer not ready" );
  397.     }
  398.   }
  399. #endif
  400. #if ATARI_TOS && ! DIRECT
  401.   int cnt;
  402.  
  403.   if ( OutFile == NULL && old_ssp == NULL ) {
  404.     old_ssp = (void *) call_super ( NULL );
  405.  
  406.     for ( cnt=0; ( ! prt_ready(0) ) && ( ++cnt <= 10 ); ) {
  407.      Ongibit(0x20);                                        /* set strobe bit */
  408.     }
  409.     if ( cnt > 10 ) {
  410.       l_stop();
  411.       puts ( "\n" );
  412.       fatal_output_error = 1;
  413.       fatal ( "Printer not ready" );
  414.     }
  415.   }
  416. #endif
  417. #if PC_DOS && DIRECT
  418.   if ( OutFile == NULL && ( biosprint ( 2, 0, BiosChannel ) & 0x29 ) ) {
  419.     l_stop();
  420.     puts ( "\n" );
  421.     fatal_output_error = 1;
  422.     fatal ( "Printer not ready" );
  423.   }
  424. #endif
  425. }
  426.  
  427. void l_stop()
  428. {
  429.     lflush();
  430. #if ATARI_TOS
  431.     if ( old_ssp != NULL ) {
  432.         MAKE_VOID call_super ( old_ssp );
  433.         old_ssp = NULL;
  434.     }
  435. #endif
  436. }
  437.  
  438. #if ATARI_TOS && DIRECT
  439.  
  440. extern void int_off __PROTO( ( void ) );
  441.  
  442. /* int_off:  ori.w  #$0700,sr
  443.  *           ret
  444.  */
  445.  
  446. extern void int_on __PROTO( ( void ) );
  447.  
  448. /* int_on:   andi.w #$F8FF,sr
  449.  *           ret
  450.  */
  451.  
  452. static short prn_out ( c )
  453. int c;
  454. {
  455.   volatile unsigned long *hz_200;
  456.   register unsigned long end_time;
  457.   volatile char *gpip = (char *) 0xFFFFFA01L;
  458.   register char g;
  459.  
  460. #if OLD
  461.   unsigned char loop_count = 0;
  462. #endif
  463.  
  464.   if ( old_ssp == NULL ) l_start();
  465.  
  466.   hz_200 = (unsigned long *) 0x04BAL;
  467. #if OLD
  468.   end_time = *hz_200 + 200;        /* check once per second */
  469. #else
  470.   end_time = *hz_200 + 2;          /* check 100 times per second */
  471. #endif
  472.  
  473.   while ( *gpip & 1 ) {  /* wait */
  474. #if OLD
  475.     /* Printer 1 sec. or more not ready ? */
  476.     if ( ( end_time < *hz_200 ) ||
  477.          ( ( ( ++loop_count & 7 ) == 0 ) && ( BatchMode || RTX_Found ) ) ) {
  478.         con_flush();         /* allow Control_C, other Processes etc. */
  479.         end_time = *hz_200 + 2;          /* check 100 times per second */
  480.     }
  481. #else
  482.     if ( end_time <= *hz_200 ) {
  483.         con_flush();               /* allow Control_C, other Processes etc. */
  484.         end_time = *hz_200 + 1;              /* check 200 times per second */
  485.     }
  486. #endif
  487.   }
  488.  
  489.   int_off();                   /* disable interrupts */
  490.  
  491.   gpip = (char *) 0xFFFF8800L; /* load sound chip adress now */
  492.  
  493.   *gpip = 15;                  /* select port B */
  494.   gpip[2] = (char) c;          /* write out char */
  495.   *gpip = 14;                  /* select port A */
  496.   g = *gpip;                   /* get old value */
  497. #if OLD
  498.   g &= 0xDF;                   /* clear strobe bit */
  499. #else
  500.   g &= ~0x20;                  /* clear strobe bit */
  501. #endif
  502.   gpip[2] = g;
  503.   g |= 0x20;                   /* set strobe bit */
  504.   g |= 0x20;                   /* short delay */
  505.   gpip[2] = g;
  506.  
  507.   int_on();                    /* enable interrupts */
  508.  
  509.   return 0;
  510. }
  511. #endif
  512.  
  513. #if ATARI_TOS && ! DIRECT
  514. static short prn_out ( c )
  515. int c;
  516. {
  517.   volatile unsigned long *hz_200 = (unsigned long *) 0x04BAL;
  518.   register unsigned long end_time;
  519.  
  520.   if ( old_ssp == NULL ) l_start();
  521.  
  522.   end_time = *hz_200 + 2;          /* check 200 times per second */
  523.  
  524.   while ( ! prt_ready(0) ) {  /* wait */
  525.     if ( end_time <= *hz_200 ) {
  526.         con_flush();               /* allow Control_C, other Processes etc. */
  527.         end_time = *hz_200 + 1;              /* check 200 times per second */
  528.     }
  529.   }
  530.  
  531.   prt_out ( 0, c );
  532.  
  533.   return 0;
  534. }
  535. #endif
  536.  
  537. #if PC_DOS && DIRECT
  538.  
  539. static short prn_out ( c )
  540. int c;
  541. {
  542.   while ( biosprint ( 0, c, BiosChannel ) & 0x29 ) {
  543.     /* wait until Ok or Control-C pressed */
  544.     con_flush();
  545.   }
  546.  
  547.   return 0;
  548. }
  549.  
  550. #endif
  551.  
  552. void
  553. con_flush()
  554. {
  555.     int chin;
  556.     void fatal();
  557.  
  558.     chin = Crawio(0xFF);
  559.     if ((chin & 0xFF) == 3) fatal("Keyboard Interrupt");
  560. }
  561.  
  562. void
  563. fatal(char *message)
  564. {
  565.     fprintf(stderr, "%s\n", message);
  566.     l_stop();
  567.     exit(-1);
  568. }
  569.  
  570. /* The following routines are generic interfaces to Chris Strunk's
  571.  * fast printing routines. Tim Gallivan 3/92.
  572.  */
  573.  
  574. int
  575. csputc(int c, FILE *stream)
  576. {
  577.     OutFile = stream;
  578.     l_start();
  579.     lputc(c);
  580.     l_stop();
  581.     return c;
  582. }
  583.  
  584. int
  585. csputs(const char *s, FILE *stream)
  586. {
  587.     OutFile = stream;
  588.     l_start();
  589.     lputs(s);
  590.     l_stop();
  591.     return 1;
  592. }
  593.  
  594. int
  595. cswrite(const void *ptr, size_t size, size_t nobj, FILE *stream)
  596. {
  597.     int count;
  598.  
  599.     if (stream == NULL) {
  600.         OutFile = stream;
  601.         l_start();
  602.         for (count=0; count < size*nobj; count++) {
  603.             lputc(*(char *)(ptr++));       /* send the data */
  604.         }
  605.         l_stop();
  606.         return count;
  607.     }
  608.     else {
  609.         int ret;
  610.         ret = fwrite(ptr, size, nobj, stream);
  611.         con_flush();
  612.         return ret;
  613.     }
  614.         
  615. }
  616.  
  617. int
  618. csprintf(FILE *stream, char *format, ...)
  619. {
  620.     va_list args;
  621.     char line[MAXLEN];
  622.  
  623.     va_start(args, format);
  624.  
  625.     if (stream == NULL) {
  626.         OutFile = stream;
  627.         vsprintf(line, format, args);
  628.         l_start();
  629.         lputs(line);
  630.         l_stop();
  631.         va_end(args);
  632.         return 0;
  633.     }
  634.     else {
  635.         vfprintf(stream, format, args);
  636.         va_end(args);
  637.         con_flush();
  638.         return 0;
  639.     }
  640.  
  641. }
  642.  
  643. /*
  644. #-----------------------------------------------------------------------------#
  645. #:    Simple support routines for LATTICE C 5.04.01 and other C compilers
  646. #
  647. #:    Lattice C Assembler
  648. #
  649. #:    The parameter comes on the stack for functions starting with '_'.
  650. #
  651. #:    void *call_super ( void * );  supervisor mode on/off
  652. #
  653. #:    Original code by Chris Strunk. Modified for use with gcc in
  654. #:    Ghostscript by Tim Gallivan, 3/92.
  655. #-----------------------------------------------------------------------------#
  656. */
  657.     asm("\
  658.  
  659.     .text 0
  660.  
  661.     .globl _int_off
  662.     .globl _int_on
  663.     .globl _call_super
  664.     .globl _call_yield
  665.     .globl _call_nice
  666.     .globl _user_trace
  667.     .globl _prt_ready
  668.     .globl _prt_out
  669.  
  670. _get_la:
  671.     moveml   d2/a2,sp@- 
  672.     .byte    0xA0,0x00            | Adresse Line-A-Var nach A0 & D0
  673.     moveml   sp@+,d2/a2
  674.     rts
  675.  
  676. _int_off:
  677.     oriw     #0x0700,sr
  678.     rts
  679.  
  680. _int_on:
  681.     andiw    #0xF8FF,sr
  682.     rts
  683.  
  684. _call_super:
  685.     movel    a7@(4),a0
  686.     moveml   d2/a2-a3,sp@-
  687.     movel    a0,sp@-
  688.     movew    #0x20,sp@-
  689.     movel    a7,a3     | save current stack pointer
  690.     trap      #1
  691.     movel    a3,a7     | make bad stack pointer good again !!!!!!!
  692.     addql    #6,sp
  693.     movel    d0,a0     | return value in both: d0 and a0
  694.     moveml   sp@+,d2/a2-a3
  695.     rts
  696.  
  697. _call_yield:
  698.     moveml   d2/a2,sp@-
  699.     movew    #0x00ff,sp@-   | MiNT Syield()  --  TOS illegal (rc -32)
  700.     trap      #1
  701.     addql    #2,sp
  702.     moveml   sp@+,d2/a2
  703.     rts
  704.  
  705. _call_nice:
  706.     movel    a7@(4),d0
  707.     moveml   d2/a2,sp@-
  708.     movew    d0,sp@-
  709.     movew    #0x10A,sp@-
  710.     trap      #1
  711.     addql    #4,sp
  712.     moveml   sp@+,d2/a2
  713.     rts
  714.  
  715. _user_trace:
  716.     moveml   d1-d7/a0-a6,sp@-
  717.     moveql   #0,d0
  718.     movel    0x3F0,a1     | TEMPLMON user trace vector
  719.     cmpal    #0,a1       | not installed ?
  720.     beqs     end_trace
  721.     jsr      a1@        | execute it !
  722.     extl     d0
  723.  
  724. end_trace:
  725.     moveml   sp@+,d1-d7/a0-a6
  726.     rts
  727.  
  728. _prt_ready:
  729.     moveml    d3/a3/a5,a7@-
  730.     subl    a5,a5
  731.     movew    d0,a7@-
  732.     movel    0x506,a0
  733.     jsr    a0@
  734.     addql    #2,a7
  735.     moveml    a7@+,d3/a3/a5
  736.     rts
  737.  
  738. _prt_out:
  739.     moveml    d3/a3/a5,a7@-
  740.     subl    a5,a5
  741.     movew    d1,a7@-
  742.     movew    d0,a7@-
  743.     movel    0x50A,a0
  744.     jsr    a0@
  745.     addql    #4,a7
  746.     moveml    a7@+,d3/a3/a5
  747.     rts
  748.  
  749.     ");
  750.