Fix PowerPC ncg so setjmp() returns the correct value. I got unlucky when ncg picked r3 for "uses REG"; this destroyed the return value in r3 and caused the new test to fail.
		
			
				
	
	
		
			157 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
(*
 | 
						|
 * Generates some integer sequences.  Each generator is a process that
 | 
						|
 * yields integers to the main process.  ACK switches processes by
 | 
						|
 * saving and restoring the stack.  It uses _lor_ and _str_ to save
 | 
						|
 * and restore the local base and frame pointer.
 | 
						|
 *)
 | 
						|
MODULE SemaTest;
 | 
						|
FROM Semaphores IMPORT Sema, NewSema, Down, Up, StartProcess;
 | 
						|
FROM Storage IMPORT ALLOCATE;
 | 
						|
FROM Test IMPORT fail, finished;
 | 
						|
 | 
						|
TYPE
 | 
						|
  Generator = POINTER TO GeneratorRecord;
 | 
						|
  GeneratorRecord = RECORD
 | 
						|
    resume: Sema;       (* up when resuming generator *)
 | 
						|
    yield: Sema;        (* up when yielding value *)
 | 
						|
    value: INTEGER;
 | 
						|
  END;
 | 
						|
VAR
 | 
						|
  curgen: Generator;    (* current generator *)
 | 
						|
  startLock: Sema;      (* down when booting generator *)
 | 
						|
  startProc: PROC;
 | 
						|
  startSelf: Generator;
 | 
						|
 | 
						|
PROCEDURE BootGenerator;
 | 
						|
  VAR pr: PROC; self: Generator;
 | 
						|
BEGIN
 | 
						|
  pr := startProc;
 | 
						|
  self := startSelf;
 | 
						|
  Up(startLock);
 | 
						|
  Down(self^.resume);   (* wait for first Resume *)
 | 
						|
  pr();
 | 
						|
END BootGenerator;
 | 
						|
 | 
						|
PROCEDURE StartGenerator(gen: Generator; pr: PROC);
 | 
						|
BEGIN
 | 
						|
  gen^.resume := NewSema(0);
 | 
						|
  gen^.yield := NewSema(0);
 | 
						|
  Down(startLock);
 | 
						|
  startProc := pr;
 | 
						|
  startSelf := gen;
 | 
						|
  StartProcess(BootGenerator, 8192);
 | 
						|
END StartGenerator;
 | 
						|
 | 
						|
PROCEDURE Resume(gen: Generator): INTEGER;
 | 
						|
  VAR self: Generator;
 | 
						|
BEGIN
 | 
						|
  self := curgen;
 | 
						|
  curgen := gen;
 | 
						|
  Up(gen^.resume);
 | 
						|
  Down(gen^.yield);     (* wait for Yield *)
 | 
						|
  curgen := self;
 | 
						|
  RETURN gen^.value
 | 
						|
END Resume;
 | 
						|
 | 
						|
PROCEDURE Yield(i: INTEGER);
 | 
						|
  VAR self: Generator;
 | 
						|
BEGIN
 | 
						|
  self := curgen;
 | 
						|
  self^.value := i;
 | 
						|
  Up(self^.yield);      (* curgen becomes invalid *)
 | 
						|
  Down(self^.resume);   (* wait for Resume *)
 | 
						|
END Yield;
 | 
						|
 | 
						|
PROCEDURE YieldHalfOf(i: INTEGER);
 | 
						|
BEGIN
 | 
						|
  Yield(i DIV 2);
 | 
						|
END YieldHalfOf;
 | 
						|
 | 
						|
PROCEDURE Triangular;
 | 
						|
  (* Yields the triangular numbers, http://oeis.org/A000217 *)
 | 
						|
  VAR n: INTEGER;
 | 
						|
BEGIN
 | 
						|
  n := 0;
 | 
						|
  LOOP
 | 
						|
    YieldHalfOf(n * (n + 1));
 | 
						|
    INC(n);
 | 
						|
  END;
 | 
						|
END Triangular;
 | 
						|
 | 
						|
PROCEDURE Pentagonal;
 | 
						|
  (* Yields the pentagonal numbers, http://oeis.org/A000326 *)
 | 
						|
  VAR n: INTEGER;
 | 
						|
BEGIN
 | 
						|
  n := 0;
 | 
						|
  LOOP
 | 
						|
    YieldHalfOf(n * (3 * n - 1));
 | 
						|
    INC(n);
 | 
						|
  END;
 | 
						|
END Pentagonal;
 | 
						|
 | 
						|
PROCEDURE Odious;
 | 
						|
  (* Yields the odius numbers, http://oeis.org/A000069 *)
 | 
						|
  VAR b, i, n: INTEGER;
 | 
						|
BEGIN
 | 
						|
  n := 1;
 | 
						|
  LOOP
 | 
						|
    (* b := count bits in n *)
 | 
						|
    b := 0;
 | 
						|
    i := n;
 | 
						|
    WHILE i # 0 DO
 | 
						|
      INC(b, i MOD 2);
 | 
						|
      i := i DIV 2;
 | 
						|
    END;
 | 
						|
 | 
						|
    IF (b MOD 2) = 1 THEN
 | 
						|
      Yield(n);
 | 
						|
    END;
 | 
						|
    INC(n);
 | 
						|
  END;
 | 
						|
END Odious;
 | 
						|
 | 
						|
TYPE
 | 
						|
  Triple = ARRAY[1..3] OF INTEGER;
 | 
						|
PROCEDURE T(i1, i2, i3: INTEGER): Triple;
 | 
						|
  VAR t: Triple;
 | 
						|
BEGIN
 | 
						|
  t[1] := i1; t[2] := i2; t[3] := i3; RETURN t
 | 
						|
END T;
 | 
						|
 | 
						|
CONST
 | 
						|
  two28 = 268435456D;   (* 0x1000_0000 *)
 | 
						|
VAR
 | 
						|
  a: ARRAY [0..9] OF Triple;
 | 
						|
  tri, pen, odi: Generator;
 | 
						|
  i, g1, g2, g3: INTEGER;
 | 
						|
BEGIN
 | 
						|
  startLock := NewSema(1);
 | 
						|
 | 
						|
  ALLOCATE(tri, SIZE(GeneratorRecord));
 | 
						|
  ALLOCATE(pen, SIZE(GeneratorRecord));
 | 
						|
  ALLOCATE(odi, SIZE(GeneratorRecord));
 | 
						|
  StartGenerator(tri, Triangular);
 | 
						|
  StartGenerator(pen, Pentagonal);
 | 
						|
  StartGenerator(odi, Odious);
 | 
						|
 | 
						|
  a[0] := T( 0,   0,  1);
 | 
						|
  a[1] := T( 1,   1,  2);
 | 
						|
  a[2] := T( 3,   5,  4);
 | 
						|
  a[3] := T( 6,  12,  7);
 | 
						|
  a[4] := T(10,  22,  8);
 | 
						|
  a[5] := T(15,  35, 11);
 | 
						|
  a[6] := T(21,  51, 13);
 | 
						|
  a[7] := T(28,  70, 14);
 | 
						|
  a[8] := T(36,  92, 16);
 | 
						|
  a[9] := T(45, 117, 19);
 | 
						|
 | 
						|
  FOR i := 0 TO INTEGER(9) DO
 | 
						|
    g1 := Resume(tri);
 | 
						|
    g2 := Resume(pen);
 | 
						|
    g3 := Resume(odi);
 | 
						|
    IF g1 # a[i][1] THEN fail(1D * two28 + LONG(a[i][1])) END;
 | 
						|
    IF g2 # a[i][2] THEN fail(2D * two28 + LONG(a[i][2])) END;
 | 
						|
    IF g3 # a[i][3] THEN fail(3D * two28 + LONG(a[i][3])) END;
 | 
						|
  END;
 | 
						|
  finished;
 | 
						|
END SemaTest.
 |