aboutsummaryrefslogblamecommitdiff
path: root/projects/board-test/fmc-test.c
blob: 98e950f9da35c722cbf80abfe38a5ea35fb1f0cf (plain) (tree)
1
2
3
4



                                                                                



























                                                                     



























































                                                                                
                           



























                                                                                                   
                                         
                                   
                                         







                                                           
                  




























































                                                                                









                                                              




















                                                                                



                                                                       

































                                                                      










                                                              















                                                                                
//------------------------------------------------------------------------------
// main.c
//------------------------------------------------------------------------------

/*
 This requires a special bitstream with a special test register.
 See core/platform/novena/fmc/rtl/novena_fmc_top.v, sections marked
 `ifdef test:
   //----------------------------------------------------------------
   // Dummy Register
   //
   // General-purpose register to test FMC interface using STM32
   // demo program instead of core selector logic.
   //
   // This register is a bit tricky, but it allows testing of both
   // data and address buses. Reading from FPGA will always return
   // value, which is currently stored in the test register, 
   // regardless of read transaction address. Writing to FPGA has
   // two variants: a) writing to address 0 will store output data
   // data value in the test register, b) writing to any non-zero
   // address will store _address_ of write transaction in the test
   // register.
   //
   // To test data bus, write some different patterns to address 0,
   // then readback from any address and compare.
   //
   // To test address bus, write anything to some different non-zero
   // addresses, then readback from any address and compare returned
   // value with previously written address.
   //
   //----------------------------------------------------------------
 */

//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#include "stm32f4xx_hal.h"
#include "stm-init.h"
#include "stm-led.h"
#include "stm-fmc.h"
#include "stm-uart.h"

//------------------------------------------------------------------------------
// Defines
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
// Macros
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
// Variables
//------------------------------------------------------------------------------
RNG_HandleTypeDef rng_inst;

// FT: "I changed some interesting-to-look-at-in-the-debugger values to be
// volatile, so that my compiler wouldn't optimize/obscure them."

volatile uint32_t data_diff = 0;
volatile uint32_t addr_diff = 0;


//------------------------------------------------------------------------------
// Prototypes
//------------------------------------------------------------------------------
/* XXX move this to stm-rng.[ch] */
static void MX_RNG_Init(void);

int test_fpga_data_bus(void);
int test_fpga_address_bus(void);


//------------------------------------------------------------------------------
// Defines
//------------------------------------------------------------------------------
#define TEST_NUM_ROUNDS		100000


//------------------------------------------------------------------------------
int main(void)
//------------------------------------------------------------------------------
{
  int i;
  
  stm_init();

  uart_send_string("Keep calm for Novena boot...\r\n");

  // Blink blue LED for six seconds to not upset the Novena at boot.
  led_on(LED_BLUE);
  for (i = 0; i < 4; i++) {
    HAL_Delay(500);
    led_toggle(LED_BLUE);
  }

  // initialize rng
  MX_RNG_Init();

  // prepare fmc interface
  fmc_init();

  // turn on green led, turn off other leds
  led_on(LED_GREEN);
  led_off(LED_YELLOW);
  led_off(LED_RED);
  led_off(LED_BLUE);

  // vars
  volatile int data_test_ok = 0, addr_test_ok = 0, successful_runs = 0, failed_runs = 0, sleep = 0;

  // main loop (test, until an error is detected)
  while (1)
    {
      // test data bus
      data_test_ok = test_fpga_data_bus();
      // test address bus
      addr_test_ok = test_fpga_address_bus();

      uart_send_string("Data: ");
      uart_send_integer(data_test_ok, 6);
      uart_send_string(", addr: ");
      uart_send_integer(addr_test_ok, 6);
      uart_send_string("\r\n");

      if (data_test_ok == TEST_NUM_ROUNDS &&
	  addr_test_ok == TEST_NUM_ROUNDS) {
	// toggle yellow led to indicate, that we are alive
	led_toggle(LED_YELLOW);

	successful_runs++;
	sleep = 0;
      } else {
	led_on(LED_RED);
	failed_runs++;
	sleep = 2000;
      }

      uart_send_string("Success ");
      uart_send_integer(successful_runs, 0);
      uart_send_string(", fail ");
      uart_send_integer(failed_runs, 0);
      uart_send_string("\r\n\r\n");

      HAL_Delay(sleep);
    }

  // should never reach this line
}


