1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
|
/*
* 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;
/*
* 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.
*/
int __perl_mpe_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 __perl_mpe_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 __perl_mpe_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 __perl_mpe_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 __perl_mpe_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 __perl_mpe_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 __perl_mpe_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");
};
/*
* ftruncate - set file size, BSD Style
*
* shortens or enlarges the file as neeeded
* uses some undocumented locking call. It is known to work on SCO unix,
* other vendors should try.
* The #error directive prevents unsupported OSes
*/
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <mpe.h>
extern void FCONTROL(short, short, longpointer);
extern void PRINTFILEINFO(int);
int ftruncate(int fd, long wantsize);
int ftruncate(int fd, long wantsize) {
int ccode_return,dummy=0;
if (lseek(fd, wantsize, SEEK_SET) < 0) {
return (-1);
}
FCONTROL(_mpe_fileno(fd),6,__perl_mpe_longaddr(&dummy)); /* Write new EOF */
if ((ccode_return=ccode()) != CCE) {
fprintf(stderr,"MPE ftruncate failed, ccode=%d, wantsize=%ld\n",ccode_return,wantsize);
PRINTFILEINFO(_mpe_fileno(fd));
errno = ESYSERR;
return (-1);
}
return (0);
}
/*
wrapper for truncate():
truncate() is UNIX, not POSIX.
This function requires ftruncate().
NAME
truncate -
SYNOPSIS
#include <unistd.h>
int truncate(const char *pathname, off_t length);
Returns: 0 if OK, -1 on error
from: Stevens' Advanced Programming in the UNIX Environment, p. 92
ERRORS
EACCES
EBADF
EDQUOT (not POSIX) <- not implemented here
EFAULT
EINVAL
EISDIR
ELOOP (not POSIX) <- not implemented here
ENAMETOOLONG
ENOTDIR
EROFS
ETXTBSY (not POSIX) <- not implemented here
from: HP-UX man page
Compile directives:
PRINT_ERROR - make this function print an error message to stderr
*/
#ifndef _POSIX_SOURCE
# define _POSIX_SOURCE
#endif
#include <sys/types.h> /* off_t, required by open() */
#include <sys/stat.h> /* required by open() */
#include <fcntl.h> /* open() */
#include <unistd.h> /* close() */
#include <stdio.h> /* perror(), sprintf() */
int
truncate(const char *pathname, off_t length)
{
int fd;
#ifdef PRINT_ERROR
char error_msg[80+1];
#endif
if (length == 0)
{
if ( (fd = open(pathname, O_WRONLY | O_TRUNC)) < 0)
{
/* errno already set */
#ifdef PRINT_ERROR
sprintf(error_msg,
"truncate(): open(%s, O_WRONLY | OTRUNC)\0",
pathname);
perror(error_msg);
#endif
return -1;
}
}
else
{
if ( (fd = open(pathname, O_WRONLY)) < 0)
{
/* errno already set */
#ifdef PRINT_ERROR
sprintf(error_msg,
"truncate(): open(%s, O_WRONLY)\0",
pathname);
perror(error_msg);
#endif
return -1;
}
if (ftruncate(fd, length) < 0)
{
/* errno already set */
#ifdef PRINT_ERROR
perror("truncate(): ftruncate()");
#endif
return -1;
}
}
if (close(fd) < 0)
{
/* errno already set */
#ifdef PRINT_ERROR
perror("truncate(): close()");
#endif
return -1;
}
return 0;
} /* truncate() */
/*
wrapper for gettimeofday():
gettimeofday() is UNIX, not POSIX.
gettimeofday() is a BSD function.
NAME
gettimeofday -
SYNOPSIS
#include <sys/time.h>
int gettimeofday(struct timeval *tp, struct timezone *tzp);
DESCRIPTION
This function returns seconds and microseconds since midnight
January 1, 1970. The microseconds is actually only accurate to
the millisecond.
Note: To pick up the definitions of structs timeval and timezone
from the <time.h> include file, the directive
_SOCKET_SOURCE must be used.
RETURN VALUE
A 0 return value indicates that the call succeeded. A -1 return
value indicates an error occurred; errno is set to indicate the
error.
ERRORS
EFAULT not implemented
Changes:
2-91 DR. Created.
*/
/* need _SOCKET_SOURCE to pick up structs timeval and timezone in time.h */
#ifndef _SOCKET_SOURCE
# define _SOCKET_SOURCE
#endif
#include <time.h> /* structs timeval & timezone,
difftime(), localtime(), mktime(), time() */
#include <sys/time.h> /* gettimeofday() */
extern int TIMER();
#ifdef __STDC__
int gettimeofday( struct timeval *tp, struct timezone *tpz )
#else
int gettimeofday( tp, tpz )
struct timeval *tp;
struct timezone *tpz;
#endif
{
static unsigned long basetime = 0;
static int dsttime = 0;
static int minuteswest = 0;
static int oldtime = 0;
register int newtime;
/*-------------------------------------------------------------------*/
/* Setup a base from which all future time will be computed. */
/*-------------------------------------------------------------------*/
if ( basetime == 0 )
{
time_t gmt_time;
time_t loc_time;
struct tm *loc_time_tm;
gmt_time = time( NULL );
loc_time_tm = localtime( &gmt_time ) ;
loc_time = mktime( loc_time_tm );
oldtime = TIMER();
basetime = (unsigned long) ( loc_time - (oldtime/1000) );
/*----------------------------------------------------------------*/
/* The calling process must be restarted if timezone or dst */
/* changes. */
/*----------------------------------------------------------------*/
minuteswest = (int) (difftime( loc_time, gmt_time ) / 60);
dsttime = loc_time_tm->tm_isdst;
}
/*-------------------------------------------------------------------*/
/* Get the new time value. The timer value rolls over every 24 days, */
/* so if the delta is negative, the basetime value is adjusted. */
/*-------------------------------------------------------------------*/
newtime = TIMER();
if ( newtime < oldtime ) basetime += 2073600;
oldtime = newtime;
/*-------------------------------------------------------------------*/
/* Return the timestamp info. */
/*-------------------------------------------------------------------*/
tp->tv_sec = basetime + newtime/1000;
tp->tv_usec = (newtime%1000) * 1000; /* only accurate to milli */
if (tpz)
{
tpz->tz_minuteswest = minuteswest;
tpz->tz_dsttime = dsttime;
}
return 0;
} /* gettimeofday() */
|