Shop OBEX P1 Docs P2 Docs Learn Events
Catalina - ANSI C for the Propeller 1 & 2 - Page 12 — Parallax Forums

Catalina - ANSI C for the Propeller 1 & 2

167891012»

Comments

  • RossHRossH Posts: 5,353

    @evanh said:
    Isn't that just using the system ticks variable, after waiting on human input, to produce a seed? That shouldn't be hard to replicate.

    After a P1 reset the system ticks variable is always the same when the program starts executing. Asking for user input adds some randomness to the timing before the system timer is consulted. The P2 has a source of randomness I could use - but the P1 doesn't have such a thing (AFAIK).

    Ross.

  • evanhevanh Posts: 15,258
    edited 2024-04-13 01:24

    I'm lost. Is the user input not an option?

    PS: The Prop2's startup seed comes from ADC sampling noise I think.

    EDIT: Yep ... Ha, it just samples the bitstream direct. 50 x 31 bits = 1550 random bits.

    ' Seed xoroshiro 128** using delta-sigma ADC bits from calibration mode
    '
            wrpin   ##$00100000,#rx_pin 'put rx pin in adc gio calibration mode
    
            mov x,#50           'ready to seed 50 times with 31 bits
    
    .seed       rep #2,#31          'get 31 bits (31*4 clocks = 124/20 = ~6us)
            testp   #rx_pin     wc
            rcl y,#1
    
            bith    y,#31           'seed via hubset
            hubset  y
    
            djnz    x,#.seed
    
            wrpin   #0,#rx_pin      'return rx pin to normal mode
    

    EDIT2: I think Xoroshiro 128** is a typo on Chip's behave. I'm pretty sure that was the original Xoroshiro 128+ algorithm used to make the free-running global generator. Dunno why he typed a double asterisk.

    EDIT3: The mark-space ratio of GIO level will be around 20% ones to 80% zeros. There will be aliasing beat patterns with patches of all zeros in the sysclock/4 sampling. Still, no two will be the same.

  • RossHRossH Posts: 5,353
    edited 2024-04-13 01:41

    @evanh said:
    I'm lost. Is the user input not an option?

    Yes, that's why I do it.

    But I would like not to have to add a line like that to every P1 program that needs random numbers.

    EDIT: For instance, what if the program does not otherwise require any user input? How to seed a random number generator on the P1 in that case?

  • evanhevanh Posts: 15,258
    edited 2024-04-13 02:26

    Right, I thought you were targetting compatibility for those old programs is all.

    Using only built-in features of the Prop1 might be tricky alright .... maybe trying spamming a counter's PLL divider to keep it unstable ... but that would need to use a pin for output I suspect ... could momentarily use the comms TX pin if no other was suitable.

    EDIT: Ah, not the divider, that's just a post-VCO divider. It's the PLL's input coming from the main PHSx counter that is important for stability of the VCO in the PLL. So spamming lots of changes to FRQx to upset the PLL's reference frequency should then keep the PLL unstable. Just toggling between two target frequencies should be enough.

  • evanhevanh Posts: 15,258

    Then just have to collect the output. It could be done like Chip did in the Prop2 - treat the pin as bitstream directly. Or another way might be take timing measurements with the second counter.

  • @evanh said:
    Using only built-in features of the Prop1 might be tricky alright .... maybe trying spamming a counter's PLL divider to keep it unstable ... but that would need to use a pin for output I suspect ... could momentarily use the comms TX pin if no other was suitable.

    EDIT: Ah, not the divider, that's just a post-VCO divider. It's the PLL's input coming from the main PHSx counter that is important for stability of the VCO in the PLL. So spamming lots of changes to FRQx to upset the PLL's reference frequency should then keep the PLL unstable. Just toggling between two target frequencies should be enough.

    This sounds like what Chip's RealRandom object does: https://obex.parallax.com/obex/real-random/

  • evanhevanh Posts: 15,258
    edited 2024-04-13 04:28

    Huh, yeah, same idea but different implementation. Also somehow is extracting the random bits from the PHSx register. That implies PHSx is in some way integral to the VCO loop inside the PLL. Or is maybe looped back from the PLL output. I don't know enough about the Prop1 to understand the detail.

    EDIT: Ahhh, the video out can be driven by a counter. So it's the WAITVID instruction that is sampling the counter's PLL jitter. Chip is just looping that back in with the ADD PHSA,CNT

  • RossHRossH Posts: 5,353

    @Electrodude said:

    This sounds like what Chip's RealRandom object does: https://obex.parallax.com/obex/real-random/

    Aha! I didn't know about that object. I'll investigate incorporating it. Thanks.

    Ross.

  • RossHRossH Posts: 5,353
    edited 2024-04-24 23:11

    Catalina 7.3 has been released here.

    This is a full release. I was embarrassed not to have known about Chip's RealRandom object so I thought I had better put out a new release to incorporate it. The addition of the new RANDOM plugin is the only significant new feature, and it is only required on the Propeller 1. I use it in Dumbo Basic to eliminate the need to ask for user input when seeding the random number generator.

    Here is the relevant extract from the README.TXT:

    RELEASE 7.3
    
    New Functionality
    -----------------
    
    1. A new random number plugin has been added for the Propeller 1, based on
       Chip Gracey's RealRandom.spin. The plugin is enabled by defining the 
       Catalina symbol RANDOM. For example:
    
          catalina ex_random.c -lci -C RANDOM
    
       Note that a random number generator is built into the Propeller 2, so the 
       plugin is not required on that platform. The RANDOM plugin occupies a
       cog on the Propeller 1. It generates random data continuously, and writes
       a new 32 bit random number to the second long in its registry entry 
       approximately every 100us (at 80Mhz).
    
       C provides a pseudo random number generator called rand() and this must
       be seeded using the srand() function, otherwise it will always return
       the same sequence of pseudo random numbers.
    
       In previous releases, the getrand() function was a "stopgap" function -
       it generated true random data on the Propeller 2, but on the Propeller 1 
       it only generated pseudo random data, seeded by the system clock. However, 
       there are good reasons to have both a pseudo random number generator and 
       a true random number generator, so with the addition of the new Propeller 
       1 RANDOM plugin, getrand() has been modified to always generate 32 bit 
       pseudo random numbers seeded by the system clock on both the Propeller 1 
       and 2, and a new getrealrand() function has been added which returns a 32
       bit true random number on both the Propeller 1 and 2 (provided the RANDOM 
       plugin has been loaded on the Propeller 1). If the RANDOM plugin has not 
       been loaded (which may be because there is not a spare cog available) on 
       the Propeller 1 then getrealrand() uses the same technique as getrand().
    
       The new getrealrand() function will generate unique random numbers in 
       situations where the Propeller 1 previously would not, such as if a 
       program was automatically started immediately after power up. In such 
       situations the system clock would be reset, so the previous technique 
       of seeding a pseudo random number generator with the system clock would 
       always generate the same sequence of pseudo random numbers. 
    
       Here is a summary of the random number routines:
    
         rand(), srand()      -> rand() generates pseudo random numbers, in the
                                 range 0 to MAX_RAND (32767), and srand() can
                                 be used to seed the random number generator
    
         getrand()            -> getrand() generates 32 bits of pseudo random
                                 data using rand(). On first call it also seeds 
                                 the random number generator using srand() and
                                 the current system clock. This avoids the need
                                 to explicitly call srand()
    
         getrealrand()        -> getrealrand() returns 32 bits of random data. 
                                 On the Propeller 1 this will be true random data
                                 if the RANDOM plugin is loaded, otherwise it
                                 will use the same technique as getrand(). On the
                                 Propeller 2 it always returns true random data.
    
       The program ex_random.c in demos/examples has been updated to demonstrate 
       both rand() and getrand() (which both generate pseudo random numbers) as 
       well as the getrealrand() function (which generates true random numbers).
    
    2  Dumbo Basic has been updated to allow the use of the new getrealrand()
       function (described in point 1, above). A new RANDOM option has been
       added to the RANDOMIZE statement to seed Basic's built in pseudo random 
       number generator with getrealrand(). 
    
       Here are all the RANDOMIZE options:
    
          RANDOMIZE            -> prompt for the seed
          RANDOMIZE TIMER      -> use the the current time as the seed
          RANDOMIZE <expr>     -> use <expr> as the seed
          RANDOMIZE RANDOM     -> use getrealrand() as the seed (on the P2,
                                  or when compiled with RANDOM on the P1) or 
                                  else prompt for the seed (note this is an
                                  extension to GW Basic).
    
       The RND function has been extended to allow for the generation of either
       pseudo random or true random numbers. Instead of just RND, use RND(x) 
       where ...
         x > 0 generates the next pseudo random number
         x = 0 returns the last random number generated (pseudo or true)
         x < 0 generates a true random number (note this is an extension to GW 
               Basic, where x < 0 reseeds the random number generator - but
               that can also be done using the RANDOMIZE statement).
    
       Dumbo Basic now enables the RANDOM plugin by default when built for the
       Propeller 1, and the basic demo programs poker.bas, blackjck.bas, 
       startrek.bas and ut-trek.bas have been updated to use the RANDOM option
       of the RANDOMIZE statement instead of the TIMER option, which depended 
       on variations in user input to generate a random seed.
    
    3. Dumbo Basic's USING clause (used in PRINT, PRINT# and LPRINT statements)
       now accepts more GW Basic format options:
    
          + : a '+' indicates a leading sign will be printed (i.e. '+' or '-')
              except as noted for '-' (below). The '+' also counts as another 
              digit in the output. In GW Basic the '+' must be in the first 
              position of the USING clause, but in Dumbo Basic it can appear 
              in any position before any decimal point (the actual position
              makes no difference - the sign will always be printed immediately
              before the number). Note that (unlike GW Basic) Dumbo Basic always
              prints a sign for negative numbers - adding '+' makes it also 
              include a leading sign for positive numbers.
    
          - : a '-' anywhere in the clause indicates a trailing sign will be
              printed for negative numbers. The '-' does NOT count as another
              digit in the output - if the number is not negative, a space
              will be printed in its place. In GW Basic the '-' must be
              in the last position of the USING clause, but in Dumbo Basic 
              it can be in any position (the actual position makes no 
              difference - the '-' will always be printed immediately after 
              the number). If both '+' and '-' are included in the same USING 
              clause then the '+' is just treated as another digit position. 
    
          ^^^^ : a '^^^^' anywhere in the clause indicates an exponent of form
              'ESNN' will be used, where E is the letter 'E', S is the sign 
              of the exponent and NN is the 2 digit exponent. The '^' 
              characters do NOT count as additional digits - they always
              indicate an exponent. In GW Basic the '^^^^' must appear at 
              the end of the USING clause, but in Dumbo Basic it can be in 
              any 4 consecutive positions. The actual position makes no
              difference.
    
       For example, the statements:
          PRINT USING "##.#^^^^"; 0.001 
          PRINT USING "+#.#^^^^"; 0.001 
          PRINT USING "##.#^^^^"; -0.001 
          PRINT USING "+#.#^^^^"; -0.001 
          PRINT USING "+#.#^^^^-"; 0.001 
          PRINT USING "##.#^^^^-"; -0.001 
          PRINT USING "+#.#^^^^-"; -0.001 
    
       would result in the following output:
           1.0E-03
          +1.0E-03
          -1.0E-03
          -1.0E-03
          +1.0E-03
           1.0E-03-
           1.0E-03-
    
    Other Changes.
    --------------
    
    1. The pseudo random number generator getrand() was returning only 31 bits
       of random data, not 32. Affected the Propeller 1 only.
    
    2. Dumbo Basic was not correctly keeping track of the current position in the 
       current line of output, which meant using ',' as a separator to move to 
       the next 14 character print zone did not always end up with the output in 
       the correct position. Affected Dumbo Basic on the Propeller 1, Propeller 2,
       and also on Windows and Linux.
    
    3. All the Dumbo Basic example programs are now UNIX format files, not DOS
       format files. This makes them easier to edit using vi on Catalyst, which 
       expects UNIX format files by default. Affected Dumbo Basic on the Propeller
       1, Propeller 2, and also on Windows and Linux.
    

    It's been so long since I added a new Propeller 1 plugin that I made notes as I figured out how to do it all over again. Catalina's registry architecture is well suited to this kind of plugin, so this was possibly the easiest one I have ever added - which makes it ideal to document for future reference:

    These instructions show the steps used in creating the new RANDOM plugin and
    making it accessible via a new C library function.
    
    Note that these instructions only include details for adding the plugin to
    the Propeller 1 default target (which is in the directory 'target\p1'), but
    similar steps apply to other other targets that also need to include the new 
    plugin (such as the embedded target which is in directory 'embedded\p1'). 
    
    Also note that the details for adding new plugins to Propeller 2 targets are
    similar in concept but differ in detail, but are not included because the 
    RANDOM plugin is only applicable to the Propeller 1.
    
    Step 1. Create the plugin from the existing Spin file
    
       In this case the file target\p1\Catalina_RND_plugin.spin
       was created from RealRandom.spin by adding code to register 
       the plugin on start up, and to write the results back to the 
       registry instead of a Spin variable. Examine these two files 
       for more details.
    
    Step 2. Define a constant for the plugin
    
       Plugin constants are defined in the Spin file:
    
          target\p1\Catalina_Common.spin
    
       where the following was added:
    
          LMM_RND = 32      ' Random Number Generator
    
       and also in the C file:
    
          source\lib\include\plugin.h
    
       where the following was added:
    
          #define LMM_RND 32
    
    Step 3. Define a name for the plugin
    
       Plugin names (e.g. used when printing the registry)
       are defined in:
    
          source\lib\catalina\plugname.c
    
       where the following was added:
    
          case LMM_RND  : return "Random Number Generator";
    
    Step 4. Add the plugin to Extras.spin
    
       Extra plugins are loaded from the file:
    
         target\p1\Extras.spin
    
       where the following was added to the OBJ declarations:
    
          #ifdef RANDOM
            RND : "Catalina_RND_Plugin"
          #endif
    
       and the following was added to the Setup function:
    
          #ifdef RANDOM
            RND.Setup
          #endif
    
       and the following was added to the Start function:
    
          #ifdef RANDOM
            RND.Start
          #endif
    
    Step 5. Define a function to access the plugin
    
       In this case, the function was defined in:
    
          source\lib\include\prop.h
    
       where the following was added:
    
          int getrealrand();
    
    Step 6. Write a function to access the plugin
    
       In this case the function was created in:
    
          source\lib\catalina\getrealrand.c
    
       where the following code was added to locate the plugin in the 
       registry and (if found) read a new random number from the 
       appropriate registry entry:
    
          #include <prop.h>
          #include <plugin.h>
    
          int getrealrand() {
             static int cog = -1;
             static request_t *request_block = NULL;
             static int last_random = 0;
             int new_random = 0;
    
             if (cog == -1) {
                cog = _locate_plugin(LMM_RND);
                if (cog >= 0) {
                   request_block = REQUEST_BLOCK(cog);
                }
             }
             if (request_block) {
                // RANDOM plugin loaded - wait for a new random
                while ((new_random == 0) || (new_random == last_random)) {
                  new_random = request_block->response;
                }
                last_random = new_random;
             }
             else {
                // RANDOM not loaded - fall back to getrand()
                new_random = getrand();
                last_random = new_random;
             }
             return new_random;
          }
    
    Step 7. Modify the relevant Makefile to build the library function
    
       In this case the relevant Makefile is:
    
          source\lib\catalina\Makefile
    
       where the following line was added:
    
          getrealrand.s \
    
    Step 8. Rebuild the C library
    
       In the directory:
    
          source\catalina\lib
    
       execute the following command:
    
          build_all
    

    Ross.

  • RossHRossH Posts: 5,353
    edited 2024-04-27 03:55

    Deleting this post as it has been superseded by the Catalina 7.3.1 patch release.

    Ross.

  • RossHRossH Posts: 5,353

    Catalina 7.3.1 has been released here.

    This is a patch release that must be installed over an existing Catalina 7.3 installation.

    Here is the relevant extract from the README.TXT:

    RELEASE 7.3.1
    
    New Functionality
    -----------------
    
    1. None.
    
    Other Changes.
    --------------
    
    1. When the alloca() function was added (release 7.0) it increased the stack
       requirements for all programs very slightly, but the stack sizes allocated
       for Factories in the Multi-Processing version of Lua was not updated. This
       led to various issues but the most obvious was that Lua programs that tried
       to use the sbrk function to defragment the C heap would not run correctly. 
       Affected the Propeller 2 only.
    
  • evanhevanh Posts: 15,258
    edited 2024-04-27 06:12

    It would be quite feasible to make the random routine into a library only call without the need for another cog. Obviously such an implementation will consume processing time and use the counterA+vid hardware of the cog it runs on, but I'd suspect those will generally not be in use on the primary C cog anyway.

  • RossHRossH Posts: 5,353
    edited 2024-04-27 22:16

    Something I have meant to do on every release, and keep forgetting ...

    The two Lua versions of Startrek (star.lua and star-tos.lua) both contain code that deliberately slows down the program output. The intention is to simulate how the game would have appeared on an old slow teletype terminal. Amusing, but a nuisance on a screen. To disable this, use the vi text editor and find the line that says:

    DisableTeleprint = false

    and change it to ...

    DisableTeleprint = true

    Now, go save the Federation! :)

  • RossHRossH Posts: 5,353

    @evanh said:
    It would be quite feasible to make the random routine into a library only call without the need for another cog. Obviously such an implementation will consume processing time and use the counterA+vid hardware of the cog it runs on, but I'd suspect those will generally not be in use on the primary C cog anyway.

    Yes. Also, it would be good enough for most purposes to just generate one truly random number on startup, to use as a seed for the pseudo random number generator. Then re-use the cog.

    Either or both of these might make it into a release at some point. But at least Catalina now has an option for a real random number generator on the Propeller 1, which was something that was missing.

Sign In or Register to comment.