//------------------------------------------------------------------------------
int test_fpga_data_bus(void)
//------------------------------------------------------------------------------
{
  int c, ok;
  uint32_t rnd, buf;
  HAL_StatusTypeDef hal_result;

  // run some rounds of data bus test
  for (c=0; c<TEST_NUM_ROUNDS; c++)
    {
      data_diff = 0;
      // try to generate "random" number
      hal_result = HAL_RNG_GenerateRandomNumber(&rng_inst, &rnd);
      if (hal_result != HAL_OK) break;

      // write value to fpga at address 0
      ok = fmc_write_32(0, &rnd);
      if (ok != 0) break;

      // read value from fpga
      ok = fmc_read_32(0, &buf);
      if (ok != 0) break;

      // compare (abort testing in case of error)
      if (buf != rnd)
	{
	  data_diff = buf;
	  data_diff ^= rnd;

	  uart_send_string("Data bus fail: expected ");
	  uart_send_binary(rnd, 32);
	  uart_send_string(", got ");
	  uart_send_binary(buf, 32);
	  uart_send_string(", diff ");
	  uart_send_binary(data_diff, 32);
	  uart_send_string("\r\n");

	  break;
	}
    }

  data_diff = buf;
  data_diff ^= rnd;

  uart_send_string("Sample of data bus test data: expected ");
  uart_send_binary(rnd, 32);
  uart_send_string(", got ");
  uart_send_binary(buf, 32);
  uart_send_string(", diff ");
  uart_send_binary(data_diff, 32);
  uart_send_string("\r\n");
  // return number of successful tests
  return c;
}


//------------------------------------------------------------------------------
int test_fpga_address_bus(void)
//------------------------------------------------------------------------------
{
  int c, ok;
  uint32_t rnd, buf;
  HAL_StatusTypeDef hal_result;

  // run some rounds of address bus test
  for (c=0; c<TEST_NUM_ROUNDS; c++)
    {
      addr_diff = 0;
      // try to generate "random" number
      hal_result = HAL_RNG_GenerateRandomNumber(&rng_inst, &rnd);
      if (hal_result != HAL_OK) break;

      // there are 26 physicaly connected address lines on the alpha,
      // but "only" 24 usable for now (the top two ones are used by FMC
      // to choose bank, and we only have one bank set up currently)
      rnd &= 0x3fffffc;

      // don't test zero addresses (fpga will store data, not address)
      if (rnd == 0) continue;

      // write dummy value to fpga at some non-zero address
      ok = fmc_write_32(rnd, &buf);
      if (ok != 0) break;

      // read value from fpga
      ok = fmc_read_32(0, &buf);
      if (ok != 0) break;

      // fpga receives address of 32-bit word, while we need
      // byte address here to compare
      buf <<= 2;

      // compare (abort testing in case of error)
      if (buf != rnd)
	{
	  addr_diff = buf;
	  addr_diff ^= rnd;

	  uart_send_string("Addr bus fail: expected ");
	  uart_send_binary(rnd, 32);
	  uart_send_string(", got ");
	  uart_send_binary(buf, 32);
	  uart_send_string(", diff ");
	  uart_send_binary(addr_diff, 32);
	  uart_send_string("\r\n");

	  break;
	}
    }

  addr_diff = buf;
  addr_diff ^= rnd;

  uart_send_string("Sample of addr bus test data: expected ");
  uart_send_binary(rnd, 32);
  uart_send_string(", got ");
  uart_send_binary(buf, 32);
  uart_send_string(", diff ");
  uart_send_binary(addr_diff, 32);
  uart_send_string("\r\n");

  return c;
}


//------------------------------------------------------------------------------
static void MX_RNG_Init(void)
//------------------------------------------------------------------------------
{
  rng_inst.Instance = RNG;
  HAL_RNG_Init(&rng_inst);
}


//------------------------------------------------------------------------------
// EOF
//------------------------------------------------------------------------------
n">HAL_OK; } hal_error_t hal_io_read(const hal_core_t *core, hal_addr_t offset, uint8_t *buf, size_t len) { hal_error_t err; if (core == NULL) return HAL_ERROR_CORE_NOT_FOUND; offset += hal_core_base(core); for (; len > 0; offset++, buf += 4, len -= 4) if ((err = hal_io_send_read_cmd(offset)) != HAL_OK || (err = hal_io_get_read_resp(offset, buf)) != HAL_OK) return err; return HAL_OK; } hal_error_t hal_io_init(const hal_core_t *core) { uint8_t buf[4] = { 0, 0, 0, CTRL_INIT }; return hal_io_write(core, ADDR_CTRL, buf, 4); } hal_error_t hal_io_next(const hal_core_t *core) { uint8_t buf[4] = { 0, 0, 0, CTRL_NEXT }; return hal_io_write(core, ADDR_CTRL, buf, 4); } hal_error_t hal_io_wait(const hal_core_t *core, uint8_t status, int *count) { hal_error_t err; uint8_t buf[4]; int i; for (i = 1; ; ++i) { if (count && (*count > 0) && (i >= *count)) return HAL_ERROR_IO_TIMEOUT; if ((err = hal_io_read(core, ADDR_STATUS, buf, 4)) != HAL_OK) return err; if (buf[3] & status) { if (count) *count = i; return HAL_OK; } } } hal_error_t hal_io_wait_ready(const hal_core_t *core) { int limit = 10; return hal_io_wait(core, STATUS_READY, &limit); } hal_error_t hal_io_wait_valid(const hal_core_t *core) { int limit = 10; return hal_io_wait(core, STATUS_VALID, &limit); } /* * Local variables: * indent-tabs-mode: nil * End: */