Kiwi Random Number Demo

A recent student project at Imperial College London coded a number of well-known pseudo random number generators for FPGA and examined their uniformity. The analysis is in terms of relative hit frequency of various predicate functions. The output stream from successive calls to the generator forms a time series and the predicates can be defined on individual entries in such a series or on various digrams and trigrams from spaced intervals.

Introduction

PAGE UNDER CONSTRUCTION AUGUST 2016

In this demo we highlight the 3 execution environments defined by Kiwi.

We need a slight variation in our C# top-level code to support changing between them: WS, RTLSIM, FPGA.

To enable the same RTL file to be synthesised for FPGA by vendor tools and simulated [RTLSIM] but to have slightly different behaviour (e.g. w.r.t. BIST self test) it is handy to define an external input to the Kiwi code that you tie low in the RTLSIM testbench but strap high in the FPGA substrate pad ring.

  [Kiwi.InputBitPort("FPGA")] static bool FPGA;

Source Code - Single Threaded

// Kiwi Scientfic Acceleration.
// Random Number Generator Statistical Survey Demo.
// (C) 2016, DJ Greaves, University of Cambridge Computer Laboratory.

using KiwiSystem;
using System;


public abstract class RandomGeneratorIF
{
  
  // Generic interface for random number generators of various designs.
  public virtual void Seed(int s)
  {
    
  }

  public virtual int Next()
  {
    return 100; // Not very random !
  }

}

public class ParkMillerGenerator : RandomGeneratorIF
{
  int seed;
  public override void Seed(int s)
  {
    seed = s;
  }
  
  // PRGEN Park and Miller CACM October 1988
  public override int Next()
  {
    const int a = 2147001325;
    const int b = 715136305;
    seed = a * seed + b;
    return seed;
  }
}


public class KiwiPaddedGenerator : RandomGeneratorIF
{
  KiwiSystem.Random dg = new KiwiSystem.Random();
  public override void Seed(int s)
  {
    dg.Reset(s);
  }
  
  public override int Next()
  {
    return dg.Next();
  }

}

public class Randu: RandomGeneratorIF
{
  int seed;
  public override void Seed(int s)
  {
    seed = s;
  }

  /* Randu : v = (65539 * v) mod (2^31)
               != v + (v<<1) + (v<<16) 
     It's good to add another one to avoid degenerate all-zero case.
  */ 
  
  public override int Next()
  {
	seed = seed + (seed << 1) + (seed << 16) + 1;
	return seed;
  }

}

public class KiwiRandomTester
{

  RandomGeneratorIF dg;  
 

  public KiwiRandomTester(int gen_no_) // constructor
  {
    dg = new KiwiPaddedGenerator();  // Instantiate one of the units, depending on gen_no in future.
  }


  public void RunOnce()
  {
    int [] stats = new int[32];
    Kiwi.Pause();
    Console.WriteLine();
    int trials = 10000;
    int midpt = trials/2;
    for (int kk=0; kk<trials; kk++)
      {
	int v = dg.Next();
	for (int q =0; q<32; q++)  // Tally bits that are set.
	  {
	    if (((v >> q) & 1) == 1) stats[q] += 1;	    
	  }

      }

    KiwiStringIO.Write("Test D "); 
    KiwiStringIO.NewLine();

    for (int rr=0; rr<32; rr++)
      {
	KiwiStringIO.Write(" res "); 
	KiwiStringIO.Write(rr);
	KiwiStringIO.Write(" tally="); 
	KiwiStringIO.Write(stats[rr]);
	KiwiStringIO.Write(" dev= "); 
	KiwiStringIO.Write(Math.Abs(stats[rr]-midpt));
	KiwiStringIO.NewLine();
      }
    KiwiStringIO.WriteLine("Kiwi Random Demo Done"); 
  }


}


public class main
{

  [Kiwi.OutputBitPort("done")] static bool done = false;

