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
|