4

I am writing an application that uses random numbers. The plan is to use RNDL/RNDH ($4E) to initialize a pseudo-random number generator. Unfortunately, I keep getting the same sequence. Tonight, I finally realized that $4E is not random with BASIC.SYSTEM. It appears that RNDL/RNDH get overwritten with the last address after a file gets loaded. Meaning, after BRUNning the application, I end up with the same random number seed. Hopefully someone can give me some guidance.

Simple test program:

0300-   A5 4F       LDA   $4F
0302-   20 DA FD    JSR   $FDDA
0305-   A5 4E       LDA   $4E
0307-   20 DA FD    JSR   $FDDA
030A-   4C 8E FD    JMP   $FD8E

Sample runs:

]BRUN SHOWRND
030D
]BRUN SHOWRND,A$810
081D
]BRUN SHOWRND,A$980
098D

To prove this is using RNDL/RNDH, here's a few CALL 768's:

]CALL768
39DB

]CALL768
A8EA

]CALL768
245B

Thoughts/Ideas?

3
  • 2
    The values at 78 and 79 are updated by the keyin routine while it's waiting for keyboard input. See: retrocomputing.stackexchange.com/questions/26123/…
    – Brian
    Feb 12 at 5:21
  • 2
    You would have the same problem with a DOS program if you booted directly into it from power-on (I observed this happening with the game Starship Commander, which seeded the Applesoft RNG with the values from $4e/4f). You have to seed the random number generator yourself. The simplest way to do that is to stop and wait for input; you can call KEYIN or increment a different location yourself.
    – fadden
    Feb 12 at 16:09
  • @fadden: I wonder if there would have been any difficulty with having DOS hit $4E when looking for a disk sector header, each time it sees a byte that isn't one, and having it xor $4F with $4E each time it sees a sector other than the one it's looking for? That would offer numbers that were more 'random' than what $4E/$4F provide.
    – supercat
    Feb 12 at 18:36

3 Answers 3

4

It seems that RANDL ($4E) and RANDH ($4F) were re-purposed as a pointer named usrbuf that's used extensively throughout ProDOS. It's used as the destination for writing the bytes read from a file. Your program is written to memory by the STA in the following code (which resides at address $F112) on page 240 of this ProDOS source listing:

rdpart0  dex
rdpart   lda  (posptr),y  ;move data to user's buffer
         sta  (usrbuf),y  ; one byte at a time.

If you want to get a random seed the easiest way is to display a title screen, clear the keyboard strobe, and wait for a key press to proceed. While waiting, increment an 8 or 16 bit value. This is what the system firmware's KEYIN routine at $FD1B does for RNDL and RNDH.

You could write your own seed-generating wait routine, and you should definitely use your own Pseudo Random Number Generator routine rather than Applesoft's RND, which has known problems - see answers to this question.

2
  • I was sort of expecting something of this nature was going on... Is there any common solution? (No clock, so I'm pondering maybe summing the ZP and then doing the same increment in an input loop to randomize.)
    – A2Geek
    Feb 12 at 15:16
  • @A2Geek: I merged my previous reply to your comment into the answer. Feb 13 at 6:40
1

RNDL/H is incremented by the standard keyboard routine when waiting for a key as described in the Technical Reference

enter image description here (P.62 of the Apple II Reference Manual)

And shown in the corresponding monitor listing

enter image description here (P.148 of the Apple II Reference Manual)

RDKEY gets only called (via KSW) when the default keyboard is queried. It isnot guaranteed if KSW is redirected or other keyboard routines are use - although many third party drivers do increment it.

The content of RNDH/L isn't true random either nor guaranteed to be different in subsequent calls or program runs. That's why BASIC maintains it own random number generator. This is not only true with ProDOS' BASIC.SYSTEM, but for all kind of application. Using BASIC.SYSTEM's BRUN just makes it (in your case) easy to observe.

The simplest way to stay with RNDH/L would be asking/waiting for a keystroke.

After all, that's the whole idea Woz had in mind creating this function. Any game would have some user input wich by definition carries imprecise timing, thus generating a reasonable random number if incremented fast enough. In this case it's incremented at about 80 kHz. While this may give a slight skew to numbers being not really random but incremental (modulo 2^16), it's good enough for practical purpose, especially when only using the lower bits.

1

If you want to go straight into algorithms that use random numbers without having any keyboard input (e.g. boot apple, launches ProDOS, and this application is the first .SYSTEM or STARTUP that gets found and jumps straight into getting random numbers), RNDL/RNDH isn't going to give you very random values. As others mentioned, the RNDL/RNDH values are driven by the keyboard input code in the firmware.

So what to use? I'd say pick a memory location and copy it into RNDL/RNDH. If you're on real hardware, the RAM isn't cleared to particular value at boot and could appear random, unlike an emulator which might set all RAM to a 00/FF/00/FF pattern for debugging purposes. The goal is to find a location which isn't going to be set up the same way with a normal ProDOS + BASIC boot pattern. I'd probably avoid anything south of the 2nd hi-res graphic page ($4000) since BASIC programs get loaded into $800 and below that is the text area which is probably consistent as well in your boot sequence. BASIC.SYSTEM loaded into $2000, so that would be consistent. If the high resolution graphics pages weren't initialized, it should be garbage from $4000-$95FF, since I believe ProDOS and BASIC.SYSTEM ends up using $9600+.

As well, you could try reading bytes from the hardware mapped area ($C000-CFFF), but that is riddled with software switches that could trigger things. However, if you hit a slot-specific location for an empty slot, you could get semi-random values since nothing is behind it, but you might end up just getting some consistency from "last value on the bus" type phenomena.

As mentioned, if you're on an emulator your RAM won't be "power-on garbage" most likely, but chances are it might support a clock of some sort, so you could resort to that too?

1
  • 1
    Many softswitches (e.g. graphics mode ones) can be used to poll the floating bus, which will usually return video memory data from the video scanner. In fact a few games do this, which is one of the reasons I first implemented emulating it back in the 90's. AppleWin also emulates some of the power-on DRAM state. Various patterns are seen, mostly repeats of 00's and FF's, though other values appear. I still think a loop like kEYIN is the best approach for a seed. Feb 13 at 6:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .