rand_test.c 7.53 KB
/* checking random number generator:
 high freq clock is sysclk, low freq clock is output of video pll
 reg [3:0] mi_rand is the flip flops 
 result xored and shifted into reg [1:0] mi_rbit
 check these in coverage. result read from MI_RANDOM_REG bit 0.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/times.h>
#include <PR/ultratypes.h>
#include "PR/bcp.h"
#include "simipc.h"
#include "iomap.h"
#include "bcp_util.h"
#include "simipc.h"
#include "iotest.h"
#include "sim.h"
#include "trace.h"


#define PASS 0
#define FAIL -1
#define UNIQUE_SEQ_LEN 30
#define TEST_CMD_FILE "random.tst"

/***********************************************************************
 * Extern definitions
 */
extern	TstCmd	TstCmdTbl[];
extern	void	IoTestAll(void);
int		IpcFd = -1;
char		*CmdFile = TEST_CMD_FILE;
int             NumberStallCycles = 0;


#define VI_VCTRL_REG 0x04300030

#define NMI_EXCEPTION (0x20)


/*
 * How many sim cycles to wait for NMI and interrupt
 */
#define NMI_WAIT 10


int IsRepeating(u8 *sequence, int t, int count);
u8  getSysClkValue(long long sysclk_period, long long location);
int getUniqueSequence(long long sysclk_period, long long vclk_period, unsigned int desiredlength, u8 *sequence);
int matchOccurs(u8 *sw, int phase, u8 *hw, int swlength, int hwlength, int sampling_rate);
void initpll();
int mi_random_test();

int secure_mode_entry_app()
{
    int retry = NMI_WAIT;

    /*
     * Get into secure mode using API
     */
    IO_READ(MI_SEC_MODE_REG);

    /*
     * Wait some number of cycles for the NMI
     */
    while (--retry) {
        BCP_STALL(1);
        if (CHECK_INTERRUPT == NMI_EXCEPTION) {
            break;
        }
    }
    if (retry == 0) {
        fprintf(LogFp, "App entry: NMI not generated correctly 0x%x\n", CHECK_INTERRUPT);
        return -1;
    }

    IO_READ(BOOT_RAM_LO_START);

    return 0;
}

int secure_mode_exit()
{
    int x;
    int retry = NMI_WAIT;

    x = IO_READ(MI_SEC_MODE_REG);

    // Preserve bits for trap enables and IRAM access, zero the rest
    x = x & (MI_SEC_MODE_MD_TRAP_EN | MI_SEC_MODE_BUT_TRAP_EN | MI_SEC_MODE_IRAM_ACCESS | MI_SEC_MODE_BROM_LO | MI_SEC_MODE_MD_TRAP_EN | MI_SEC_MODE_BUT_TRAP_EN);
    IO_WRITE(MI_SEC_MODE_REG, x);

    while (--retry) {
        BCP_STALL(1);
        if ((CHECK_INTERRUPT & NMI_EXCEPTION) == 0) {
            break;
        }
    }
    if (retry == 0) {
        fprintf(LogFp, "Secure mode exit: NMI not cleared\n");
        return -1;
    }

    return 0;
}

FILE *LogFp;
unsigned long  Dflags;
int main(){
    
    IpcInit(NULL);
    FindServer();

    LogFp = stderr;

    do_keep_alive_socket(1);

    /* 
     * MI functional tests 
     */

    /*
     * Run this one first, since it depends on contents of 
     * V2.
     * Check that a recall happened on reset. May have to do
     * a pin reset
     */
    secure_mode_entry_app();

    if(mi_random_test() == 0){
        printf("PASS random number test\n");
    }
    else{
        printf("FAIL random number test\n");
    }
    secure_mode_exit();
    do_keep_alive_socket(0);
    return 0;
}
int mi_random_test(){

  u32 random;
  int i;
  u8 hw[1024];
  u8 sw[1024*16];
  int sampling_rate;
  unsigned int vclk_period, sysclk_period;
  unsigned int hwlength, swlength;
  unsigned int desiredlength;
  long long bcptime_old;
  
  int ret=0;
  long long bcptime_new, elapsed;
  IO_READ(MI_SEC_MODE_REG);
  IO_READ(BOOT_RAM_LO_START);
  

  
  /*bypass pll*/
  
  
  IO_WRITE(VI_VCTRL_REG,  0x03000000);
  
    
  bcp_sysclk_period(&sysclk_period);
  sysclk_period = sysclk_period/1000;
  bcp_vclk_period(&vclk_period);
  vclk_period = vclk_period/1000;
  fprintf(stderr," period in ns = %d\n",(int) sysclk_period); 
  fprintf(stderr," period in ns = %d\n",(int) vclk_period); 
  
  //sysclk_period = 16;
  //vclk_period = 18;
  hwlength =64;

  for(i =0; i< hwlength; i++){
    bcp_time(&bcptime_old);
    bcp_stall(8); /* takes sysclk_period * 8 ns */
    random = IO_READ(MI_RANDOM_REG); /* takes 8 clocks */
    bcp_time(&bcptime_new);
    elapsed = bcptime_new - bcptime_old;
    //printf("random = %08x elapsed = %lld period= %d\n", random, elapsed, (int)sysclk_period);
    /* store a bit in a byte!*/
    if (random == 0x00000001){
      hw[i] = 0x01;
    }
    else{
      hw[i] = 0x00;
    }
  }

  sampling_rate = 16;
  /* 8 clocks from stall and 8 from the IO_READ*/
  /*sampling_rate = 8;*/ /* 8 clocks from IO_READ*/
  desiredlength = sampling_rate * hwlength*2;
  swlength = getUniqueSequence(sysclk_period, vclk_period, desiredlength,sw);
  for(i=0;i<swlength; i++){
    //printf("sw[%d]=%d\n",i, sw[i]);
  }
    
  /* see if match occurs for any phase */
  for(i=0; i< UNIQUE_SEQ_LEN; i++){
    if(matchOccurs(sw, i, hw, swlength, hwlength,sampling_rate) ==1){
      fprintf(stderr,"TEST PASSED, phase =%d, sampled at %d\n", i, sampling_rate);
      break;
    }
  }
  if (i==UNIQUE_SEQ_LEN){
    fprintf(stderr,"TEST FAILED\n");
    ret = 1;
  }

  return ret;
}