  // Xilinx GPIO push buttons on ML605 and VC707 cards.
  [Kiwi.InputBitPort("GPIO_SW_N")] static bool GPIO_SW_N;
  [Kiwi.InputBitPort("GPIO_SW_W")] static bool GPIO_SW_W;
  [Kiwi.InputBitPort("GPIO_SW_S")] static bool GPIO_SW_S;
  [Kiwi.InputBitPort("GPIO_SW_E")] static bool GPIO_SW_E;
  [Kiwi.InputBitPort("GPIO_SW_C")] static bool GPIO_SW_C;

  [Kiwi.InputBitPort("FPGA")] static bool FPGA;


  static KiwiRandomTester kl;

  static void mainWork()
  {
    // On FPGA can drive via GPIO push switches.
    // disable for diosim    if (GPIO_SW_N)  
      {
	done = false;
	kl.RunOnce();
	done = true;
      }
  }

  static void open()
  {
    kl = new KiwiRandomTester(0);
  }




  [Kiwi.HardwareEntryPoint()]   // For the RTLSIM and FPGA execution environments.
  public static void HwProcess()
  {
    Console.WriteLine("KiwiRandomTester Demo Start");
    Kiwi.KppMark("START");
    open();
    Kiwi.KppMark("KiwiRandomTester Constructed");
    
      {
	mainWork();
	Kiwi.Pause();
      }
    Console.WriteLine("KiwiRandomTester Demo Finished");
    Kiwi.Pause();
    done = true;
    Kiwi.KppMark("END");
  }


  // For [WD] execution, Software entry point.
  public static int Main()
  {
    open();
    for (int run=0; run<10; run++)
      {
	GPIO_SW_C = false;
	GPIO_SW_N = true;
	mainWork();
	GPIO_SW_N = false;
	// We simulate some pressing of the buttons here.
	for (int it=0; it<1; it++)
	  {	    
	    Console.WriteLine("RunOnce generation: run={0}, it={1}", run, it);
	    mainWork();
	  }
      }
    return 0;
  }
}

Compilation with Mono C# and KiwiC

mcs KiwiRandomTester.cs /unsafe /r:/home/djg11/d320/hprls/kiwipro/kiwic/distro/support/Kiwi.dll  /r:/home/djg11/d320/hprls/kiwipro/kiwic/distro/support/KiwiRandom.dll /r:/home/djg11/d320/hprls/kiwipro/kiwic/distro/support/KiwiStringIO.dll
KiwiRandomTester.cs(138,44): warning CS0414: The private field `main.done' is assigned but its value is never used
KiwiRandomTester.cs(141,48): warning CS0414: The private field `main.GPIO_SW_N' is assigned but its value is never used
KiwiRandomTester.cs(142,48): warning CS0169: The private field `main.GPIO_SW_W' is never used
KiwiRandomTester.cs(143,48): warning CS0169: The private field `main.GPIO_SW_S' is never used
KiwiRandomTester.cs(144,48): warning CS0169: The private field `main.GPIO_SW_E' is never used
KiwiRandomTester.cs(145,48): warning CS0414: The private field `main.GPIO_SW_C' is assigned but its value is never used
KiwiRandomTester.cs(147,43): warning CS0169: The private field `main.FPGA' is never used
Compilation succeeded - 7 warning(s)

Typical Outputs

WD Execution Environment

For Workstation Devlopment we can run the binary on mono or inside the HPR L/S simulator.

MONO_PATH=/home/djg11/d320/hprls/kiwipro/kiwic/distro/support mono KiwiRandomTester.exe
RunOnce generation: run=3, it=0
 res 0 tally=4958 dev= 42
 res 1 tally=4997 dev= 3
 res 2 tally=4915 dev= 85
 res 3 tally=5102 dev= 102
 res 4 tally=5036 dev= 36
 res 5 tally=4934 dev= 66
 res 6 tally=4950 dev= 50
 res 7 tally=5067 dev= 67
 res 8 tally=4980 dev= 20
 res 9 tally=4979 dev= 21
 res 10 tally=5078 dev= 78
 res 11 tally=5040 dev= 40
 res 12 tally=4975 dev= 25
 res 13 tally=4912 dev= 88
 res 14 tally=4934 dev= 66
 res 15 tally=5021 dev= 21
 res 16 tally=5029 dev= 29
 res 17 tally=5024 dev= 24
 res 18 tally=4985 dev= 15
 res 19 tally=4974 dev= 26
 res 20 tally=4990 dev= 10
 res 21 tally=5013 dev= 13
 res 22 tally=5076 dev= 76
 res 23 tally=4993 dev= 7
 res 24 tally=5030 dev= 30
 res 25 tally=4969 dev= 31
 res 26 tally=5001 dev= 1
 res 27 tally=5016 dev= 16
 res 28 tally=4999 dev= 1
 res 29 tally=5041 dev= 41
 res 30 tally=4998 dev= 2
 res 31 tally=4928 dev= 72
...
Kiwi Random Demo Done

This provides profile output for performance prediction ....

RTL SIM Execution Environment

KiwiC compile:

kiwic   -vnl=KiwiRandomTester.v KiwiRandomTester.exe -vnl-resets=synchronous -res2-loadstore-port-count=0 \
        -repack-to-roms=enable -vnl-roundtrip=disable -bevelab-default-pause-mode=bblock -bevelab-soft-pause-threshold=1 \
        -vnl-rootmodname=DUT  /home/djg11/d320/hprls/kiwipro/kiwic/distro/support/KiwiRandom.dll \
        /r:/home/djg11/d320/hprls/kiwipro/kiwic/distro/support/KiwiStringIO.dll 

Note that this design does not use Console.WriteLine for its output. This would have given ASCII output for WD and RTLSIM. The RTLSIM output would use Verilog's $display PLI call.

Instead, we compiled with KiwiStringIO that causes the FPGA to convert from binary to ASCII and write the characters to a UART. This then works on the FPGA execution environment too.

Owing to the very long runtimes needed for RTLSIM we used Verilator.

mkdir -p verilated
verilator -cc -Wno-fatal -Mdir verilated --top-module VERISYS KiwiRandomTester.v verisys.v /home/djg11/d320/hprls/hpr/cvgates.v
g++ -o verilated_run -O2 -g -Iverilated -I/usr/share/verilator/include sim_main.cpp verilated/VVERISYS.cpp /usr/share/verilator/include/verilated.cpp verilated/VVERISYS__Syms.cpp
ulimit -t 19 ; ./verilated_run
KiwiRandomTester Demo Start

 res 0 tally=4953 dev= 47
 res 1 tally=5001 dev= 1
 res 2 tally=5066 dev= 66
 res 3 tally=5020 dev= 20
 res 4 tally=5012 dev= 12
 res 5 tally=4970 dev= 30
 res 6 tally=4952 dev= 48
 res 7 tally=5015 dev= 15
 res 8 tally=5090 dev= 90
 res 9 tally=5021 dev= 21
 res 10 tally=4993 dev= 7
 res 11 tally=4936 dev= 64
 res 12 tally=4953 dev= 47
 res 13 tally=4983 dev= 17
 res 14 tally=5000 dev= 0
 res 15 tally=5057 dev= 57
 res 16 tally=5048 dev= 48
 res 17 tally=4986 dev= 14
 res 18 tally=4969 dev= 31
 res 19 tally=4977 dev= 23
 res 20 tally=5011 dev= 11
 res 21 tally=4984 dev= 16
 res 22 tally=5085 dev= 85
 res 23 tally=4958 dev= 42
 res 24 tally=4983 dev= 17
 res 25 tally=5075 dev= 75
 res 26 tally=5042 dev= 42
 res 27 tally=4901 dev= 99
 res 28 tally=5032 dev= 32
 res 29 tally=4980 dev= 20
 res 30 tally=5009 dev= 9
 res 31 tally=4956 dev= 44
Random Done - PRGEN Park and Miller CACM October 1988
Exit on done asserted.
- verisys.v:35: Verilog $finish
KiwiRandomTester Demo Finished
Finished sim_main.cpp

FPGA Execution Environment

We use a tcl script for the Zynq 7020 on the Zedboard ...

Performance and Conclusions

We need to explore the performance of this design. So far we just simply coded it up and ran it as a demo.

We'll look at how accurate the perfomance predictor is ...


UP