HP3000-L Archives

January 1997, Week 3

HP3000-L@RAVEN.UTC.EDU

Options: Use Monospaced Font
Show Text Part by Default
Show All Mail Headers

Message: [<< First] [< Prev] [Next >] [Last >>]
Topic: [<< First] [< Prev] [Next >] [Last >>]
Author: [<< First] [< Prev] [Next >] [Last >>]

Print Reply
Subject:
From:
Mark Klein <[log in to unmask]>
Reply To:
Mark Klein <[log in to unmask]>
Date:
Sun, 19 Jan 1997 17:56:33 PDT
Content-Type:
text/plain
Parts/Attachments:
text/plain (170 lines)
Well, since there have been some questions recently about calling
intrinsics from GCC and people have expressed an interest in 'tips and
techniques', I thought I'd show an example of calling the PRINT
intrinsic from GCC.

The first task is to determine the actual calling sequence of the
intrinsic. In this case, I use the <plug alert> CSEQ tool from Lund <end
plug>. Another way is to use the Pascal compiler to dump the SYSINTR
file. There are probably others and that is the subject of another post.

In any event, CSEQ indicates:

CSEQ [2.0] - LPS Toolbox [A.01i]            (c) 1995 Lund Performance Solutions

CSEQ [nm]: PRINT

Procedure PRINT (
   message      : anyvar record  ;        {R25, R26}
                                          {Address type = LongAddr}
   length       :        int16   ;        {R24}
   control      :        int16   )        {R23}
      uncheckable_anyvar

CSEQ [nm]:

This indicates that the buffer is a long pointer whose address is contained in
R26 and R25. R24 contains the length and R23 contains the control character.
Using that information the following code (which includes some assembly to
support long pointers - just copy that stuff verbatim) will print a string:

#include "longpointer.h"

main()
  {
  char *buf = "this is a test!";
  char  buf1[80];
  int   ccode;

  extern int    CCODE();
  extern int    errno;

  extern void   PRINT(LONGPOINTER lp,
                      short       length,
                      short       control);

  LONGPOINTER lp_buf = longaddr(buf);

  PRINT(lp_buf, -strlen(buf), 0);
  ccode = CCODE();

  sprintf(buf1, "ccode from PRINT call: %d\n", ccode);
  PRINT(longaddr(buf1), -strlen(buf1), 0);
  if (errno != 0)
    {
    sprintf(buf1, "errno: %d\n", errno);
    PRINT(longaddr(buf1), -strlen(buf1), 0);
    }
  };

and longpointer.h is:

typedef struct {
  int           spaceid;
  unsigned int  offset;
  } LONGPOINTER;

int getspaceid(void *source)
  {
  /*
   * Given the short pointer, determine it's space ID.
   */

  asm("comiclr,= 0,%r26,%r28");
  asm("ldsid (%r0,%r26),%r28");
  };

LONGPOINTER longaddr(void *source)      // %r26 == offset
  {
  /*
   * Return the long pointer for the address in sr5 space.
   */

  asm("or %r26,%r0,%r29");
  asm("comiclr,= 0,%r26,%r28");
  asm("ldsid (%r0,%r26),%r28");
  };

void longmove(int len,                  // %r26 == byte length
              LONGPOINTER source,       // %r23 == source space, %r24 == off
              LONGPOINTER target)       // sp-#56 == target space, sp-#52== off
  {
  /*
   * Move data between two buffers in long pointer space.
   */

  /*
   * This goo is to remove data from arg0-arg3 and place it in the frame
   * since these registers are needed for the millicode call and the gcc
   * optimizer doesn't really know we want to reuse them.
   */
  int bytelen  = len;
  int srcspace = source.spaceid;
  int srcoff   = source.offset;
  int trgspace = target.spaceid;
  int trgoff   = target.offset;

  asm(".import $$lr_unk_unk_long,MILLICODE");
  /*
   * The colons separate output from input parameters. In this case,
   * there are no output references from the instructions. The "m"
   * constraint indicates that the following token is a memory reference.
   * The general format is:
   *   asm("<instruction template>" : <output> : <input>);
   *     where <output> and <input> are:
   *       "<constraint>" (<token>)
   *     <instruction template> is the PA-RISC instruction in template fmt.
   * Refer to the gcc documentation or http://www.dis.com/gnu/gcc_toc.html
   */
  asm("ldw %0,%%r1"     :: "m" (srcspace));     // load source space to %r1
  asm("mtsp %r1,%sr1");                         // copy source space to %sr1
  asm("ldw %0,%%r26"    :: "m" (srcoff));       // load source offset to %r26
  asm("ldw %0,%%r24"    :: "m" (len));          // load length to %r24
  asm("ldw %0,%%r25"    :: "m" (trgoff));       // load target offset to %r25
  asm("ldw %0,%%r1"     :: "m" (trgspace));     // load target space to %r1
  asm("bl $$lr_unk_unk_long,%r31");             // start branch to millicode
  asm("mtsp %r1,%sr2");                         // copy target space to %sr2
  };

int longpeek(LONGPOINTER source)        // %r25 == spaceid, %r26 == offset
  {
  /*
   * Fetch the int in long pointer space.
   */
  asm("mtsp %r25,%sr1");
  asm("ldw 0(%sr1,%r26),%r28");
  };

void longpoke(LONGPOINTER target,       // %r25 == spaceid, %r26 == offset
          unsigned int val)             // %r24 == value
  {
  /*
   * Store the val into long pointer space.
   */
  asm("mtsp %r25,%sr1");
  asm("stw  %r24, 0(%sr1,%r26)");
  };

void move_fast(int len,                 // %r26 == byte length
               void *src,               // %r25 == source addr
               void *trg)               // %r24 == target addr
  {
  /*
   * Move using short pointers.
   */
  asm(".import $$lr_unk_unk,MILLICODE");
  asm("or %r26,%r0,%r1");               // Copy length to %r1 (temp)
  asm("or %r25,%r0,%r26");              // Move source addr into position
  asm("or %r24,%r0,%r25");              // Move target addr into position
  asm("bl $$lr_unk_unk,%r31");          // Start branch to millicode
  asm("or %r1,%r0,%r24");               // Move length into position
  };


/tmp(168): gcc print.c
WARNING: /tmp/cca552041.o HAS FILECODE 0

/tmp(169): a.out
this is a test!
ccode from PRINT call: 2

ATOM RSS1 RSS2