• [笔记].怎样使用Nios II中的Memory Test模板来测试RAM和Flash


    本文简单描述如何使用Memory Test模板来测试RAM和Flash,此处以SDRAM和EPCS为例。

    使用环境:Altera Quartus 9.1 SP1 + Nios II  9.1 Software Build Tools for Eclipse SP1

    步骤1 在SOPC Builder中配置RAM和FLash

    图1 例化epcs控制器和sdram控制器

    图1 例化epcs控制器和sdram控制器

    注意观察epcs控制器和sdram控制器的起始和终止地址。此处epcs controller,例化为epcs,起始地址是0x01002090,终止地址是0x01002097;sdram controller,与epcs类似。当然也可查看之后生成的system.h。

    步骤2 使用Nios II中的Memory Test模板来测试

    1. 使用Memory Test模板创建软件工程

    图2 创建软件工程

    图2 创建软件工程

    2. 编译程序及检查相关设置

    编程成功后,打开system.h,查看与存储器相关的映射内容。

    #define ALT_MODULE_CLASS_epcs altera_avalon_epcs_flash_controller
    #define EPCS_BASE 0x1001800
    #define EPCS_IRQ 1
    #define EPCS_IRQ_INTERRUPT_CONTROLLER_ID 0
    #define EPCS_NAME "/dev/epcs"
    #define EPCS_REGISTER_OFFSET 512
    #define EPCS_SPAN 2048
    #define EPCS_TYPE "altera_avalon_epcs_flash_controller"

    代码1 EPCS相关的映射

    #define ALT_MODULE_CLASS_sdram altera_avalon_new_sdram_controller
    #define SDRAM_BASE 0x800000
    #define SDRAM_CAS_LATENCY 3
    #define SDRAM_CONTENTS_INFO ""
    #define SDRAM_INIT_NOP_DELAY 0.0
    #define SDRAM_INIT_REFRESH_COMMANDS 2
    #define SDRAM_IRQ -1
    #define SDRAM_IRQ_INTERRUPT_CONTROLLER_ID -1
    #define SDRAM_IS_INITIALIZED 1
    #define SDRAM_NAME "/dev/sdram"
    #define SDRAM_POWERUP_DELAY 100.0
    #define SDRAM_REFRESH_PERIOD 15.625
    #define SDRAM_REGISTER_DATA_IN 1
    #define SDRAM_SDRAM_ADDR_WIDTH 22
    #define SDRAM_SDRAM_BANK_WIDTH 2
    #define SDRAM_SDRAM_COL_WIDTH 8
    #define SDRAM_SDRAM_DATA_WIDTH 16
    #define SDRAM_SDRAM_NUM_BANKS 4
    #define SDRAM_SDRAM_NUM_CHIPSELECTS 1
    #define SDRAM_SDRAM_ROW_WIDTH 12
    #define SDRAM_SHARED_DATA 0
    #define SDRAM_SIM_MODEL_BASE 1
    #define SDRAM_SPAN 8388608
    #define SDRAM_STARVATION_INDICATOR 0
    #define SDRAM_TRISTATE_BRIDGE_SLAVE ""
    #define SDRAM_TYPE "altera_avalon_new_sdram_controller"
    #define SDRAM_T_AC 5.5
    #define SDRAM_T_MRD 3
    #define SDRAM_T_RCD 20.0
    #define SDRAM_T_RFC 70.0
    #define SDRAM_T_RP 20.0
    #define SDRAM_T_WR 14.0

    代码2 SDRAM相关的映射

    3. 运行程序

    运行程序后,在Nios II Console出现如下字样。

    图3 Nios II Console 显示结果 

    图3 Nios II Console 显示结果

    此命令行界面,提示输入a,测试RAM;输入b,测试Flash;输入q,退出。

    由于程序是在SDRAM中运行的,那么我们先测试EPCS。选择b,回车;接下来输入EPCS设备名,出现如下提示。

    图4 提示测试EPCS Flash

    图4 提示测试EPCS Flash

    命令行提示,EPCS设备已经打开;区域0有8个块等信息;并询问是否测试块3。此处选择y,开始测试。

    图5 测试EPCS

    图5 测试EPCS

    在EPCS的块3,写Flash和读Flash操作被测试完毕。然后自动关闭EPCS设备。

    回车后,选择a,接着测试SDRAM。

    图6 提示输入测试SDRAM的起始地址

    图6 提示输入测试SDRAM的起始地址

    提示输入其实地址。从system.h可以看到,SDRAM从0x800000开始寻址;在SOPC Builder中,更可以清楚地了解到SDRAM的起始和终止地址。然而,程序是在SDRAM中运行的;如果在此处,直接输入SDRAM寻址的起始地址,有可能引起冲突,以致于程序无法继续运行下去。那我们先测试其他地址开始的内容,此处以0x900000为例。

    图6 提示输入测试SDRAM的终止地址

    图6 提示输入测试SDRAM的终止地址

    输入大于测试SDRAM的起始地址的地址即可,此处以0xA00000为例。

    图7 输入测试SDRAM的终止地址,显示测试结果

    图7 输入测试SDRAM的终止地址,显示测试结果

    测试结果显示:从地址0x900000到地址0xA00000,数据总线测试通过;地址总线测试通过,字节和半字数据接入测试通过;单独位测试通过。

    附录1 mem_test.c

    此处,水平有限,不做解析,请读者自行分析。着重分析和学习其中的存储器操作方法。

    /**************************************************************************
     * Copyright (c) 2004 Altera Corporation, San Jose, California, USA.      *
     * All rights reserved. All use of this software and documentation is     *
     * subject to the License Agreement located at the end of this file below.*
     *************************************************************************/
    /**************************************************************************
     *
     * 
     * Description
     *************** 
     * This is a test program which tests RAM and flash memory. 
     *
     * 
     * Requirements
     ****************
     * This is a "Hosted" application. According to the ANSI C standard, hosted 
     * applications can rely on numerous system-services (including properly-
     * initialized device drivers and, in this case, STDOUT).  
     * 
     * When this program is compiled, code is added before main(), so that all 
     * devices are properly-initialized and all system-services (e.g. the 
     * library) are ready-to-use. In this hosted environment, all standard C 
     * programs will run.
     * 
     * A hosted application (like this example) does not need to concern itself 
     * with initializing devices. As long as it only calls C Standard Library 
     * functions, a hosted application can run "as if on a workstation."
     * 
     * An application runs in a hosted environment if it declares the function 
     * main(), which this application does.
     * 
     * This software example requires a STDOUT component such as a UART or 
     * JTAG UART, a CFI flash component, and 2 RAM components (one for running
     * the program, and one for testing)  Therefore it can run on the following
     * hardware examples:
     * 
     * Nios Development Board, Stratix II Edition:
     * -  Standard (DMA RAM test will not run)
     * -  Full Featured
     *
     * DSP Development Board, Stratix II Edition:
     * -  Standard (DMA RAM test will not run)
     * -  Full Featured
     *
     * Nios Development Board, Stratix Edition:
     * -  Standard (DMA RAM test will not run)
     * -  Full Featured
     * 
     * Nios Development Board, Stratix Professional Edition:
     * -  Standard (DMA RAM test will not run)
     * -  Full Featured
     * 
     * Nios Development Board, Cyclone Edition:
     * -  Standard (DMA RAM test will not run)
     * -  Full Featured
     *
     * Nios Development Board, Cyclone II Edition:
     * -  Standard (DMA RAM test will not run)
     * -  Full Featured
     *
     * Note: This example will not run on the Nios II Instruction Set Simulator
     * 
     * Peripherals Exercised by SW
     *******************************
     * The example's purpose is to test RAM and flash, as well as demonstrate the 
     * use of the DMA controller and flash API in NiosII.
     * 
     * The RAM test routine performs the following operations:
     * 1.) Tests the address and data lines for shorts and opens. 
     * 2.) Tests byte and half-word access.
     * 3.) Tests every bit in the memory to store both '1' and '0'. 
     * 4.) Tests DMA access to the memory.
     *
     * IMPORTANT: The RAM test is destructive to the contents of the RAM.  For this
     * reason, you MUST assure that none of the software sections are located in 
     * the RAM being tested.  This requires that code, data, and exception 
     * locations must all be in a memory seperate from the one being tested.
     * These locations can be adjusted in Nios II IDE and SOPC Builder.
     *
     *  
     * The flash tests demonstrate the use of the flash programming API.  After the
     * flash device specified is opened, the test routine searches for a block in 
     * the device that is already erased.  This prevents any overwriting of 
     * important data that may be programmed in flash.  When an erased block is 
     * found, the routine performs a test of the flash API calls on that block.
     *
     * The following API functions are then run to test the flash interface:
     * 
     * - alt_get_flash_info
     *    This function queries the flash device and collects various information 
     *    about it.  In the example, the results of this query are compared to what
     *    is expected, and an error is reported in the event of a mismatch.
     * - alt_write_flash
     *    This function writes a specified number of bytes to the flash device.  
     *    In the example, this function is called repeatedly in a loop to write a 
     *    lengthy amount of data.
     * - alt_read_flash
     *    This function reads a specified number of bytes of data from the flash 
     *    device.  In the example, alt_read_flash is used to read back and test 
     *    all of the writing routines.
     * - alt_erase_flash_block
     *    This function performs a block erase on the flash device. 
     * - alt_write_flash_block
     *    This function writes an erase block of data to the flash device.  
     * 
     * During the test, status and error information is passed to the user via 
     * printf's.
     * 
     * Software Files
     ******************
     * memtest.c - Main C file that contains all memory testing code in this 
     *             example.
     * 
     **************************************************************************/
    
    
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #include "sys/alt_dma.h"
    #include "system.h"
    #include "sys/alt_flash.h"
    #include "sys/alt_flash_dev.h"
    
    /* Mode parameters for Flash Test */
    #define TEST 1
    #define SHOWMAP 2
    #define CFI 3
    #define EPCS 4
    #define QUIT_WITHOUT_TESTING -1
    
    /* One nice define for going to menu entry functions. */
    #define MenuCase(letter,proc) case letter:proc; break;
    
    /* Global DMA "transaction finished" flag */
    #ifdef DMA_NAME  
    static volatile int rx_done = 0;
    #endif /* DMA_NAME */  
    
    /******************************************************************
    *  Function: MenuHeader
    *
    *  Purpose: Prints the menu header.
    *
    ******************************************************************/
    static void MenuHeader(void)
    {
      printf("\n\n");
      printf("             <---->   Nios II Memory Test.   <---->\n");
      printf("This software example tests the memory in your system to assure it\n");
      printf("is working properly.  This test is destructive to the contents of\n");
      printf("the memory it tests. Assure the memory being tested does not contain\n");
      printf("the executable or data sections of this code or the exception address\n");
      printf("of the system.\n");
    }
    
    /******************************************************************
    *  Function: MenuBegin
    *
    *  Purpose: Prints the top portion of the menu.
    *
    ******************************************************************/
    static void MenuBegin( char *title )
    {
      printf("\n\n");
      printf("----------------------------------\n");
      printf("%s\n",title);
      printf("----------------------------------\n");
    }
    
    /******************************************************************
    *  Function: MenuItem
    *
    *  Purpose: Prints selection items in the menu, enumerated by the 
    *           specified letter.
    *
    ******************************************************************/
    static void MenuItem( char letter, char *name )
    {
      printf("     %c:  %s\n" ,letter, name);
    }
    
    /******************************************************************
    *  Function: GetInputString
    *
    *  Purpose: Parses an input string for the character '\n'.  Then
    *           returns the string, minus any '\r' characters it 
    *           encounters.
    *
    ******************************************************************/
    void GetInputString( char* entry, int size, FILE * stream )
    {
      int i;
      int ch = 0;
      
      for(i = 0; (ch != '\n') && (i < size); )
      {
        if( (ch = getc(stream)) != '\r')
        {
          entry[i] = ch;
          i++;
        }
      }
    }
    
    /******************************************************************
    *  Function: MenuEnd
    *
    *  Purpose: Prints the end of the menu, then captures and returns
    *           the user's selection.
    *
    ******************************************************************/
    static int MenuEnd( char lowLetter, char highLetter )
    {
      static char entry[4];
      static char ch;
    
      printf("     q:  Exit\n");
      printf("----------------------------------\n");
      printf("\nSelect Choice (%c-%c): [Followed by ]",lowLetter,highLetter);
    
      GetInputString( entry, sizeof(entry), stdin );
      if(sscanf(entry, "%c\n", &ch))
      {
        if( ch >= 'A' && ch <= 'Z' )
          ch += 'a' - 'A';
        if( ch == 27 )
          ch = 'q';
      }
      return ch;
    }
    
    /******************************************************************
    *  Function: MemGetAddressRange
    *
    *  Purpose: Gathers a range of memory from the user.
    *
    ******************************************************************/
    static int MemGetAddressRange(int* base_address, int* end_address)
    {
    
      char line[12];
    
      while(1)
      {
        /* Get the base address */
        printf("Base address to start memory test: (i.e. 0x800000)\n");
        printf(">");
    
        GetInputString( line, sizeof(line), stdin );
       
        /* Check the format to make sure it was entered as hex */
        if(sscanf(line, "0x%X", base_address) != 1)
        {
          printf("%s\n", line);
          printf(" -ERROR: Invalid base address entered.  Address must be in the form '0x800000'\n\n");
          continue;
        }
        
        /* Get the end address */
        printf("End Address:\n");
        printf(">");
    
        GetInputString( line, sizeof(line), stdin );
        
        /* Check the format to make sure it was entered as hex */
        if(sscanf(line, "0x%X", end_address) != 1)
        {
          printf(" -ERROR: Invalid end address entered.  Address must be in the form '0x8FFFFF'\n\n");
          continue;
        }
        
        /* Make sure end address is greater than base address. */
        if (end_address <= base_address)
        {
          printf(" -ERROR: End address must be greater than the start address\n\n");
    
          continue;
        }
        break;
      }
    
      return(0);
    }
    
    /******************************************************************
    *  Function: MemTestDataBus
    *
    *  Purpose: Tests that the data bus is connected with no 
    *           stuck-at's, shorts, or open circuits.
    *
    ******************************************************************/
    static int MemTestDataBus(unsigned int address)
    {
      unsigned int pattern;
      unsigned int ret_code = 0x0;
    
      /* Perform a walking 1's test at the given address. */
      for (pattern = 1; pattern != 0; pattern <<= 1)
      {
        /* Write the test pattern. */
        IOWR_32DIRECT(address, 0, pattern);
    
        /* Read it back (immediately is okay for this test). */
        if (IORD_32DIRECT(address, 0) != pattern)
        {
          ret_code = pattern;
          break;
        }
      }
      return ret_code;
    }
    
    
    /******************************************************************
    *  Function: MemTestAddressBus
    *
    *  Purpose: Tests that the address bus is connected with no 
    *           stuck-at's, shorts, or open circuits.
    *
    ******************************************************************/
    static int MemTestAddressBus(unsigned int memory_base, unsigned int nBytes)
    {
      unsigned int address_mask = (nBytes - 1);
      unsigned int offset;
      unsigned int test_offset;
    
      unsigned int pattern     = 0xAAAAAAAA;
      unsigned int antipattern  = 0x55555555;
    
      unsigned int ret_code = 0x0;
    
      /* Write the default pattern at each of the power-of-two offsets. */
      for (offset = sizeof(unsigned int); (offset & address_mask) != 0; offset <<= 1)
      {
        IOWR_32DIRECT(memory_base, offset, pattern);
      }
    
      /* Check for address bits stuck high. */
      test_offset = 0;
      IOWR_32DIRECT(memory_base, test_offset, antipattern);
      for (offset = sizeof(unsigned int); (offset & address_mask) != 0; offset <<= 1)
      {
         if (IORD_32DIRECT(memory_base, offset) != pattern)
         {
            ret_code = (memory_base+offset);
            break;
         }
      }
    
      /* Check for address bits stuck low or shorted. */
      IOWR_32DIRECT(memory_base, test_offset, pattern);
      for (test_offset = sizeof(unsigned int); (test_offset & address_mask) != 0; test_offset <<= 1)
      {
        if (!ret_code)
        {
          IOWR_32DIRECT(memory_base, test_offset, antipattern);
          for (offset = sizeof(unsigned int); (offset & address_mask) != 0; offset <<= 1)
          {
            if ((IORD_32DIRECT(memory_base, offset) != pattern) && (offset != test_offset))
            {
              ret_code = (memory_base + test_offset);
              break;
            }
          }
          IOWR_32DIRECT(memory_base, test_offset, pattern);
        }
      }
    
      return ret_code;
    }
    
    
    /******************************************************************
    *  Function: MemTest8_16BitAccess
    *
    *  Purpose: Tests that the memory at the specified base address
    *           can be read and written in both byte and half-word 
    *           modes.
    *
    ******************************************************************/
    static int MemTest8_16BitAccess(unsigned int memory_base)
    {
      int ret_code = 0x0;
    
      /* Write 4 bytes */
      IOWR_8DIRECT(memory_base, 0, 0x0A);
      IOWR_8DIRECT(memory_base, 1, 0x05);
      IOWR_8DIRECT(memory_base, 2, 0xA0);
      IOWR_8DIRECT(memory_base, 3, 0x50);
    
      /* Read it back as one word */
      if(IORD_32DIRECT(memory_base, 0) != 0x50A0050A)
      {
        ret_code = memory_base;
      }
    
      /* Read it back as two half-words */
      if (!ret_code)
      {
        if ((IORD_16DIRECT(memory_base, 2) != 0x50A0) ||
            (IORD_16DIRECT(memory_base, 0) != 0x050A))
        {
          ret_code = memory_base;
        }
      }
    
      /* Read it back as 4 bytes */
      if (!ret_code)
      {
        if ((IORD_8DIRECT(memory_base, 3) != 0x50) ||
            (IORD_8DIRECT(memory_base, 2) != 0xA0) ||
            (IORD_8DIRECT(memory_base, 1) != 0x05) ||
            (IORD_8DIRECT(memory_base, 0) != 0x0A))
        {
        ret_code = memory_base;
        }
      }
    
      /* Write 2 half-words */
      if (!ret_code)
      {
        IOWR_16DIRECT(memory_base, 0, 0x50A0);
        IOWR_16DIRECT(memory_base, 2, 0x050A);
    
        /* Read it back as one word */
        if(IORD_32DIRECT(memory_base, 0) != 0x050A50A0)
        {
          ret_code = memory_base;
        }
      }
    
      /* Read it back as two half-words */
      if (!ret_code)
      {
        if ((IORD_16DIRECT(memory_base, 2) != 0x050A) ||
            (IORD_16DIRECT(memory_base, 0) != 0x50A0))
        {
          ret_code = memory_base;
        }
      }
    
      /* Read it back as 4 bytes */
      if (!ret_code)
      {
        if ((IORD_8DIRECT(memory_base, 3) != 0x05) ||
            (IORD_8DIRECT(memory_base, 2) != 0x0A) ||
            (IORD_8DIRECT(memory_base, 1) != 0x50) ||
            (IORD_8DIRECT(memory_base, 0) != 0xA0))
        {
          ret_code = memory_base;
        }
      }
    
      return(ret_code);
    }
    
    
    /******************************************************************
    *  Function: MemTestDevice
    *
    *  Purpose: Tests that every bit in the memory device within the 
    *           specified address range can store both a '1' and a '0'.
    *
    ******************************************************************/
    static int MemTestDevice(unsigned int memory_base, unsigned int nBytes)
    {
      unsigned int offset;
      unsigned int pattern;
      unsigned int antipattern;
      unsigned int ret_code = 0x0;
    
      /* Fill memory with a known pattern. */
      for (pattern = 1, offset = 0; offset < nBytes; pattern++, offset+=4)
      {
        IOWR_32DIRECT(memory_base, offset, pattern);
      }
    
      printf(" .");
    
      /* Check each location and invert it for the second pass. */
      for (pattern = 1, offset = 0; offset < nBytes; pattern++, offset+=4)
      {
        if (IORD_32DIRECT(memory_base, offset) != pattern)
        {
          ret_code = (memory_base + offset);
          break;
        }
        antipattern = ~pattern;
        IOWR_32DIRECT(memory_base, offset, antipattern);
      }
    
      printf(" .");
    
      /* Check each location for the inverted pattern and zero it. */
      for (pattern = 1, offset = 0; offset < nBytes; pattern++, offset+=4)
      {
        antipattern = ~pattern;
        if (IORD_32DIRECT(memory_base, offset) != antipattern)
        {
          ret_code = (memory_base + offset);
          break;
        }
        IOWR_32DIRECT(memory_base, offset, 0x0);
      }
      return ret_code;
    }
    
    /******************************************************************
    *  Function: dma_done
    *
    *  Purpose: Called when a DMA recieve transaction is complete.
    *           Increments rx_done to signal to the main program that
    *           the transaction is done.
    *
    ******************************************************************/
    #ifdef DMA_NAME  
    static void dma_done (void* handle, void* data)
    {
      rx_done++;
    }
    #endif /* DMA_NAME */  
    
    /******************************************************************
    *  Function: MemDMATest
    *
    *  Purpose: Tests every bit in the memory device within the 
    *  specified address range using DMA.  The DMA controller provides 
    *  a more rigourous test of the memory since it performs back-to-
    *  back memory accesses at full system speed.
    *
    ******************************************************************/
    #ifdef DMA_NAME  
    static int MemDMATest(unsigned int memory_base, unsigned int nBytes)
    {
      int rc;
      int ret_code = 0;
      int pattern, offset;
      alt_dma_txchan txchan;
      alt_dma_rxchan rxchan;
      void* data_written;
      void* data_read;
      
      /* Get a couple buffers for the test */
      data_written = (void*)alt_uncached_malloc(0x1000);
      data_read = (void*)alt_uncached_malloc(0x1000);
      
      
      /* Fill write buffer with known values */
      for (pattern = 1, offset = 0; offset < 0x1000; pattern++, offset+=4)
      {
        IOWR_32DIRECT((int)data_written, offset, pattern);
      }
    
      /* Create the transmit channel */
      if ((txchan = alt_dma_txchan_open("/dev/dma")) == NULL)
      {
        printf ("Failed to open transmit channel\n");
        exit (1);
      }
      
      /* Create the receive channel */
      if ((rxchan = alt_dma_rxchan_open("/dev/dma")) == NULL)
      {
        printf ("Failed to open receive channel\n");
        exit (1);
      }
      
      for(offset = memory_base; offset < (memory_base + nBytes); offset += 0x1000)
      {
        /* Use DMA to transfer from write buffer to memory under test */
        /* Post the transmit request */
        if ((rc = alt_dma_txchan_send (txchan, data_written, 0x1000, NULL, NULL)) < 0)
        {
          printf ("Failed to post transmit request, reason = %i\n", rc);
          exit (1);
        }
    
        /* Post the receive request */
        if ((rc = alt_dma_rxchan_prepare (rxchan, (void*)offset, 0x1000, dma_done, NULL)) < 0)
        {
          printf ("Failed to post read request, reason = %i\n", rc);
          exit (1);
        }
      
        /* Wait for transfer to complete */
        while (!rx_done);
        rx_done = 0;
        
        /* Clear the read buffer before we fill it */
        memset(data_read, 0, 0x1000);
        
        /* Use DMA to read data back into read buffer from memory under test */
        /* Post the transmit request */
        if ((rc = alt_dma_txchan_send (txchan, (void*)offset, 0x1000, NULL, NULL)) < 0)
        {
          printf ("Failed to post transmit request, reason = %i\n", rc);
          exit (1);
        }
    
        /* Post the receive request */
        if ((rc = alt_dma_rxchan_prepare (rxchan, data_read, 0x1000, dma_done, NULL)) < 0)
        {
          printf ("Failed to post read request, reason = %i\n", rc);
          exit (1);
        }
    
        /* Wait for transfer to complete */
        while (!rx_done);
        rx_done = 0;
        
        if (memcmp(data_written, data_read, 0x1000))
        {
          ret_code = offset;
          break;
        }
      }
      alt_uncached_free(data_written);
      alt_uncached_free(data_read);
      return ret_code;
    }
    #endif /* DMA_NAME */  
    
    
    /******************************************************************
    *  Function: TestRam
    *
    *  Purpose: Performs a full-test on the RAM specified.  The tests
    *           run are:
    *             - MemTestDataBus
    *             - MemTestAddressBus
    *             - MemTest8_16BitAccess
    *             - MemTestDevice
    *             - MemDMATest
    *
    ******************************************************************/
    static void TestRam(void)
    {
      
      int memory_base, memory_end, memory_size;
      int ret_code = 0x0;
    
      /* Find out what range of memory we are testing */
      MemGetAddressRange(&memory_base, &memory_end);
      memory_size = (memory_end - memory_base);
    
      printf("\n");
      printf("Testing RAM from 0x%X to 0x%X\n", memory_base, (memory_base + memory_size));
    
      /* Test Data Bus. */
      ret_code = MemTestDataBus(memory_base);
    
      if (ret_code)
       printf(" -Data bus test failed at bit 0x%X", (int)ret_code);
      else
        printf(" -Data bus test passed\n");
    
      /* Test Address Bus. */
      if (!ret_code)
      {
        ret_code  = MemTestAddressBus(memory_base, memory_size);
        if  (ret_code)
          printf(" -Address bus test failed at address 0x%X", (int)ret_code);
        else
          printf(" -Address bus test passed\n");
      }
    
      /* Test byte and half-word access. */
      if (!ret_code)
      {
        ret_code = MemTest8_16BitAccess(memory_base);
        if  (ret_code)
          printf(" -Byte and half-word access test failed at address 0x%X", (int)ret_code);
        else
          printf(" -Byte and half-word access test passed\n");
      }
    
      /* Test that each bit in the device can store both 1 and 0. */
      if (!ret_code)
      {
        printf(" -Testing each bit in memory device.");
        ret_code = MemTestDevice(memory_base, memory_size);
        if  (ret_code)
          printf("  failed at address 0x%X", (int)ret_code);
        else
          printf("  passed\n");
      }
      
      /* Test DMA access to the RAM if DMA exists */
    #ifdef DMA_NAME  
      if (!ret_code)
      {
        printf(" -Testing memory using DMA.");
        ret_code = MemDMATest(memory_base, memory_size);
        if  (ret_code)
          printf("  failed at address 0x%X", (int)ret_code);
        else
          printf("  passed\n");
      }
    #endif /* DMA_NAME */
          
      if (!ret_code)
        printf("Memory at 0x%X Okay\n", memory_base);
    }
    
    
    /******************************************************************
    *  Function: FlashCheckIfBlockErased
    *
    *  Purpose: Checks the specified flash block to see if it is 
    *           completely erased (all 0xFFFFFFFF).
    *
    ******************************************************************/
    static int FlashCheckIfBlockErased(alt_flash_fd* fd, int block, flash_region* regions)
    {
      int i, j;
      int ret_code = 0x0;
      char block_is_erased = 0x1;
      alt_u8 *data_read;
     
      /* Get a buffer */
      data_read = malloc(64);
      
      /* Initialize the flag */
      block_is_erased = 0x1;
    
      for(i = 0; i < regions->block_size; i += 64)
      {
        ret_code = alt_read_flash(fd, ((block * regions->block_size) + i), data_read, 64);
    
        for(j=0; j < 64; j+=1)
        {
          if(*(data_read+j) != 0xFF)
          {
            /* If this byte isn't erased, then neither is the block */
            block_is_erased = 0x0;
            break;
          }
        }
        if (block_is_erased == 0x0)
          break;
      }
      /* Block is erased if we indexed through all block locations */
      if(i == regions->block_size)
        ret_code = 1;
      else
        ret_code = 0;
      
      free(data_read);
     
      return ret_code;
    }
    
    
    /******************************************************************
    *  Function: FlashTestBlockWrite
    *
    *  Purpose: Tests that the function alt_write_flash_block is
    *           is working properly.
    *
    ******************************************************************/
    static int FlashTestBlockWrite(int block, int *error, alt_flash_fd* fd, flash_region* regions)
    {
      int i;
      int ret_code = 0x0;
      int test_offset;
    
      alt_u8 *data_written;
      alt_u8 *data_read;
    
    
      /* Get a couple buffers for the test */
      data_written = malloc(100);
      data_read = malloc(100);
    
      test_offset = (regions->offset + (block * regions->block_size));
    
      /* Fill write buffer with 100 values (incremented by 3) */
      for(i=0; i < 100; i++)
        *(data_written + i) = (i * 3);
    
      /* Write the buffer to flash starting 0x40 bytes from the beginning of the block. */
      printf(" -Testing \"alt_write_flash_block\".");
      ret_code = alt_write_flash_block(fd, test_offset, (test_offset + 0x40), data_written, 100);
      if (!ret_code)
      {
        /* Now read it back into the read_buffer */
        ret_code = alt_read_flash(fd, (test_offset + 0x40), data_read, 100);
        if(!ret_code)
        {
          /* See if they match */
          if (memcmp(data_written, data_read, 100))
          {
            printf("  FAILED.\n");
            *error++;
          }
          else
            printf("  passed.\n");
        }
      }
    
      /* Test unaligned writes */
      if(!ret_code)
      {
        /* Erase the block */
        ret_code = alt_erase_flash_block(fd, test_offset, regions->block_size);
      
        /* Write the buffer to flash on an unaligned address. */
        printf(" -Testing unaligned writes.");
        ret_code = alt_write_flash_block(fd, test_offset, (test_offset + 0x43), data_written, 100);
        if (!ret_code)
        {
          /* Now read it back into the read_buffer */
          ret_code = alt_read_flash(fd, (test_offset + 0x43), data_read, 100);
          if(!ret_code)
          {
            /* See if they match */
            if (memcmp(data_written, data_read, 100))
            {
              printf("  FAILED.\n");
              *error++;
            }
            else
              printf("  passed.\n");
          }
        }
      }
    
      /* Free up the buffers we allocated. */
      free(data_written);
      free(data_read);
      
      return ret_code;
    }
    
    
    /******************************************************************
    *  Function: FlashTestReadWrite
    *
    *  Purpose: Tests that the functions alt_write_flash and
    *           alt_read_flash are working properly, as well as tests
    *           that every bit in the specified block can store both
    *           a '1' and '0'.
    *
    ******************************************************************/
    static int FlashTestReadWrite(int block, int *error, alt_flash_fd* fd, flash_region* regions)
    {
      int i;
      int ret_code = 0x0;
      int test_offset;
    
      alt_u8 *data_written;
      alt_u8 *data_read;
     
    
      /* Get a couple buffers for the tests */
      data_written = malloc(regions->block_size);
      data_read = malloc(regions->block_size);
     
      /* Calculate the offset at which the block lives */
      test_offset = (regions->offset + (block * regions->block_size));
    
      printf("\n -Starting Flash Test.\n");
     
      printf(" -Testing \"alt_write_flash\" and \"alt_read_flash\".\n");
      /* Fill buffer with incrementing values */
      for(i=0; i < regions->block_size; i++)
        *(data_written + i) = i;
    
      /* Write the buffer to flash block */
      ret_code = alt_write_flash(fd, test_offset, data_written, regions->block_size);
         
      if (!ret_code)
      {
        /* Read flash block into read buffer */
        ret_code = alt_read_flash(fd, test_offset, data_read, regions->block_size);
        if(!ret_code)
        {
          /* See if they match */
          if (memcmp(data_written, data_read, regions->block_size))
          {
            printf("    pass 1 - FAILED.\n");
            *error++;
          }
          else
            printf("    pass 1 - passed.\n");
        }
      
        /* Now fill the buffer with decrementing values (invert the incrementing ones) */
        for(i=0; i < regions->block_size; i++)
          *(data_written + i) = ~((alt_u8)(i));
     
        /* Write the buffer to flash block */
        ret_code = alt_write_flash(fd, test_offset, data_written, regions->block_size);
        
        if (!ret_code)
        {
          /* Read flash block into read buffer */
          ret_code = alt_read_flash(fd, test_offset, data_read, regions->block_size);
          if(!ret_code)
          {
            /* See if they match */
            if (memcmp(data_written, data_read, regions->block_size))
            {
              printf("    pass 2 - FAILED.\n");
              *error++;
            }
            else
              printf("    pass 2 - passed.\n");
          }
        }
        if (*error)
          ret_code = 1;
      }
    
      /* Free up the buffers we allocated */
      free(data_written);
      free(data_read);
      
      return ret_code;
    }
    
    
    /******************************************************************
    *  Function: FlashTestBlockErase
    *
    *  Purpose: Tests that the function alt_erase_flash_block is
    *           is working properly.  Assumes that the specified
    *           flash block contains some non-0xFFFFFFFF data before
    *           this function is called.
    *
    ******************************************************************/
    static int FlashTestBlockErase(int block, int *error, alt_flash_fd* fd, flash_region* regions)
    {
    
      int ret_code = 0x0;
      int test_offset;
    
      /* Calculate the offset of the block */
      test_offset = (regions->offset + (block * regions->block_size));
    
      printf(" -Testing \"alt_erase_flash_block\".");
      ret_code = alt_erase_flash_block(fd, test_offset, regions->block_size);
      /* Check that the erase was successful. */
      if (!ret_code)
      {
        if(FlashCheckIfBlockErased(fd, block, regions))
          printf("  passed.\n");
        else
        {
          printf("  FAILED\n");  
          *error++;
        }
      }
      
      return ret_code;
    }
    
    
    /******************************************************************
    *  Function: FlashRunTests
    *
    *  Purpose: Performs a full-test on the Flash specified.  The tests
    *           run are:
    *             - alt_write_flash
    *             - alt_read_flash
    *             - alt_erase_flash_block
    *             - alt_write_flash_block
    * 
    ******************************************************************/
    static void FlashRunTests(alt_flash_fd* fd, int block, flash_region* regions)
    {
      int ret_code = 0x0;
      int error = 0x0;
      int test_offset;
    
      /* Calculate the offset of the block */
      test_offset = (regions->offset + (block * regions->block_size));
      
      /* Test reading and writing functions */
      ret_code = FlashTestReadWrite(block, &error, fd, regions);
     
      /* Test the erase function */
      if (!ret_code)
      {
        ret_code = FlashTestBlockErase(block, &error, fd, regions);
      }
      /* Test the block write function */
      if (!ret_code)
      {
        ret_code = FlashTestBlockWrite(block, &error, fd, regions);
      }
    
      /* Erase the block so we dont fill one up each time we run the test */
      printf(" -Returning block %d to its erased state.\n", block);
      alt_erase_flash_block(fd, test_offset, regions->block_size);
     
      printf(" -Flash tests complete.\n");
      if(ret_code || error)
      {
        printf(" -At least one test failed.\n\n");
      }
    }
    
    
    /******************************************************************
    *  Function: GetFlashName
    *
    *  Purpose: Gets the name of the flash to test from the user
    *           Defaults to "/dev/ext_flash", the name of the flash
    *           component in the Nios II example designs.
    * 
    ******************************************************************/
    static int GetFlashName(char line[30], int flash_type)
    {
    
      char ch = 0x0;
      int i;
    
      if (flash_type == CFI)
      { 
        printf("\nEnter the name of the CFI flash device to be opened,\n");
        printf("or just press  to open \"/dev/ext_flash\"\n");
        printf(">");
      }
      else if (flash_type == EPCS)
      {
        printf("\nEnter the name of the EPCS flash device to be opened,\n");
        printf("or just press  to open \"/dev/epcs_controller\"\n");
        printf(">");
      }
     
      for(i = 0; ch != '\n'; i++)
      {
        ch = getc(stdin);
        if(ch == '\r' || ch == '\n')
        {
          /* Hitting  defaults to the standard component name */
          if( i <= 1 )
          {
            if (flash_type == CFI)
              strcpy(line, "/dev/ext_flash\0");
            else if (flash_type == EPCS)
              strcpy(line, "/dev/epcs_controller\0");
          }
             
          else
            /* Properly terminate the string. */
            line[i] = '\0';
        }
        else
         line[i] = ch;
      }
     
      return 0;
    }
    
    
    
    /******************************************************************
    *  Function: FlashErase
    *
    *  Purpose: Erases 1 or all blocks in the specified flash device.
    * 
    ******************************************************************/
    static void FlashErase(int flash_type)
    {
      alt_flash_fd* fd;
      int test_offset;
      int ret_code;
      flash_region* regions;
      int number_of_regions;
      alt_u8 entry[4];
      alt_u8 flashname[30];
      unsigned int block;
     
      /* Get the name of the flash we are erasing */
      ret_code = GetFlashName(flashname, flash_type);
     
      fd = alt_flash_open_dev(flashname);
      if (fd)
      {
        /* Find out some useful stuff about the flash */
        ret_code = alt_get_flash_info(fd, ®ions, &number_of_regions);
        if (!ret_code)
        {
          printf(" -Region has %d blocks.\n", regions->number_of_blocks);
          printf(" -Which block would you like to erase?\n");
          printf(" -> ");
          
          GetInputString( entry, sizeof(entry), stdin );
    
          if(entry[0] == 'a')
          {
            printf(" -Erase ALL blocks? (y/n) ");
    
            GetInputString( entry, sizeof(entry), stdin );
            
            if(entry[0] == 'y')
            {
              /* Erase all blocks */
              printf(" -Erasing %d blocks.  Please Wait.\n", (regions->number_of_blocks));
              for(block = 0; block < regions->number_of_blocks; block++)
              {
                /* Dont erase it if it's already erased silly. */
                if ((FlashCheckIfBlockErased(fd, block, regions)) == 0)
                {
                  test_offset = (regions->offset + (block * regions->block_size));
                  alt_erase_flash_block(fd, test_offset, regions->block_size);
                }
                /* Just a simple progress meter so we dont get bored waiting for the flash to erase. */
                printf(".");
                if(((block + 1) % 80) == 0)
                {
                  printf("\n");
                }
              }
              printf("\n -All Blocks Erased.\n");
            }
            else
            {
              printf("Erased zero blocks.\n");
            }
          }
          /* Just erase one block */
          if(sscanf(entry, "%d\n", &block))
          {
            if ((block >= 0) && (block <= (regions->number_of_blocks - 1)))
            {
              test_offset = (regions->offset + (block * regions->block_size));
              alt_erase_flash_block(fd, test_offset, regions->block_size);
              printf(" -Block %d erased.\n", block);
            }
            else
            {
              printf(" -Block number entered is %d\n", block);
              printf(" -Block number must be between 0 and %d.\n", (regions->number_of_blocks - 1));
            }
          }
        }
        printf(" -Closing flash \"%s\".\n", flashname);
        alt_flash_close_dev(fd);
      }
    }
    
      
    /******************************************************************
    *  Function: FlashFindErasedBlocks
    *
    *  Purpose: Looks through the specified flash for blocks which 
    *           are completely erased.  If the mode parameter is 
    *           TEST, this function simply returns the index of the 
    *           first block which is completely erased.  If the mode
    *           parameter is SHOWMAP, the function prints a list of 
    *           all blocks, indicating which ones are erased.
    * 
    ******************************************************************/
    static int FlashFindErasedBlocks(alt_flash_fd* fd, flash_region* regions, int number_of_regions, int mode)
    { 
      int region_index, block_index;
      int block_erased = 0x0;
      alt_u8 entry[5];
      unsigned int block;
    
      /* Currently only supports flashes with 1 region, but region loop is left here for possible */
      /* future implementation */
      for(region_index = 0; region_index < number_of_regions; region_index++)
      {
        printf(" -Checking Region %d for erased blocks.\n", region_index);
        /* SHOWMAP mode has a legend reminding us what little plus and minus signs mean */
        if(mode == SHOWMAP)
        {
          printf("            erased block = '-'\n");     
          printf("          unerased block = '+'\n\n");     
        }
        /* Check those blocks. */
        for(block_index = 0; block_index < (regions->number_of_blocks); block_index++)
        {
          block_erased = FlashCheckIfBlockErased(fd, block_index, regions);
          /* If it's erased and were running in TEST mode, we're done */
          if(block_erased && (mode == TEST))
            break;
          /* If in SHOWMAP mode, mark block as either erased or not-erased. */
          else if(block_erased && (mode == SHOWMAP))
            printf("  Block %3d @ 0x%8.8X:\t-\n", block_index, (regions->offset + (block_index * regions->block_size)));           
          else if(!block_erased && (mode == SHOWMAP))
            printf("  Block %3d @ 0x%8.8X:\t+\n", block_index, (regions->offset + (block_index * regions->block_size)));           
        }
        /* Special case if no blocks are erased (TEST mode only)*/
        if(( block_index == ( regions->number_of_blocks )) && ( mode == TEST ))
        {
          printf(" -Found no erased blocks.  Please enter the number of the block\n");
          printf("  you would like to test.  Enter 'q' to quit without testing flash.\n");
          printf(" -> ");
    
          GetInputString( entry, sizeof(entry), stdin );
    
          if(entry[0] == 'q')
          {
                block_index = QUIT_WITHOUT_TESTING;
                break;
            }
          else if(sscanf(entry, "%d\n", &block))
          {
            if ((block >= 0) && (block <= (regions->number_of_blocks - 1)))
            {
                block_index = block;
                break;
            }
            else 
            {
              printf(" -Block number entered is %d\n", block);
              printf(" -Block number must be between 0 and %d.\n", (regions->number_of_blocks - 1));
            }
          }        
        }
        /* Break out of the region loop if we've found an erased block to test. */
        if(block_erased && (mode == TEST))
          break;
      }
    
      return block_index;
    }
    
    
    /******************************************************************
    *  Function: TestFlash
    *
    *  Purpose: Opens the specified flash device.  If the mode
    *           parameter is TEST, the function finds an erased 
    *           block, then tests it.  If the mode parameter is 
    *           SHOWMAP, the function lists all blocks in the flash and
    *           indicates which ones are erased.  The flash is closed
    *           at the end of the function.
    * 
    ******************************************************************/
    static void TestFlash(int mode, int flash_type)
    {
      alt_flash_fd* fd;
      int number_of_regions;
      int block;
      flash_region* regions;
      int ret_code = 0x0;
      alt_u8 entry[4];
      alt_u8 flashname[30];
      
      ret_code = GetFlashName(flashname, flash_type);
    
      fd = alt_flash_open_dev(flashname);
      if (fd)
      {
        printf(" -Successfully opened %s\n", flashname);
        
        /* Get some useful info about the flash */
        ret_code = alt_get_flash_info(fd, ®ions, &number_of_regions);
          
        if (!ret_code)
        {
          printf(" -Region 0 contains %d blocks.\n", regions->number_of_blocks);
          
          block = FlashFindErasedBlocks(fd, regions, number_of_regions, mode);
    
          /* If we're in TEST mode, ask if this block is okay to test. */
          if(( mode == TEST ) && ( block != QUIT_WITHOUT_TESTING ))
          {
            printf(" -Block %d, at address 0x%X identified.\n", block, (regions->offset + (block * regions->block_size)));
            printf(" -Would you like to test this block? (y/n)");
    
            GetInputString(entry, sizeof(entry), stdin);
    
            if ( entry[0] == 'y' && entry[1] == '\n' )
            {
              /* Test that Flash! */
              FlashRunTests(fd, block, regions);
              printf(" -Closing flash device \"%s\".\n", flashname);
              alt_flash_close_dev(fd);
            }       
          }
        }
      }
      else
      {
        printf(" -ERROR: Could not open %s\n", flashname);   
      }
    }
    
    
    /******************************************************************
    *  Function: TopMenu
    *
    *  Purpose: Generates the top level menu.
    * 
    ******************************************************************/
    static int TopMenu( void )
    {
      char ch;
    
      /* Print the top-level menu to stdout */
      while (1)
      {
        MenuBegin("      Memory Test Main Menu");
        MenuItem( 'a', "Test RAM" );
        MenuItem( 'b', "Test Flash");
    #ifdef EPCS_CONTROLLER_NAME    
        MenuItem( 'c', "Test EPCS Serial Flash");
        ch = MenuEnd( 'a', 'c' );    
    #else
        ch = MenuEnd( 'a', 'b' );
    #endif /* EPCS_CONTROLLER_NAME */
    
        switch(ch)
        {
          MenuCase('a',TestRam());
          MenuCase('b',TestFlash(TEST, CFI));
          MenuCase('e',FlashErase(CFI));       /* hidden option */
          MenuCase('m',TestFlash(SHOWMAP, CFI)); /* hidden option */
    #ifdef EPCS_CONTROLLER_NAME    
          MenuCase('c',TestFlash(TEST, EPCS));
          MenuCase('f',FlashErase(EPCS));       /* hidden option */
          MenuCase('s',TestFlash(SHOWMAP, EPCS)); /* hidden option */
    #endif /* EPCS_CONTROLLER_NAME */
          case 'q':    break;
          default:    printf("\n -ERROR: %c is an invalid entry.  Please try again\n", ch); break;
        }
        if (ch == 'q')
          break;
        printf("\nPress enter to continue...\n");
        while( (( ch = getc(stdin)) != '\n' ) && ( ch != EOF ));
    
      }
      return (ch);
    }
    
    
    /******************************************************************
    *  Function: main
    *
    *  Purpose: Continually prints the menu and performs the actions
    *           requested by the user.
    * 
    ******************************************************************/
    int main(void)
    {
    
      int ch;
    
      /* Print the Header */
      MenuHeader();
      /* Print the menu and do what the user requests, until they hit 'q' */
      while (1)
      {
        ch = TopMenu();
        if (ch == 'q')
        {
          printf( "\nExiting from Memory Test.\n");
          break;
        }
      }
      return (0);
    }
    
    
    /******************************************************************************
    *                                                                             *
    * License Agreement                                                           *
    *                                                                             *
    * Copyright (c) 2004 Altera Corporation, San Jose, California, USA.           *
    * All rights reserved.                                                        *
    *                                                                             *
    * Permission is hereby granted, free of charge, to any person obtaining a     *
    * copy of this software and associated documentation files (the "Software"),  *
    * to deal in the Software without restriction, including without limitation   *
    * the rights to use, copy, modify, merge, publish, distribute, sublicense,    *
    * and/or sell copies of the Software, and to permit persons to whom the       *
    * Software is furnished to do so, subject to the following conditions:        *
    *                                                                             *
    * The above copyright notice and this permission notice shall be included in  *
    * all copies or substantial portions of the Software.                         *
    *                                                                             *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  *
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    *
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      *
    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING     *
    * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER         *
    * DEALINGS IN THE SOFTWARE.                                                   *
    *                                                                             *
    * This agreement shall be governed in all respects by the laws of the State   *
    * of California and by the laws of the United States of America.              *
    * Altera does not recommend, suggest or require that this reference design    *
    * file be used in conjunction or combination with any other product.          *
    ******************************************************************************/

    参考

    1. Altera.Nios II Software Developer's Handbook

  • 相关阅读:
    Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the EditerInput
    React 综合事件 SyntheticEvent
    浏览器进程?线程?
    如何选择Redux的store和React的state?
    主流浏览器内核介绍(前端开发值得了解的浏览器内核历史)
    前端路由实现与 react-router 源码分析
    Sass Less SCSS 的抉择
    单行居中显示文字,多行居左显示,最多两行超过用省略号结尾
    link和@import的区别
    css选择符属性继承优先级算法以及css3新增伪类新特性
  • 原文地址:https://www.cnblogs.com/yuphone/p/1717605.html
Copyright © 2020-2023  润新知