Retrocomputing

Random numbers support

The following example will show how Knuths random generator from pages 221-222 in Numerical Recipes in Pascal, 1st edition can be created as an external module and then linked into a Pascal P-code module.

The random function needs to keep a state to generate a different number from the previous call. External Pascal sub-modules don't have their own global storage, and therefore the main procedure must provide that space. We don't want the calling program to know about the inner working of the external rand procedure, and we are therefore making it look like the external procedure just needs an integer, which must be set to 0 before the first call. In reality it is interpreted as a pointer to a record structure. If it is nil then the structure is a allocated with a new operation. The mechanism expects nil to be identical to '0' when seen as an integer.

OS-9 Pascal edition

{ Returns a uniform random deviate between 0.0 and 1.0.
  Set idum to any negative value to initialize or reinitialize the sequence.
}
PROGRAM SupportRand;
TYPE
  stateptr = ^state;
  state = RECORD
           Idum, Ran3Inext, Ran3Extp : integer;
           Ran3Ma : ARRAY [1..55] OF real
          END;

{ Initialize the storage for the random generator
  and randomize based on system time.
}
PROCEDURE randomize(VAR b:stateptr);

  VAR
    y, m, d, h, mi, s : integer;

  BEGIN
    IF b = nil THEN
      NEW(b);
    b^.Idum := -1;
    systime(y, m, d, h, mi, s);
    IF y <> 0 THEN
      b^.Idum := -h * 1330 + mi * 30 + s;
  END;


FUNCTION random(VAR b:stateptr):real;

  (* CONST
   * mbig=1000000000;mseed=161803398;mz=0;fac=1.0e-9;
   * var
   * i,ii,k,mj,mk : longint;
   *)

  CONST
     mbig = 4.0e6;
     mseed = 1618033.0;
     mz = 0.0;
     fac = 2.5e-7;  { 1/mbig }

  VAR
     i,ii,k : integer;
     mj,mk : real;

  BEGIN
     IF b = nil THEN
        randomize(b);
     IF b^.Idum < 0 THEN BEGIN
        mj := mseed + b^.Idum;
        IF mj >= 0.0 THEN
           mj := mj - mbig * trunc(mj/mbig)
        ELSE
             mj := mbig - abs(mj) + mbig * trunc(abs(mj)/mbig);
  (*         mj := mj mod mbig; *)
        b^.Ran3Ma[55] := mj;
        mk := 1;
        FOR i := 1 TO 54 DO BEGIN
            ii := 21 * i mod 55;
            b^.Ran3Ma[ii] := mk;
            mk := mj-mk;
            IF mk < mz THEN mk := mk+mbig;
            mj := b^.Ran3Ma[ii]
        END;
        FOR k := 1 TO 4 DO BEGIN
           FOR i := 1 TO 55 DO BEGIN
              b^.Ran3Ma[i] := b^.Ran3Ma[i]-b^.Ran3Ma[1+((i+30) mod 55)];
              IF b^.Ran3Ma[i] < mz THEN b^.Ran3Ma[i] := b^.Ran3Ma[i] + mbig;
            END
        END;
        b^.Ran3Inext := 0;
        b^.Ran3Extp := 31;
        b^.Idum := 1
     END;

     b^.Ran3Inext := b^.Ran3Inext+1;
     IF b^.Ran3Inext = 56 THEN
        b^.Ran3Inext := 1;
     b^.Ran3Extp := b^.Ran3Extp+1;
     IF b^.Ran3Extp = 56 THEN
        b^.Ran3Extp := 1;
     mj := b^.Ran3Ma[b^.Ran3Inext]-b^.Ran3Ma[b^.Ran3Extp];
     IF mj < mz THEN mj := mj+mbig;
     b^.Ran3Ma[b^.Ran3Inext] := mj;
     random := mj*fac;
  END;

BEGIN {no main program, this is a standalone subroutine module}
END.

Compilation to be linked as an external module

First we compile the SupportRandom.pas file into a P-code file with the name SupportRandom.prun.

OS9: pascal <SupportRandom.pas : o=SupportRandom.prun

Note the numbers of the procedures you want to make into external subroutines.

PROC NAME       PSEC  PSIZE  LOCAL  STACK   CSEC  CSIZE  DEBUG
   0 SUPPORTR      6      7      0      7      7      0      0
   1 RANDOMIZ      1     91     12     19      2      0      0
   2 RANDOM        2    823     20     25      6      0      0
                        921     32     51             0

The second step is to translate it into assembly form.

OS9:pascals pascalt.prun #20K

Enter the name of the pcode file to be translated.
SupportRandom.prun

Enter the name of the 6809 assembly language file to be produced.
SupportRandom.asm

Translate all procedures? (Y or N)? n

Produce external definition file (Y or N)? y

Enter the name of the external definition file to be produced.
SupportRandom.e

Enter a list of procedure numbers to translate.
A zero value will terminate the list.
A negative value will back out a previously selected entry.
1
2
0

List of procedures selected for translation.
   1
   2

Is this list correct. (Y or N)? y

Enter a pathlist to be used as the external module pathlist
and module name.
random

Translate line numbers in pcode file (Y or N)? y


Begin translation of ...
Proc Name     Psize Csize
   1 RAND       682     0

Assemble the module. The file PascalDefs must be present in the data directory.

OS9:asm SupportRandom.asm o=SupportRandom

The external module is created in the execution directory with the file name SupportRandom. It is recommended to choose a naming convention that shows that these files are not commands. The module is now available for other programs to link to. Keep the SupportRandom.e for this occasion.

When you have compiled your program, which uses random numbers, then the output is a file called PCODEF. This is then linked to the support module.

Run the linkage editor.

OS9:pascale <SupportRandom.e :PCODEF

Run the program.

OS9:pascaln PCODEF