!lm10
!rm76
Random Number Generator from Integer BASIC

When you are writing games or other simulation exercises, you frequently need a source of random numbers.  In Basic it's easy, but how about assembly language?

The WozPak from Call A.P.P.L.E. has directions for calling the RND(X) function in the Integer BASIC ROMs.  Remember that this function returns a random integer between 0 and X-1 for an argument X.  Linda Egan, from Maywood, California, wrote that she had trouble making the WozPak method work.  I don't know what that method was, but I looked up the code in the ROM and came up with some working code.

<random code here>

Lines 1190-1260 are all you need.  They set up a call to the ROM code, and pick up the returned value.

Line 1190 sets the X-register to $20.  The ROM code uses X for a stack index, and $20 means an empty stack.  This is not the hardware stack ($100-1FF), but a software-implemented stack.  The stack is in three parts.  The part I call IB.LOSTACK runs from $50 thru $6F.  IB.HISTACK runs from $A0 thru $BF.  A third part runs from $78 thru $97.  The ROM code pushes our argument on these stacks like this:  the low byte goes on LOSTACK, the high byte on HISTACK, and a zero (from the Y-register) on the FLAGSTACK.  (If the value pushed on FLAGSTACK was not zero, it would be used as the high-byte of an address along with the low-byte from LOSTACK to indirectly address the data value.)

Lines 1200 and 1210 store our argument where the ROM code expects it to be, in $CE and $CF.  Lines 1240 and 1250 retrieve the resulting random number from the stack.

Lines 1280 through 1420 are a test loop to demonstrate the random function.  Twenty lines of eight random numbers each are printed on the screen in hexadecimal.  I used an argument of 1000, so all the numbers are between 0 and 999.

What if you don't have the Integer BASIC ROMs in your Apple?  Since the code is not very long, you could make your own copy of Woz's routines.  I did that, and came up with the following program.  I used the same test loop, but this time it is in lines 1760 thru 1900.
!np
Lines 1160 and 1170 save the argument for later use.  Lines 1180-1260 get the current random seed from the Apple Monitor and store it in VALUE.  However, if the seed was 0000 it is converted to 0100.  This is because a seed of 0000 replicates itself forever.  Furthermore, the sign bit is stripped off; in other words, VALUE is set to the seed value modulo 32768.  This is supposed to force the VALUE to be between 1 and 7FFF.

The random seed is also modified by the monitor whenever you are in KEYIN waiting for an input from the keyboard.  This code is at $FD1B thru $FD24 in the monitor ROM.  This means the seed might have any (truly random) value between 0000 and FFFF.  If by chance it is $8000 when the RND function is called, VALUE will be set to 0000.

Lines 1270-1290 clear two more bytes of VALUE, which will be used later, in the division loop.

Lines 1300-1400 are Woz's algorithm for generating a sequence of random integers.  It is a binary polynomial technique, but there seems to be a bug in it.  If you run it 32768 times, you should generate each and every value between 0 and $7FFF exactly one time, but in random order.  I tested it, and it really generates the values between $6000 and $60FF twice, and never generates $2000-20FF at all!  You can play with it and see if there are some seed values which will produce numbers between $2000 and $20FF.

Lines 1420-1440 check the argument.  If it is zero, I return the value zero for the function.  Integer BASIC would give you "*** >32767 ERR" with a zero argument.

Lines 1490-1650 are a division program, to divide the random VALUE by the LIMIT.  After it is finished, the quotient is in VALUE and VALUE+1, and the remainder is in VALUE+2 and VALUE+3.  We don't need the quotient; the remainder is the random value we want.

Lines 1690-1710 pick up the result in registers A and Y, and return to the calling program.

