Basics.mesa
For Sun-3, Sun-4, and other big-endian, 32-bit processors
Copyright Ó 1985, 1988, 1989, 1991 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) February 27, 1985 8:10:50 pm PST
Carl Hauser, July 11, 1988 3:12:38 pm PDT
JKF August 26, 1988 12:50:28 pm PDT
Willie-s, July 25, 1991 2:56 pm PDT
Michael Plass, September 27, 1991 9:29 am PDT
Doug Wyatt, August 27, 1991 4:38 pm PDT
Basics: CEDAR DEFINITIONS ~ BEGIN
Commonly-used types and values
bitsPerByte: NAT ~ BITS[BYTE];
bitsPerWord: NAT ~ BITS[WORD];
bitsPerLongWord: NAT ~ BITS[CARD]; -- = bitsPerWord!
bitsPerDWord: NAT ~ BITS[DWORD]; -- = 2*bitsPerLongWord
bytesPerWord: NAT ~ BYTES[WORD];
bytesPerDWord: NAT ~ BYTES[DWORD];
logBitsPerByte: NAT ~ BITS[[0..bitsPerByte)]; -- LogBase2[bitsPerByte] (= 3)
logBitsPerWord: NAT ~ BITS[[0..bitsPerWord)];
logBitsPerDWord: NAT ~ BITS[[0..bitsPerDWord)];
logBytesPerWord: NAT ~ BITS[[0..bytesPerWord)];
logBytesPerDWord: NAT ~ BITS[[0..bytesPerDWord)];
bitsPerChar: NAT ~ bitsPerByte;
logBitsPerChar: NAT ~ logBitsPerByte;
charsPerWord: NAT ~ bytesPerWord;
logCharsPerWord: NAT ~ logBytesPerWord;
Word: TYPE ~ MACHINE DEPENDENT RECORD [ -- bitsPerWord bits
SELECT OVERLAID * FROM
card => [card: CARD], -- assert BITS[CARD] = BITS[CARDINAL]
int => [int: INT], -- assert BITS[INT] = BITS[INTEGER]
real => [real: REAL], -- assert BITS[REAL] = BITS[WORD]
bytes => [bytes: PACKED ARRAY [0..bytesPerWord) OF BYTE],
bits => [bits: PACKED ARRAY [0..bitsPerWord) OF BOOL],
Caution: bytes and bits not necessarily in significance order!
ENDCASE
];
DWord: TYPE ~ MACHINE DEPENDENT RECORD [ -- bitsPerDWord bits
SELECT OVERLAID * FROM
card => [card: DCARD],
int => [int: DINT],
real => [real: DREAL],
bytes => [bytes: PACKED ARRAY [0..bytesPerDWord) OF BYTE],
bits => [bits: PACKED ARRAY [0..bitsPerDWord) OF BOOL],
Caution: bytes and bits not necessarily in significance order!
ENDCASE
];
PartialComparison: TYPE ~ {less, equal, greater, incomparable};
Comparison: TYPE ~ PartialComparison [less..greater];
RawWords: TYPE ~ RECORD [SEQUENCE COMPUTED CARD OF WORD];
RawCards: TYPE ~ RECORD [SEQUENCE COMPUTED CARD OF CARD];
RawBytes: TYPE ~ RECORD [PACKED SEQUENCE COMPUTED CARD OF BYTE];
RawChars: TYPE ~ RECORD [PACKED SEQUENCE COMPUTED CARD OF CHAR];
RawBits: TYPE ~ RECORD [PACKED SEQUENCE COMPUTED CARD OF CARDINAL[0..1]];
UnsafeBlock: TYPE ~ RECORD [
base: POINTER TO RawBytes ¬ NIL,
startIndex: INT ¬ 0,
count: INT ¬ 0
];
... describes the byte sequence base[startIndex..startIndex+count).
Arithmetic utilities
CompareCard: PROC [a, b: CARD] RETURNS [Comparison]
~ INLINE { RETURN[IF a=b THEN equal ELSE IF a>b THEN greater ELSE less] };
CompareInt: PROC [a, b: INT] RETURNS [Comparison]
~ INLINE { RETURN[IF a=b THEN equal ELSE IF a>b THEN greater ELSE less] };
CompareBits: UNSAFE PROC [
aBase: POINTER TO RawBits, aStart: CARD,
bBase: POINTER TO RawBits, bStart: CARD,
count: CARDINAL] RETURNS [Comparison]
~ UNCHECKED MACHINE CODE {"Basics𡤌ompareBits"};
OddCard: PROC [n: CARD] RETURNS [BOOL]
~ INLINE { RETURN [VAL[n MOD 2]] };
... cheaply tests whether n is odd; equivalent to (but faster than) (n MOD 2)#0.
OddInt: PROC [n: INT] RETURNS [BOOL]
~ INLINE { RETURN [OddCard[LOOPHOLE[n]]] };
Bounds checking
NonNegative: PROC [value: INT] RETURNS [[0..INT.LAST]]
~ INLINE { RETURN[value] };
BoundsCheck: PROC [arg, limit: WORD] RETURNS [WORD]
~ INLINE { IF arg >= limit THEN RaiseBoundsFault[]; RETURN [arg] };
BoundsCheckInt: PROC [arg: INT, limit: [0..INT.LAST]] RETURNS [[0..INT.LAST)]
~ INLINE {
IF LOOPHOLE[arg, CARD] >= limit THEN RaiseBoundsFault[];
RETURN [LOOPHOLE[arg]];
};
RaiseBoundsFault: PROC
~ TRUSTED MACHINE CODE {
"XR←RaiseBoundsFault"
};
Effect is ... ERROR RuntimeError.BoundsFault;
NilCheck: PROC [ptr: POINTER] RETURNS [POINTER]
~ TRUSTED MACHINE CODE {
"XR←NilCheck"
};
Effect is ... { IF ptr=NIL THEN ERROR RuntimeError.NilFault; RETURN[ptr] };
Control links
IsBound: PROC [proc: PROC ANY RETURNS ANY] RETURNS [BOOL]
~ TRUSTED MACHINE CODE {
"XR←IsBound"
};
Logic utilities
BITAND: PROC [WORD, WORD] RETURNS [WORD]
~ TRUSTED MACHINE CODE {
"*#define XRM𡤋ITAND(x, y) (((word)(x)) & ((word)(y))).XRM𡤋ITAND"
};
BITOR: PROC [WORD, WORD] RETURNS [WORD]
~ TRUSTED MACHINE CODE {
"*#define XRM𡤋ITOR(x, y) (((word)(x)) | ((word)(y))).XRM𡤋ITOR"
};
BITXOR: PROC [WORD, WORD] RETURNS [WORD]
~ TRUSTED MACHINE CODE {
"*#define XRM𡤋ITXOR(x, y) (((word)(x)) ^ ((word)(y))).XRM𡤋ITXOR"
};
BITNOT: PROC [WORD] RETURNS [WORD]
~ TRUSTED MACHINE CODE {
"*#define XRM𡤋ITNOT(x) (~((word)(x))).XRM𡤋ITNOT"
};
BITLSHIFT: PROC [value: WORD, count: [0..bitsPerWord)] RETURNS [WORD]
... left-shifts the value by the count.
~ TRUSTED MACHINE CODE {
"*#define XRM𡤋ITLSHIFT(x, y) ((word)(x) << (word)(y)).XRM𡤋ITLSHIFT"
};
BITRSHIFT: PROC [value: WORD, count: [0..bitsPerWord)] RETURNS [WORD]
... right-shifts the value by the count.
~ TRUSTED MACHINE CODE {
"*#define XRM𡤋ITRSHIFT(x, y) ((word)(x) >> (word)(y)).XRM𡤋ITRSHIFT"
};
BITSHIFT: PROC [value: WORD, count: INTEGER] RETURNS [WORD]
... shifts the value by the count. If count is positive, the shift is to the left. If count is negative, the shift is to the right.
~ TRUSTED MACHINE CODE {
"Basics𡤋ITSHIFT"
};
Block copying utilities
CopyWords: UNSAFE PROC [
dst: POINTER TO RawWords,
src: POINTER TO RawWords,
count: CARDINAL]
~ UNCHECKED MACHINE CODE {
"Basics𡤌opyWords"
};
Copies a block of words: for all i in [0..count), dst[i] ¬ src[i].
The order of transfer is unspecified; destination and source should be disjoint.
MoveWords: UNSAFE PROC [
dst: POINTER TO RawWords,
src: POINTER TO RawWords,
count: CARDINAL]
~ UNCHECKED MACHINE CODE {
"Basics←MoveWords"
};
Moves a block of words: ripples in proper order if destination and source overlap.
FillWords: UNSAFE PROC [
dst: POINTER TO RawWords,
count: CARDINAL, value: WORD]
~ UNCHECKED MACHINE CODE {
"Basics𡤏illWords"
};
Fills a block of words with a constant: for all i in [0..count), dst[i] ¬ value.
CopyBytes: UNSAFE PROC [
dstBase: POINTER TO RawBytes, dstStart: CARD,
srcBase: POINTER TO RawBytes, srcStart: CARD,
count: CARDINAL]
~ UNCHECKED MACHINE CODE {
"Basics𡤌opyBytes"
};
Copies a block of bytes: for all i in [0..count), dstBase[dstStart+i] ¬ srcBase[srcStart+i].
The order of transfer is unspecified; destination and source should be disjoint.
MoveBytes: UNSAFE PROC [
dstBase: POINTER TO RawBytes, dstStart: CARD,
srcBase: POINTER TO RawBytes, srcStart: CARD,
count: CARDINAL]
~ UNCHECKED MACHINE CODE {
"Basics←MoveBytes"
};
Moves a block of bytes: ripples in proper order if destination and source overlap.
FillBytes: UNSAFE PROC [
dstBase: POINTER TO RawBytes, dstStart: CARD,
count: CARDINAL, value: BYTE]
~ UNCHECKED MACHINE CODE {
"Basics𡤏illBytes"
};
Fills a block of bytes with a constant: for all i in [0..count), dstBase[dstStart+i] ¬ value.
CopyBits: UNSAFE PROC [
dstBase: POINTER TO RawBits, dstStart: CARD,
srcBase: POINTER TO RawBits, srcStart: CARD,
count: CARDINAL]
~ UNCHECKED MACHINE CODE {"Basics𡤌opyBits"};
MoveBits: UNSAFE PROC [
dstBase: POINTER TO RawBits, dstStart: CARD,
srcBase: POINTER TO RawBits, srcStart: CARD,
count: CARDINAL]
~ UNCHECKED MACHINE CODE {"Basics←MoveBits"};
FillBits: UNSAFE PROC [
dstBase: POINTER TO RawBits, dstStart: CARD,
count: CARDINAL, value: WORD]
~ UNCHECKED MACHINE CODE {"Basics𡤏illBits"};
ByteBltBlock: TYPE ~ RECORD [blockPointer: POINTER, startIndex, stopIndexPlusOne: CARDINAL];
ByteBlt: UNSAFE PROC [to, from: ByteBltBlock] RETURNS [nBytes: CARDINAL]
~ TRUSTED MACHINE CODE {
"Basics𡤋yteBlt"
};
Retained for compatibility. The effect is ...
nBytes ¬ MIN[
MAX[to.startIndex, to.stopIndexPlusOne] - to.startIndex,
MAX[from.startIndex, from.stopIndexPlusOne] - from.startIndex
];
MoveBytes[to.blockPointer, to.startIndex, from.blockPointer, from.startIndex, nBytes];
32 and 16 bit types and operations
LongNumber: TYPE ~ Word32; -- for backward compatibility
Word32: TYPE ~ MACHINE DEPENDENT RECORD [ -- 32 bits
SELECT OVERLAID * FROM
card => [card: CARD32],
int => [int: INT32],
real => [real: REAL32],
pair => [hi, lo: CARD16],
bytes => [hh, hl, lh, ll: BYTE],
bits => [bits: PACKED ARRAY [0..32) OF BOOL],
Caution: bits not necessarily in significance order!
lc => [lc: CARD], li => [li: INT], -- for backward compatibility; assert BITS[CARD]=32
ENDCASE
];
Word16: TYPE ~ MACHINE DEPENDENT RECORD [ -- 16 bits
SELECT OVERLAID * FROM
card => [card: CARD16],
int => [int: INT16],
pair => [hi, lo: BYTE],
bits => [bits: PACKED ARRAY [0..16) OF BOOL],
Caution: bits not necessarily in significance order!
ENDCASE
];
LowHalf: PROC [n: CARD32] RETURNS [CARD16]
~ INLINE { RETURN[n MOD 2**16] };
HighHalf: PROC [n: CARD32] RETURNS [CARD16]
~ INLINE { RETURN[n / 2**16] };
LowByte: PROC [n: CARD16] RETURNS [BYTE]
~ INLINE { RETURN[n MOD 2**8] };
HighByte: PROC [n: CARD16] RETURNS [BYTE]
~ INLINE { RETURN[n / 2**8] };
Endian types and operations
HWORD: TYPE ~ MACHINE DEPENDENT RECORD [hi, lo: BYTE];
FWORD: TYPE ~ MACHINE DEPENDENT RECORD [hi, lo: HWORD];
These definitions are for things that "go on the wire"; well, mostly communication, but arguably anything that has an external representation that passes between machines, e.g. tape drives and floppy disks.
Some machines are big endian, some are little endian... Dorados, DLions, IBM 360s, Motorola 68000s, and SPARCs are big endian; PDP-11s, VAXes and Intel are little endian.
PrincOps LONGs are word swapped from a clean big endian viewpoint. Beware: Many Cedar programs, in particular RPC, send raw PrincOps (word swapped) LONGs on the wire.
Don't use CARD, CARDINAL, INT, INTEGER, WORD, or subranges bigger than a BYTE in the definition of any record going to or coming from the wire. Enumerated types bigger than a BYTE (ErrorCodes, for example) won't work either.
FFromCard32: PROC [n: CARD32] RETURNS [FWORD]
~ INLINE { RETURN[LOOPHOLE[n]] };
FFromInt32: PROC [n: INT32] RETURNS [FWORD]
~ INLINE { RETURN[LOOPHOLE[n]] };
Card32FromF: PROC [f: FWORD] RETURNS [CARD32]
~ INLINE { RETURN[LOOPHOLE[f]] };
Int32FromF: PROC [f: FWORD] RETURNS [INT32]
~ INLINE { RETURN[LOOPHOLE[f]] };
HFromCard16: PROC [n: CARD16] RETURNS [HWORD]
~ INLINE { RETURN[LOOPHOLE[n]] };
HFromInt16: PROC [n: INT16] RETURNS [HWORD]
~ INLINE { RETURN[LOOPHOLE[n]] };
Card16FromH: PROC [h: HWORD] RETURNS [CARD16]
~ INLINE { RETURN[LOOPHOLE[h]] };
Int16FromH: PROC [h: HWORD] RETURNS [INT16]
~ INLINE {
temp: PACKED RECORD[h0, h1: INT16] ~ [0, LOOPHOLE[h]];
RETURN[temp.h1]
};
END.
Carl Hauser, October 13, 1986 11:23:32 am PDT
Working on conversion for Dragon .
changes to:
LongNumber reordered contained words, bytes and bits; renamed the tags and subfields
ShortNumber retyped the subfields; renamed the tags and subfields
UnsafeBlock retyped the base field.
Carl Hauser, June 11, 1987 4:10:57 pm PDT
added the Endian types and operations.
Carl Hauser, March 24, 1988 11:07:21 am PST
Removed VM parameters. Get them from the VM interface.
Jim Foote, August 26, 1988 10:50:59 am PDT
Added FillBytes, changed Fill to FillWords, added IsBound.
Michael Plass, August 2, 1991 11:54:50 am PDT
Moved the (unimplemented) arithmetic section to the (new) BasicArithmetic interface.
Removed the ERROR declarations; they were unused and redundant with RuntimeError.