>I'm running into some difficulty reworking c89 #pragma intrinsics into
>reasonable prototypes that actually work on gcc/iX. The resultant code
>does not seem to have the correct prologue and/or epilogue and the calls
>are failing.
There are usually hidden parameters that need to be addressed and there
are some long pointer issues to deal with. The easiest way to do this
is invest in the Lund Developer's Toolbox (written by Allegro). (I don't
get no steenking commissions ... so a plug alert isn't warranted. :-))
You're interested most in the CSEQ tool. It will produce calling sequences
for the intrinsics. And, if you SET GCC, it will produce gcc compatible
declarations. You may still need to dummy up some declarations if you
don't have them (typically typedefs) and you'll need my longpointer.h
goo (a version included below).
The following is an example implementation of a call to HPGETPROCPLABEL:
#ifdef __GNUC__
extern void HPGETPROCPLABEL( int parms,
void * procname,
void * plabel,
void * status,
void * firstfile,
int casesensitive,
/* following added in 5.5 */ int symbol_type,
void * data_size,
int position,
int search_path,
int binding);
#define T_STATUS struct { short subsys; short info; }
#define CALL_HPGETPROCPLABEL(procname, plabel, status, \
firstfile, casesensitive, symbol_type, data_size, \
position, search_path, binding) \
HPGETPROCPLABEL(10, (procname), (plabel), (status), \
(firstfile), (casesensitive), (symbol_type), \
(data_size), (position), (search_path), (binding));
#else
#pragma intrinsic HPGETPROCPLABEL
#define CALL_HPGETPROCPLABEL(procname, plabel, status, \
firstfile, casesensitive, symbol_type, data_size, \
position, search_path, binding) \
HPGETPROCPLABEL((procname), (plabel), (status), \
(firstfile), (casesensitive), (symbol_type), \
(data_size), (position), (search_path), (binding));
#endif
and in the code:
...
CALL_HPGETPROCPLABEL(&buf,value,&status,lib,1,0,&dummy,0,0,0);
if (status.info != 0) {...}
This follows my coding style and allows me to use the same body of code
for both c89 and gcc. Note that while the intrinsic is in essence option
variable, I supply all of the parameters, specifying the default values
for parameters I don't care about. CSEQ will tell you what those defaults
should be.
Here's an example using longpointers. This both moves data around using
long pointers, and calls an intrinsic expecting a longpointer as one of
the params:
#include "longpointer.h"
extern void PRINT(
longpointer message,
int len,
int cctl);
main()
{
char buf[80];
char *buf1 = "this is a test!";
char outbuf[80];
int i = 1234;
LONGPOINTER lp_buf = longaddr(buf);
sprintf(outbuf,"space: 0x%08x, offset: 0x%08x\n",
lp_buf.spaceid,lp_buf.offset);
PRINT(longaddr(outbuf), -strlen(outbuf), 0);
lp_buf = longaddr(&i);
sprintf(outbuf,"peek of i: %d\n",longpeek(lp_buf));
PRINT(longaddr(outbuf), -strlen(outbuf), 0);
longpoke(lp_buf,4567);
sprintf(outbuf,"poked i: %d\n",i);
PRINT(longaddr(outbuf), -strlen(outbuf), 0);
lp_buf = longaddr(buf1);
sprintf(outbuf,"buf1 space: 0x%08x, offset: 0x%08x\n",
lp_buf.spaceid,lp_buf.offset);
PRINT(longaddr(outbuf), -strlen(outbuf), 0);
longmove(strlen(buf1) + 1, longaddr(buf1), longaddr(buf));
sprintf(outbuf,"moved buf: %s\n",buf);
PRINT(longaddr(outbuf), -strlen(outbuf), 0);
buf1 = "This is the second test!";
move_fast(strlen(buf1) + 1, buf1, buf);
sprintf(outbuf,"moved buf: %s\n",buf);
PRINT(longaddr(outbuf), -strlen(outbuf), 0);
};
and finally .... longpointer.h:
/*
* gcc long pointer support code for HPPA.
* Copyright 1998, DIS International, Ltd.
* Permission is granted to use this code under the GNU LIBRARY GENERAL
* PUBLIC LICENSE, Version 2, June 1991.
*/
typedef struct {
int spaceid;
unsigned int offset;
} LONGPOINTER, longpointer;
int getspaceid(void *source)
{
int val;
/*
* Given the short pointer, determine it's space ID.
*/
/*
* The colons separate output from input parameters. In this case,
* the output of the instruction (output indicated by the "=" in the
* constraint) is to a memory location (indicated by the "m"). The
* input constraint indicates that the source to the instruction
* is a register reference (indicated by the "r").
* The general format is:
* asm("<instruction template>" : <output> : <input> : <clobbers>);
* where <output> and <input> are:
* "<constraint>" (<token>)
* <instruction template> is the PA-RISC instruction in template fmt.
* <clobbers> indicates those registers clobbered by the instruction
* and provides hints to the optimizer.
*
* Refer to the gcc documentation or http://www.dis.com/gnu/gcc_toc.html
*/
asm volatile (
"comiclr,= 0,%1,%%r28;
ldsid (%%r0,%1),%%r28;
stw %%r28, %0"
: "=m" (val) // Output to val
: "r" (source) // Source must be gen reg
: "%r28"); // Clobbers %r28
return (val);
};
LONGPOINTER longaddr(void *source)
{
LONGPOINTER lptr;
/*
* Return the long pointer for the address in sr5 space.
*/
asm volatile (
"comiclr,= 0,%2,%%r28;
ldsid (%%r0,%2),%%r28;
stw %%r28, %0;
stw %2, %1"
: "=m" (lptr.spaceid),
"=m" (lptr.offset) // Store to lptr
: "r" (source) // Source must be gen reg
: "%r28"); // Clobbers %r28
return (lptr);
};
LONGPOINTER addtopointer(LONGPOINTER source, // %r26 == source offset
// %r25 == source space
int len) // %r24 == length in bytes
{
/*
* Increment a longpointer.
*/
asm volatile (
"copy %0,%%r28; // copy space to r28
add %1,%2,%%r29" // Increment the pointer
: // No output
: "r" (source.spaceid), // Source address
"r" (source.offset),
"r" (len) // Length
: "%r28", // Clobbers
"%r29");
};
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.
*/
asm volatile (
".import $$lr_unk_unk_long,MILLICODE;
mtsp %0,%%sr1; // copy source space to sr1
copy %1,%%r26; // load source offset to r26
copy %4,%%r24; // load length to r24
copy %3,%%r25; // load target offset to r25
bl $$lr_unk_unk_long,%%r31; // start branch to millicode
mtsp %2,%%sr2" // copy target space to sr2
: // No output
: "r" (source.spaceid), // Source address
"r" (source.offset),
"r" (target.spaceid), // Target address
"r" (target.offset),
"r" (len) // Byte length
: "%r1", // Clobbers
"%r24",
"%r25",
"%r26",
"%r31");
};
int longpeek(LONGPOINTER source)
{
/*
* Fetch the int in long pointer space.
*/
unsigned int val;
asm volatile (
"mtsp %1, %%sr1;
copy %2, %%r28;
ldw 0(%%sr1, %%r28), %%r28;
stw %%r28, %0"
: "=m" (val) // Output val
: "r" (source.spaceid), // Source space ID
"r" (source.offset) // Source offset
: "%r28"); // Clobbers %r28
return (val);
};
void longpoke(LONGPOINTER target, // %r25 == spaceid, %r26 == offset
unsigned int val) // %r24 == value
{
/*
* Store the val into long pointer space.
*/
asm volatile (
"mtsp %0,%%sr1;
copy %1, %%r28;
stw %2, 0(%%sr1, %%r28)"
: // No output
: "r" (target.spaceid), // Target space ID
"r" (target.offset), // Target offset
"r" (val) // Value to store
: "%r28" // Clobbers %r28
); // Copy space to %sr1
};
void move_fast(int len, // %r26 == byte length
void *source, // %r25 == source addr
void *target) // %r24 == target addr
{
/*
* Move using short pointers.
*/
asm volatile (
".import $$lr_unk_unk,MILLICODE;
copy %1, %%r26; // Move source addr into pos
copy %2, %%r25; // Move target addr into pos
bl $$lr_unk_unk,%%r31; // Start branch to millicode
copy %0, %%r24" // Move length into position
: // No output
: "r" (len), // Byte length
"r" (source), // Source address
"r" (target) // Target address
: "%r24", // Clobbers
"%r25",
"%r26",
"%r31");
};
|