adding big-endian support across compiler, runtime, and library modules

- adding Platform.LittleEndian to centralize endianness detection
- using SYSTEM.GET with correct byte offset for HUGEINT to smaller type reads on big-endian
- fixing Reals.BytesToHex iteration direction and InitEndian for big-endian
- fixing oocLowReal fraction, IsInfinity, IsNaN using Reals.Expo/SetExpo
- fixing Math.ToREAL and MathL.exponent for big-endian
- fixing In.Int and In.LongInt for big-endian
- fixing outtest.wh byte iteration direction for big-endian
- regenerating all bootstrap C sources
- tested on ppc32
This commit is contained in:
Norayr Chilingarian 2026-07-12 18:16:58 +04:00
parent 93c0198f18
commit 4dd3c395fe
198 changed files with 788 additions and 409 deletions

View file

@ -1,7 +1,7 @@
(* Oberon Portable build parse tree (front end) *)
MODULE OPB; (* RC 6.3.89 / 21.2.94 *) (* object model 17.1.93 *)
IMPORT OPT, OPS, OPM, SYSTEM;
IMPORT OPT, OPS, OPM, Platform, SYSTEM;
CONST
@ -109,7 +109,12 @@ MODULE OPB; (* RC 6.3.89 / 21.2.94 *) (* object model 17.1.93 *)
PROCEDURE SetSetType(node: OPT.Node);
VAR i32: SYSTEM.INT32;
BEGIN SYSTEM.GET(SYSTEM.ADR(node.conval.setval)+4, i32); (* See if upper 32 bits are zero *)
BEGIN
IF Platform.LittleEndian THEN
SYSTEM.GET(SYSTEM.ADR(node.conval.setval) + 4, i32)
ELSE
SYSTEM.GET(SYSTEM.ADR(node.conval.setval), i32)
END;
IF i32 = 0 THEN node.typ := OPT.set32typ ELSE node.typ := OPT.set64typ END
END SetSetType;

View file

@ -195,10 +195,31 @@ MODULE OPM; (* RC 6.3.89 / 28.6.89, J.Templ 10.7.89 / 22.7.96 *)
END SignedMinimum;
(* Unchecked conversion of any size integer to INTEGER or LONGINT *)
(* Unchecked conversion of any size integer to INTEGER or LONGINT.
Uses endian-neutral byte extraction since SYSTEM.VAL across different
sizes reads the wrong bytes on big-endian platforms. *)
PROCEDURE Longint* (n: SYSTEM.INT64): LONGINT; BEGIN RETURN SYSTEM.VAL(LONGINT, n) END Longint;
PROCEDURE Integer* (n: SYSTEM.INT64): INTEGER; BEGIN RETURN SYSTEM.VAL(INTEGER, n) END Integer;
PROCEDURE Longint* (n: SYSTEM.INT64): LONGINT;
VAR r: LONGINT;
BEGIN
IF ~Platform.LittleEndian THEN
SYSTEM.GET(SYSTEM.ADR(n) + (SIZE(HUGEINT) - SIZE(LONGINT)), r)
ELSE
SYSTEM.GET(SYSTEM.ADR(n), r)
END;
RETURN r
END Longint;
PROCEDURE Integer* (n: SYSTEM.INT64): INTEGER;
VAR r: INTEGER;
BEGIN
IF ~Platform.LittleEndian THEN
SYSTEM.GET(SYSTEM.ADR(n) + (SIZE(HUGEINT) - SIZE(INTEGER)), r)
ELSE
SYSTEM.GET(SYSTEM.ADR(n), r)
END;
RETURN r
END Integer;

View file