u8  getSysClkValue(long long sysclk_period, long long location){
  u8 result=0;
  long long location1, location2;
  location1 = location - (location % sysclk_period); 
  /* previous rising edge*/
  location2 = location1 + sysclk_period/2; /* middle of period*/
  if (location < location2){
    result = 0x01;
    
  }
  else{
    result = 0x00;
    
  }
  return result;
}

int getUniqueSequence(long long sysclk_period, long long vclk_period, unsigned int desiredlength, u8 *sequence){
  /* collect whole unsampled sequence into the vector sequence*/
  /* assume positive edge happens on multiples of period in ns */
  u8 mi_rand[4];
  u8 mi_rbit[2];
  u8 temp;
  int count=0;
  int t=0;
  mi_rbit[0] =0x00;
  mi_rbit[1] =0x00;
  mi_rand[0]=mi_rand[1]=mi_rand[2]=mi_rand[3]=0x00;
  temp = 0x00;

  while(count < desiredlength){
    
      if(t % vclk_period == 0){
	mi_rand[3] = mi_rand[2];
	mi_rand[2] = mi_rand[1];
	mi_rand[1] = mi_rand[0];
	mi_rand[0] = getSysClkValue(sysclk_period, t);
	printf("t = %d ff =%02x %02x %02x %02x\n", t, mi_rand[3], mi_rand[2], mi_rand[1], mi_rand[0]);
      }

      if((t+10) % sysclk_period ==0){
	
	mi_rbit[1] = mi_rbit[0];
	mi_rbit[0] = mi_rand[0] ^ mi_rand[1] ^ mi_rand[2] ^mi_rand[3];
	
	if((count < 1024*2)&&(t !=0)){
	  sequence[count] = mi_rbit[0];
	  //printf("seq %d = %08x\n",count, sequence[count]);
	  count++;
	}
      }
      t++;
  }
  
  /*extract unique sequence */
  /*
  for(t=count/2; t>=2;t--){
    if(IsRepeating(sequence, t, count)==1){
      fprintf(stderr,"repeated after t= %d\n",t);
      break;
    }
  }
  */
  /*return entire sequence*/
  
  /* 0 to t-1 is unique alignment */
  /*return t;*/
  return count;
  
}

/* does the sequence repeat after t */
int IsRepeating(u8 *sequence, int t, int count){
  int i;
  int issame =1;
  for(i=0; i<t; i++){
    if(sequence[i] != sequence[i+t]){
      issame =0;
      break;
    }
  }
  if(issame ==1){
    return 1;
  }
  else {
    return 0;
  }
}
  
/* check match, for a certain phase, say 5, check numbers 5, 5 + s, 5 +2s etc
wrapping around the unique sequence. s is sampling rate */
int matchOccurs(u8 *sw, int phase, u8 *hw, int swlength, int hwlength, int sampling_rate){
  int i;
  int result =1;
  
  printf("phase = %d sw->\n",phase );
  for(i=0; i< swlength; i++){
    printf("%02x ", sw[i]);
  }
  printf("\n");
  printf("hw->\n");
  for(i=0; i< hwlength; i++){
    printf("%02x ", hw[i]);
  }
  printf("\n");
  
  for (i=0; i< hwlength; i++){
    if((phase + sampling_rate*i) >= swlength){
      break;
    }
    //if (hw[i] != sw[(phase + sampling_rate*i) % swlength]){
    if (hw[i] != sw[(phase + sampling_rate*i)]){
      result = 0;
      break;
    }
  }
  return result;
}