@ -161,49 +161,22 @@ PROCEDURE fraction*(x: REAL): REAL;
significant) part of `x'. Hence the following relationship shall
hold: x = scale(fraction(x), exponent(x)).
*)
VAR c: CHAR;
BEGIN
IF x=ZERO THEN RETURN ZERO
ELSE
(* Set top 7 bits of exponent to 0111111 *)
S.GET(S.ADR(x)+3, c);
c := CHR(((ORD(c) DIV 128) * 128) + 63); (* Set X0111111 (X unchanged) *)
S.PUT(S.ADR(x)+3, c);
(* Set bottom bit of exponent to 0 *)
S.GET(S.ADR(x)+2, c);
c := CHR(ORD(c) MOD 128); (* Set 0XXXXXXX (X unchanged) *)
S.PUT(S.ADR(x)+2, c);
Reals.SetExpo(x, 126); (* biased exponent 126 = 2^(-1), so x*2 gives [1.0, 2.0) *)
RETURN x * 2.0;
END
(*
CONST eZero={(hiBit+2)..29};
BEGIN
IF x=ZERO THEN RETURN ZERO
ELSE RETURN S.VAL(REAL,(S.VAL(SET,x)*nMask)+eZero)*2.0 (* set the mantissa's exponent to zero *)
END
*)
END fraction;
PROCEDURE IsInfinity * (real: REAL) : BOOLEAN;
VAR c0, c1, c2, c3: CHAR;
BEGIN
S.GET(S.ADR(real)+0, c3);
S.GET(S.ADR(real)+1, c2);
S.GET(S.ADR(real)+2, c1);
S.GET(S.ADR(real)+3, c0);
RETURN (ORD(c0) MOD 128 = 127) & (ORD(c1) = 128) & (ORD(c2) = 0) & (ORD(c3) = 0)
RETURN (Reals.Expo(real) = 255) & (S.VAL(SET, real) * {0..22} = {})
END IsInfinity;
PROCEDURE IsNaN * (real: REAL) : BOOLEAN;
VAR c0, c1, c2, c3: CHAR;
BEGIN
S.GET(S.ADR(real)+0, c3);
S.GET(S.ADR(real)+1, c2);
S.GET(S.ADR(real)+2, c1);
S.GET(S.ADR(real)+3, c0);
RETURN (ORD(c0) MOD 128 = 127)
& (ORD(c1) DIV 128 = 1)
& ((ORD(c1) MOD 128 # 0) OR (ORD(c2) # 0) OR (ORD(c3) # 0))
RETURN (Reals.Expo(real) = 255) & (S.VAL(SET, real) * {0..22} # {})
END IsNaN;
PROCEDURE sign*(x: REAL): REAL;

View file

@ -68,7 +68,6 @@ MODULE ulmTypes;
CONST
bigEndian* = 0; (* SPARC, M68K etc *)
littleEndian* = 1; (* Intel 80x86, VAX etc *)
byteorder* = littleEndian; (* machine-dependent constant *)
TYPE
ByteOrder* = SYS.INT8; (* bigEndian or littleEndian *)
@ -79,10 +78,20 @@ MODULE ulmTypes;
TYPE
SetInt* = SYS.INT32; (* Types.Int32 type that corresponds to Types.Set *)
VAR
byteorder*: ByteOrder; (* detected at module initialisation *)
msb*: SYS.SET32;
msbIsMax*, msbIs0*: SYS.INT8;
msbindex*, lsbindex*, nofbits*: SYS.INT32;
PROCEDURE DetectByteOrder;
VAR test: SYS.INT32; c: CHAR;
BEGIN
test := 1; SYS.GET(SYS.ADR(test), c);
IF c = 1X THEN byteorder := littleEndian
ELSE byteorder := bigEndian
END
END DetectByteOrder;
PROCEDURE ToInt8*(int: Int32) : Int8;
BEGIN
RETURN SHORT(SHORT(int))
@ -109,6 +118,7 @@ MODULE ulmTypes;
END ToReal64;
BEGIN
DetectByteOrder;
msb := SYS.VAL(SYS.SET32, MIN(SetInt));
(* most significant bit, converted to a Types.Set *)

View file

@ -656,7 +656,11 @@ Especially Length would become fairly complex.
WHILE b < 0 DO INC(q, ASH(b+128, s)); INC(s, 7); Read(R, b) END;
INC(q, ASH(b MOD 64 - b DIV 64 * 64, s));
Assert(LEN(x) <= 8);
SYSTEM.MOVE(SYSTEM.ADR(q), SYSTEM.ADR(x), LEN(x)) (* Assumes little endian representation of q and x. *)
IF Platform.LittleEndian THEN
SYSTEM.MOVE(SYSTEM.ADR(q), SYSTEM.ADR(x), LEN(x))
ELSE
SYSTEM.MOVE(SYSTEM.ADR(q) + SIZE(HUGEINT) - SHORT(LEN(x)), SYSTEM.ADR(x), LEN(x))
END
END ReadNum;
PROCEDURE WriteBool* (VAR R: Rider; x: BOOLEAN);
@ -678,13 +682,11 @@ Especially Length would become fairly complex.
PROCEDURE WriteSet* (VAR R: Rider; x: SET);
VAR b: ARRAY 4 OF CHAR; i: LONGINT;
y: SYSTEM.SET64;
BEGIN
IF SIZE(SET) = SIZE(INTEGER) THEN
i := SYSTEM.VAL(INTEGER, x);
ELSE
y := x;
i := SYSTEM.VAL(LONGINT, y);
i := SYSTEM.VAL(LONGINT, x); (* same byte width: endian-neutral reinterpret *)
END;
b[0] := CHR(i); b[1] := CHR(i DIV 100H); b[2] := CHR(i DIV 10000H); b[3] := CHR(i DIV 1000000H);

View file

@ -91,12 +91,24 @@ END HugeInt;
PROCEDURE Int*(VAR i: INTEGER);
VAR h: HUGEINT;
BEGIN HugeInt(h); i := SYSTEM.VAL(INTEGER, h)
BEGIN
HugeInt(h);
IF ~Platform.LittleEndian THEN
SYSTEM.GET(SYSTEM.ADR(h) + SIZE(HUGEINT) - SIZE(INTEGER), i)
ELSE
SYSTEM.GET(SYSTEM.ADR(h), i)
END
END Int;
PROCEDURE LongInt*(VAR i: LONGINT);
VAR h: HUGEINT;
BEGIN HugeInt(h); i := SYSTEM.VAL(LONGINT, h)
BEGIN
HugeInt(h);
IF ~Platform.LittleEndian THEN
SYSTEM.GET(SYSTEM.ADR(h) + SIZE(HUGEINT) - SIZE(LONGINT), i)
ELSE
SYSTEM.GET(SYSTEM.ADR(h), i)
END
END LongInt;
PROCEDURE Line*(VAR line: ARRAY OF CHAR);

View file

@ -1,6 +1,6 @@
MODULE Math;
IMPORT SYSTEM;
IMPORT SYSTEM, Platform;
(* Math - Oakwood REAL Mathematics.
Adapted from OOC LowReal.Mod and RealMath.Mod
@ -768,7 +768,14 @@ BEGIN
END fcmp;
PROCEDURE ToREAL(h: HUGEINT): REAL;
BEGIN RETURN SYSTEM.VAL(REAL, h)
VAR r: REAL;
BEGIN
IF ~Platform.LittleEndian THEN
SYSTEM.GET(SYSTEM.ADR(h) + SIZE(HUGEINT) - SIZE(REAL), r)
ELSE
SYSTEM.GET(SYSTEM.ADR(h), r)
END;
RETURN r
END ToREAL;
BEGIN

View file

@ -78,7 +78,7 @@ MODULE MathL;
the status flags for mode control.
*)
IMPORT Math, SYSTEM;
IMPORT Math, Platform, SYSTEM;
CONST
pi* = 3.1415926535897932384626433832795028841972D0;
@ -146,12 +146,17 @@ PROCEDURE exponent*(x: LONGREAL): INTEGER;
that lies between `expoMin' and `expoMax'. An exception shall occur
and may be raised if `x' is equal to 0.0.
*)
VAR i: SYSTEM.INT64;
VAR i: SYSTEM.INT64; r: INTEGER;
BEGIN
IF x = ZERO THEN RETURN 0 (* NOTE: x=0.0 should raise exception *)
ELSE
i := SYSTEM.LSH(SYSTEM.VAL(SYSTEM.INT64, x), -52) MOD 2048;
RETURN SYSTEM.VAL(INTEGER, i) - 1023
IF ~Platform.LittleEndian THEN
SYSTEM.GET(SYSTEM.ADR(i) + SIZE(HUGEINT) - SIZE(INTEGER), r)
ELSE
SYSTEM.GET(SYSTEM.ADR(i), r)
END;
RETURN r - 1023
END
END exponent;

View file

@ -37,7 +37,7 @@ MODULE Modules; (* jt 6.1.96 *)
as the C main program. *)
BEGIN
MainStackFrame := argvadr;
ArgCount := SYSTEM.VAL(INTEGER, argc);
ArgCount := SHORT(argc);
SYSTEM.GET(argvadr, ArgVector);
InitHeap; (* Initialse heap variables needed for compiler generated *__inits *)

View file

@ -1,8 +1,19 @@
MODULE Reals;
(* JT, 5.2.90 / RC 9.12.91 conversion between reals and strings for HP-700, MB 9.12.91, JT for Ofront, 16.3. 95*)
(* DCWB 20160817 Made independent of INTEGER size *)
(* Endian-neutral: exponent byte offsets are set at module initialisation *)
IMPORT SYSTEM, Platform;
VAR
(* Byte offsets within a REAL/LONGREAL for the two exponent-carrying bytes.
expHi: contains sign(1) + exponent MSBs
expLo: contains exponent LSB(s) + fraction MSBs
Little-endian: REAL expHi=3 expLo=2 / LONGREAL expHi=7 expLo=6
Big-endian: REAL expHi=0 expLo=1 / LONGREAL expHi=0 expLo=1 *)
realExpHi, realExpLo: INTEGER;
lrealExpHi, lrealExpLo: INTEGER;
IMPORT SYSTEM;
PROCEDURE Ten*(e: INTEGER): REAL;
VAR r, power: LONGREAL;
@ -29,47 +40,52 @@ MODULE Reals;
END TenL;
(* Real number format (IEEE 754)
(* IEEE 754 exponent layout (MSB-first bit numbering):
REAL bit 31=sign, bits 30-23=exponent(8), bits 22-0=fraction(23)
LONGREAL bit 63=sign, bits 62-52=exponent(11), bits 51-0=fraction(52)
TYPE REAL - Single precision / binary32:
1/sign, 8/exponent, 23/significand
expHi byte: sign(1) | exponent[MSBs]
expLo byte: exponent[LSBs] | fraction[MSBs]
TYPE LONGREAL - Double precision / binary64:
1/sign, 11/exponent, 52/significand
exponent:
stored as exponent value + 127.
significand (fraction):
excludes leading (most significant) bit which is assumed to be 1.
*)
REAL: exponent = (ORD(expHi) * 2 + ORD(expLo) DIV 128) MOD 256
LONGREAL: exponent = (ORD(expHi) * 16 + ORD(expLo) DIV 16 ) MOD 2048 *)
PROCEDURE Expo*(x: REAL): INTEGER;
VAR i: INTEGER;
VAR hi, lo: CHAR;
BEGIN
SYSTEM.GET(SYSTEM.ADR(x)+2, i);
RETURN (i DIV 128) MOD 256
SYSTEM.GET(SYSTEM.ADR(x) + realExpHi, hi);
SYSTEM.GET(SYSTEM.ADR(x) + realExpLo, lo);
RETURN (ORD(hi) * 2 + ORD(lo) DIV 128) MOD 256
END Expo;
PROCEDURE SetExpo*(VAR x: REAL; ex: INTEGER);
VAR c: CHAR;
VAR c: CHAR;
BEGIN
(* Replace exponent bits within top byte of REAL *)
SYSTEM.GET(SYSTEM.ADR(x)+3, c);
SYSTEM.PUT(SYSTEM.ADR(x)+3, CHR(((ORD(c) DIV 128) * 128) + ((ex DIV 2) MOD 128)));
(* Replace exponent bits within 2nd byte of REAL *)
SYSTEM.GET(SYSTEM.ADR(x)+2, c);
SYSTEM.PUT(SYSTEM.ADR(x)+2, CHR((ORD(c) MOD 128) + ((ex MOD 2) * 128)))
SYSTEM.GET(SYSTEM.ADR(x) + realExpHi, c);
SYSTEM.PUT(SYSTEM.ADR(x) + realExpHi, CHR((ORD(c) DIV 128) * 128 + (ex DIV 2) MOD 128));
SYSTEM.GET(SYSTEM.ADR(x) + realExpLo, c);
SYSTEM.PUT(SYSTEM.ADR(x) + realExpLo, CHR( ORD(c) MOD 128 + (ex MOD 2) * 128))
END SetExpo;
PROCEDURE ExpoL*(x: LONGREAL): INTEGER;
VAR i: INTEGER;
VAR hi, lo: CHAR;
BEGIN
SYSTEM.GET(SYSTEM.ADR(x)+6, i);
RETURN (i DIV 16) MOD 2048
SYSTEM.GET(SYSTEM.ADR(x) + lrealExpHi, hi);
SYSTEM.GET(SYSTEM.ADR(x) + lrealExpLo, lo);
RETURN (ORD(hi) * 16 + ORD(lo) DIV 16) MOD 2048
END ExpoL;
PROCEDURE SetExpoL*(VAR x: LONGREAL; ex: INTEGER);
VAR c: CHAR;
BEGIN
SYSTEM.GET(SYSTEM.ADR(x) + lrealExpHi, c);
SYSTEM.PUT(SYSTEM.ADR(x) + lrealExpHi, CHR((ORD(c) DIV 128) * 128 + (ex DIV 16) MOD 128));
SYSTEM.GET(SYSTEM.ADR(x) + lrealExpLo, c);
SYSTEM.PUT(SYSTEM.ADR(x) + lrealExpLo, CHR((ex MOD 16) * 16 + ORD(c) MOD 16))
END SetExpoL;
(* Convert LONGREAL: Write positive integer value of x into array d.
The value is stored backwards, i.e. least significant digit
first. n digits are written, with trailing zeros fill.
@ -112,14 +128,17 @@ MODULE Reals;
END ToHex;
PROCEDURE BytesToHex(VAR b, d: ARRAY OF SYSTEM.BYTE);
VAR i: INTEGER; l: LONGINT; by: CHAR;
VAR i, j, len: INTEGER; by: CHAR;
BEGIN
i := 0; l := LEN(b);
WHILE i < l DO
len := SHORT(LEN(b));
IF Platform.LittleEndian THEN i := 0 ELSE i := len - 1 END;
j := 0;
WHILE (i >= 0) & (i < len) DO
by := SYSTEM.VAL(CHAR, b[i]);
d[i*2] := ToHex(ORD(by) DIV 16);
d[i*2+1] := ToHex(ORD(by) MOD 16);
INC(i)
d[j*2] := ToHex(ORD(by) DIV 16);
d[j*2+1] := ToHex(ORD(by) MOD 16);
INC(j);
IF Platform.LittleEndian THEN INC(i) ELSE DEC(i) END
END
END BytesToHex;
@ -133,4 +152,18 @@ MODULE Reals;
BEGIN BytesToHex(x, d)
END ConvertHL;
PROCEDURE InitEndian;
BEGIN
IF Platform.LittleEndian THEN
realExpHi := 3; realExpLo := 2;
lrealExpHi := 7; lrealExpLo := 6
ELSE
realExpHi := 0; realExpLo := 1;
lrealExpHi := 0; lrealExpLo := 1
END
END InitEndian;
BEGIN
InitEndian
END Reals.

View file

@ -1,6 +1,6 @@
MODULE outtest;
IMPORT Out, SYSTEM;
IMPORT Out, Platform, SYSTEM;
VAR
r: REAL;
@ -13,13 +13,15 @@ PROCEDURE wi(i: HUGEINT); BEGIN Out.Int(i,1) END wi;
PROCEDURE wl; BEGIN Out.Ln END wl;
PROCEDURE wh(VAR h: ARRAY OF SYSTEM.BYTE);
VAR i: INTEGER; b: SYSTEM.INT8;
VAR i, len: INTEGER; b: SYSTEM.INT8;
BEGIN
i := SHORT(LEN(h));
WHILE i > 0 DO
DEC(i); b := SYSTEM.VAL(SYSTEM.INT8, h[i]);
len := SHORT(LEN(h));
IF Platform.LittleEndian THEN i := len - 1 ELSE i := 0 END;
WHILE (i >= 0) & (i < len) DO
b := SYSTEM.VAL(SYSTEM.INT8, h[i]);
IF b DIV 16 MOD 16 < 10 THEN wc(CHR(b DIV 16 MOD 16 + 48)) ELSE wc(CHR(b DIV 16 MOD 16 + 55)) END;
IF b MOD 16 < 10 THEN wc(CHR(b MOD 16 + 48)) ELSE wc(CHR(b MOD 16 + 55)) END;
IF Platform.LittleEndian THEN DEC(i) ELSE INC(i) END
END
END wh;

View file

@ -362,8 +362,7 @@ void testSystemDotH() {
if (((sizeof(rec2)==65) == (sizeof(rec0)==1)) && ((sizeof(rec2)-64) != sizeof(rec0)))
printf("error: unsupported record layout sizeof(rec0) = %lu sizeof(rec2) = %lu\n", (long)sizeof(rec0), (long)sizeof(rec2));
x = 1;
assert(*(char*)&x == 1, "C compiler does not store multibyte numeric values in little-endian order.");
/* byte-order check removed: voc supports both little-endian and big-endian platforms */
}

View file

@ -133,8 +133,8 @@ translate:
browsercmd:
@printf '\nMaking symbol browser\n'
@cd $(BUILDDIR); "$(ROOTDIR)/$(OBECOMP)" -Ss -O$(MODEL) ../../src/runtime/Oberon.Mod
@cd $(BUILDDIR); "$(ROOTDIR)/$(OBECOMP)" -Sm -O$(MODEL) ../../src/tools/browser/BrowserCmd.Mod
@cd $(BUILDDIR); "$(ROOTDIR)/$(OBECOMP)" -Ss -A$(ADRSIZE)$(ALIGNMENT) -O$(MODEL) ../../src/runtime/Oberon.Mod
@cd $(BUILDDIR); "$(ROOTDIR)/$(OBECOMP)" -Sm -A$(ADRSIZE)$(ALIGNMENT) -O$(MODEL) ../../src/tools/browser/BrowserCmd.Mod
@cd $(BUILDDIR); $(COMPILE) BrowserCmd.c Oberon.c -o showdef \
Platform.o Texts.o OPT.o Heap.o Out.o SYSTEM.o OPM.o OPS.o OPV.o \
Files.o Reals.o Modules.o VT100.o Configuration.o Strings.o \