[笔记].怎样使用Nios II中的Memory Test模板来测试RAM和Flash.[Memory][Nios II][SOPC Builder]
0赞本文简单描述如何使用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控制器
注意观察epcs控制器和sdram控制器的起始和终止地址。此处epcs controller,例化为epcs,起始地址是0x01002090,终止地址是0x01002097;sdram controller,与epcs类似。当然也可查看之后生成的system.h。
步骤2 使用Nios II中的Memory Test模板来测试
1. 使用Memory Test模板创建软件工程
图2 创建软件工程
2. 编译程序及检查相关设置
编程成功后,打开system.h,查看与存储器相关的映射内容。
1 |
#define ALT_MODULE_CLASS_epcs altera_avalon_epcs_flash_controller |
2 |
#define EPCS_BASE 0x1001800 |
3 |
#define EPCS_IRQ 1 |
4 |
#define EPCS_IRQ_INTERRUPT_CONTROLLER_ID 0 |
5 |
#define EPCS_NAME "/dev/epcs" |
6 |
#define EPCS_REGISTER_OFFSET 512 |
7 |
#define EPCS_SPAN 2048 |
8 |
#define EPCS_TYPE "altera_avalon_epcs_flash_controller" |
代码1 EPCS相关的映射
01 |
#define ALT_MODULE_CLASS_sdram altera_avalon_new_sdram_controller |
02 |
#define SDRAM_BASE 0x800000 |
03 |
#define SDRAM_CAS_LATENCY 3 |
04 |
#define SDRAM_CONTENTS_INFO "" |
05 |
#define SDRAM_INIT_NOP_DELAY 0.0 |
06 |
#define SDRAM_INIT_REFRESH_COMMANDS 2 |
07 |
#define SDRAM_IRQ -1 |
08 |
#define SDRAM_IRQ_INTERRUPT_CONTROLLER_ID -1 |
09 |
#define SDRAM_IS_INITIALIZED 1 |
10 |
#define SDRAM_NAME "/dev/sdram" |
11 |
#define SDRAM_POWERUP_DELAY 100.0 |
12 |
#define SDRAM_REFRESH_PERIOD 15.625 |
13 |
#define SDRAM_REGISTER_DATA_IN 1 |
14 |
#define SDRAM_SDRAM_ADDR_WIDTH 22 |
15 |
#define SDRAM_SDRAM_BANK_WIDTH 2 |
16 |
#define SDRAM_SDRAM_COL_WIDTH 8 |
17 |
#define SDRAM_SDRAM_DATA_WIDTH 16 |
18 |
#define SDRAM_SDRAM_NUM_BANKS 4 |
19 |
#define SDRAM_SDRAM_NUM_CHIPSELECTS 1 |
20 |
#define SDRAM_SDRAM_ROW_WIDTH 12 |
21 |
#define SDRAM_SHARED_DATA 0 |
22 |
#define SDRAM_SIM_MODEL_BASE 1 |
23 |
#define SDRAM_SPAN 8388608 |
24 |
#define SDRAM_STARVATION_INDICATOR 0 |
25 |
#define SDRAM_TRISTATE_BRIDGE_SLAVE "" |
26 |
#define SDRAM_TYPE "altera_avalon_new_sdram_controller" |
27 |
#define SDRAM_T_AC 5.5 |
28 |
#define SDRAM_T_MRD 3 |
29 |
#define SDRAM_T_RCD 20.0 |
30 |
#define SDRAM_T_RFC 70.0 |
31 |
#define SDRAM_T_RP 20.0 |
32 |
#define SDRAM_T_WR 14.0 |
代码2 SDRAM相关的映射
3. 运行程序
运行程序后,在Nios II Console出现如下字样。
图3 Nios II Console 显示结果
此命令行界面,提示输入a,测试RAM;输入b,测试Flash;输入q,退出。
由于程序是在SDRAM中运行的,那么我们先测试EPCS。选择b,回车;接下来输入EPCS设备名,出现如下提示。
图4 提示测试EPCS Flash
命令行提示,EPCS设备已经打开;区域0有8个块等信息;并询问是否测试块3。此处选择y,开始测试。
图5 测试EPCS
在EPCS的块3,写Flash和读Flash操作被测试完毕。然后自动关闭EPCS设备。
回车后,选择a,接着测试SDRAM。
图6 提示输入测试SDRAM的起始地址
提示输入其实地址。从system.h可以看到,SDRAM从0x800000开始寻址;在SOPC Builder中,更可以清楚地了解到SDRAM的起始和终止地址。然而,程序是在SDRAM中运行的;如果在此处,直接输入SDRAM寻址的起始地址,有可能引起冲突,以致于程序无法继续运行下去。那我们先测试其他地址开始的内容,此处以0x900000为例。
图6 提示输入测试SDRAM的终止地址
输入大于测试SDRAM的起始地址的地址即可,此处以0xA00000为例。
图7 输入测试SDRAM的终止地址,显示测试结果
测试结果显示:从地址0x900000到地址0xA00000,数据总线测试通过;地址总线测试通过,字节和半字数据接入测试通过;单独位测试通过。
附录1 mem_test.c
此处,水平有限,不做解析,请读者自行分析。着重分析和学习其中的存储器操作方法。
0001 |
/************************************************************************** |
0002 |
* Copyright (c) 2004 Altera Corporation, San Jose, California, USA. * |
0003 |
* All rights reserved. All use of this software and documentation is * |
0004 |
* subject to the License Agreement located at the end of this file below.* |
0005 |
*************************************************************************/ |
0006 |
/************************************************************************** |
0007 |
* |
0008 |
* |
0009 |
* Description |
0010 |
*************** |
0011 |
* This is a test program which tests RAM and flash memory. |
0012 |
* |
0013 |
* |
0014 |
* Requirements |
0015 |
**************** |
0016 |
* This is a "Hosted" application. According to the ANSI C standard, hosted |
0017 |
* applications can rely on numerous system-services (including properly- |
0018 |
* initialized device drivers and, in this case, STDOUT). |
0019 |
* |
0020 |
* When this program is compiled, code is added before main(), so that all |
0021 |
* devices are properly-initialized and all system-services (e.g. the |
0022 |
* library) are ready-to-use. In this hosted environment, all standard C |
0023 |
* programs will run. |
0024 |
* |
0025 |
* A hosted application (like this example) does not need to concern itself |
0026 |
* with initializing devices. As long as it only calls C Standard Library |
0027 |
* functions, a hosted application can run "as if on a workstation." |
0028 |
* |
0029 |
* An application runs in a hosted environment if it declares the function |
0030 |
* main(), which this application does. |
0031 |
* |
0032 |
* This software example requires a STDOUT component such as a UART or |
0033 |
* JTAG UART, a CFI flash component, and 2 RAM components (one for running |
0034 |
* the program, and one for testing) Therefore it can run on the following |
0035 |
* hardware examples: |
0036 |
* |
0037 |
* Nios Development Board, Stratix II Edition: |
0038 |
* - Standard (DMA RAM test will not run) |
0039 |
* - Full Featured |
0040 |
* |
0041 |
* DSP Development Board, Stratix II Edition: |
0042 |
* - Standard (DMA RAM test will not run) |
0043 |
* - Full Featured |
0044 |
* |
0045 |
* Nios Development Board, Stratix Edition: |
0046 |
* - Standard (DMA RAM test will not run) |
0047 |
* - Full Featured |
0048 |
* |
0049 |
* Nios Development Board, Stratix Professional Edition: |
0050 |
* - Standard (DMA RAM test will not run) |
0051 |
* - Full Featured |
0052 |
* |
0053 |
* Nios Development Board, Cyclone Edition: |
0054 |
* - Standard (DMA RAM test will not run) |
0055 |
* - Full Featured |
0056 |
* |
0057 |
* Nios Development Board, Cyclone II Edition: |
0058 |
* - Standard (DMA RAM test will not run) |
0059 |
* - Full Featured |
0060 |
* |
0061 |
* Note: This example will not run on the Nios II Instruction Set Simulator |
0062 |
* |
0063 |
* Peripherals Exercised by SW |
0064 |
******************************* |
0065 |
* The example's purpose is to test RAM and flash, as well as demonstrate the |
0066 |
* use of the DMA controller and flash API in NiosII. |
0067 |
* |
0068 |
* The RAM test routine performs the following operations: |
0069 |
* 1.) Tests the address and data lines for shorts and opens. |
0070 |
* 2.) Tests byte and half-word access. |
0071 |
* 3.) Tests every bit in the memory to store both '1' and '0'. |
0072 |
* 4.) Tests DMA access to the memory. |
0073 |
* |
0074 |
* IMPORTANT: The RAM test is destructive to the contents of the RAM. For this |
0075 |
* reason, you MUST assure that none of the software sections are located in |
0076 |
* the RAM being tested. This requires that code, data, and exception |
0077 |
* locations must all be in a memory seperate from the one being tested. |
0078 |
* These locations can be adjusted in Nios II IDE and SOPC Builder. |
0079 |
* |
0080 |
* |
0081 |
* The flash tests demonstrate the use of the flash programming API. After the |
0082 |
* flash device specified is opened, the test routine searches for a block in |
0083 |
* the device that is already erased. This prevents any overwriting of |
0084 |
* important data that may be programmed in flash. When an erased block is |
0085 |
* found, the routine performs a test of the flash API calls on that block. |
0086 |
* |
0087 |
* The following API functions are then run to test the flash interface: |
0088 |
* |
0089 |
* - alt_get_flash_info |
0090 |
* This function queries the flash device and collects various information |
0091 |
* about it. In the example, the results of this query are compared to what |
0092 |
* is expected, and an error is reported in the event of a mismatch. |
0093 |
* - alt_write_flash |
0094 |
* This function writes a specified number of bytes to the flash device. |
0095 |
* In the example, this function is called repeatedly in a loop to write a |
0096 |
* lengthy amount of data. |
0097 |
* - alt_read_flash |
0098 |
* This function reads a specified number of bytes of data from the flash |
0099 |
* device. In the example, alt_read_flash is used to read back and test |
0100 |
* all of the writing routines. |
0101 |
* - alt_erase_flash_block |
0102 |
* This function performs a block erase on the flash device. |
0103 |
* - alt_write_flash_block |
0104 |
* This function writes an erase block of data to the flash device. |
0105 |
* |
0106 |
* During the test, status and error information is passed to the user via |
0107 |
* printf's. |
0108 |
* |
0109 |
* Software Files |
0110 |
****************** |
0111 |
* memtest.c - Main C file that contains all memory testing code in this |
0112 |
* example. |
0113 |
* |
0114 |
**************************************************************************/ |
0115 |
|
0116 |
|
0117 |
#include |
0118 |
#include |
0119 |
#include |
0120 |
#include |
0121 |
#include |
0122 |
|
0123 |
#include "sys/alt_dma.h" |
0124 |
#include "system.h" |
0125 |
#include "sys/alt_flash.h" |
0126 |
#include "sys/alt_flash_dev.h" |
0127 |
|
0128 |
/* Mode parameters for Flash Test */ |
0129 |
#define TEST 1 |
0130 |
#define SHOWMAP 2 |
0131 |
#define CFI 3 |
0132 |
#define EPCS 4 |
0133 |
#define QUIT_WITHOUT_TESTING -1 |
0134 |
|
0135 |
/* One nice define for going to menu entry functions. */ |
0136 |
#define MenuCase(letter,proc) case letter:proc; break; |
0137 |
|
0138 |
/* Global DMA "transaction finished" flag */ |
0139 |
#ifdef DMA_NAME |
0140 |
static volatile int rx_done = 0; |
0141 |
#endif /* DMA_NAME */ |
0142 |
|
0143 |
/****************************************************************** |
0144 |
* Function: MenuHeader |
0145 |
* |
0146 |
* Purpose: Prints the menu header. |
0147 |
* |
0148 |
******************************************************************/ |
0149 |
static void MenuHeader( void ) |
0150 |
{ |
0151 |
printf ( "\n\n" ); |
0152 |
printf ( " <----> Nios II Memory Test. <---->\n" ); |
0153 |
printf ( "This software example tests the memory in your system to assure it\n" ); |
0154 |
printf ( "is working properly. This test is destructive to the contents of\n" ); |
0155 |
printf ( "the memory it tests. Assure the memory being tested does not contain\n" ); |
0156 |
printf ( "the executable or data sections of this code or the exception address\n" ); |
0157 |
printf ( "of the system.\n" ); |
0158 |
} |
0159 |
|
0160 |
/****************************************************************** |
0161 |
* Function: MenuBegin |
0162 |
* |
0163 |
* Purpose: Prints the top portion of the menu. |
0164 |
* |
0165 |
******************************************************************/ |
0166 |
static void MenuBegin( char *title ) |
0167 |
{ |
0168 |
printf ( "\n\n" ); |
0169 |
printf ( "----------------------------------\n" ); |
0170 |
printf ( "%s\n" ,title); |
0171 |
printf ( "----------------------------------\n" ); |
0172 |
} |
0173 |
|
0174 |
/****************************************************************** |
0175 |
* Function: MenuItem |
0176 |
* |
0177 |
* Purpose: Prints selection items in the menu, enumerated by the |
0178 |
* specified letter. |
0179 |
* |
0180 |
******************************************************************/ |
0181 |
static void MenuItem( char letter, char *name ) |
0182 |
{ |
0183 |
printf ( " %c: %s\n" ,letter, name); |
0184 |
} |
0185 |
|
0186 |
/****************************************************************** |
0187 |
* Function: GetInputString |
0188 |
* |
0189 |
* Purpose: Parses an input string for the character '\n'. Then |
0190 |
* returns the string, minus any '\r' characters it |
0191 |
* encounters. |
0192 |
* |
0193 |
******************************************************************/ |
0194 |
void GetInputString( char * entry, int size, FILE * stream ) |
0195 |
{ |
0196 |
int i; |
0197 |
int ch = 0; |
0198 |
|
0199 |
for (i = 0; (ch != '\n' ) && (i < size); ) |
0200 |
{ |
0201 |
if ( (ch = getc (stream)) != '\r' ) |
0202 |
{ |
0203 |
entry[i] = ch; |
0204 |
i++; |
0205 |
} |
0206 |
} |
0207 |
} |
0208 |
|
0209 |
/****************************************************************** |
0210 |
* Function: MenuEnd |
0211 |
* |
0212 |
* Purpose: Prints the end of the menu, then captures and returns |
0213 |
* the user's selection. |
0214 |
* |
0215 |
******************************************************************/ |
0216 |
static int MenuEnd( char lowLetter, char highLetter ) |
0217 |
{ |
0218 |
static char entry[4]; |
0219 |
static char ch; |
0220 |
|
0221 |
printf ( " q: Exit\n" ); |
0222 |
printf ( "----------------------------------\n" ); |
0223 |
printf ( "\nSelect Choice (%c-%c): [Followed by ,lowLetter,highLetter); |
0224 |
|
0225 |
GetInputString( entry, sizeof (entry), stdin ); |
0226 |
if ( sscanf (entry, "%c\n" , &ch)) |
0227 |
{ |
0228 |
if ( ch >= 'A' && ch <= 'Z' ) |
0229 |
ch += 'a' - 'A' ; |
0230 |
if ( ch == 27 ) |
0231 |
ch = 'q' ; |
0232 |
} |
0233 |
return ch; |
0234 |
} |
0235 |
|
0236 |
/****************************************************************** |
0237 |
* Function: MemGetAddressRange |
0238 |
* |
0239 |
* Purpose: Gathers a range of memory from the user. |
0240 |
* |
0241 |
******************************************************************/ |
0242 |
static int MemGetAddressRange( int * base_address, int * end_address) |
0243 |
{ |
0244 |
|
0245 |
char line[12]; |
0246 |
|
0247 |
while (1) |
0248 |
{ |
0249 |
/* Get the base address */ |
0250 |
printf ( "Base address to start memory test: (i.e. 0x800000)\n" ); |
0251 |
printf ( ">" ); |
0252 |
|
0253 |
GetInputString( line, sizeof (line), stdin ); |
0254 |
|
0255 |
/* Check the format to make sure it was entered as hex */ |
0256 |
if ( sscanf (line, "0x%X" , base_address) != 1) |
0257 |
{ |
0258 |
printf ( "%s\n" , line); |
0259 |
printf ( " -ERROR: Invalid base address entered. Address must be in the form '0x800000'\n\n" ); |
0260 |
continue ; |
0261 |
} |
0262 |
|
0263 |
/* Get the end address */ |
0264 |
printf ( "End Address:\n" ); |
0265 |
printf ( ">" ); |
0266 |
|
0267 |
GetInputString( line, sizeof (line), stdin ); |
0268 |
|
0269 |
/* Check the format to make sure it was entered as hex */ |
0270 |
if ( sscanf (line, "0x%X" , end_address) != 1) |
0271 |
{ |
0272 |
printf ( " -ERROR: Invalid end address entered. Address must be in the form '0x8FFFFF'\n\n" ); |
0273 |
continue ; |
0274 |
} |
0275 |
|
0276 |
/* Make sure end address is greater than base address. */ |
0277 |
if (end_address <= base_address) |
0278 |
{ |
0279 |
printf ( " -ERROR: End address must be greater than the start address\n\n" ); |
0280 |
|
0281 |
continue ; |
0282 |
} |
0283 |
break ; |
0284 |
} |
0285 |
|
0286 |
return (0); |
0287 |
} |
0288 |
|
0289 |
/****************************************************************** |
0290 |
* Function: MemTestDataBus |
0291 |
* |
0292 |
* Purpose: Tests that the data bus is connected with no |
0293 |
* stuck-at's, shorts, or open circuits. |
0294 |
* |
0295 |
******************************************************************/ |
0296 |
static int MemTestDataBus(unsigned int address) |
0297 |
{ |
0298 |
unsigned int pattern; |
0299 |
unsigned int ret_code = 0x0; |
0300 |
|
0301 |
/* Perform a walking 1's test at the given address. */ |
0302 |
for (pattern = 1; pattern != 0; pattern <<= 1) |
0303 |
{ |
0304 |
/* Write the test pattern. */ |
0305 |
IOWR_32DIRECT(address, 0, pattern); |
0306 |
|
0307 |
/* Read it back (immediately is okay for this test). */ |
0308 |
if (IORD_32DIRECT(address, 0) != pattern) |
0309 |
{ |
0310 |
ret_code = pattern; |
0311 |
break ; |
0312 |
} |
0313 |
} |
0314 |
return ret_code; |
0315 |
} |
0316 |
|
0317 |
|
0318 |
/****************************************************************** |
0319 |
* Function: MemTestAddressBus |
0320 |
* |
0321 |
* Purpose: Tests that the address bus is connected with no |
0322 |
* stuck-at's, shorts, or open circuits. |
0323 |
* |
0324 |
******************************************************************/ |
0325 |
static int MemTestAddressBus(unsigned int memory_base, unsigned int nBytes) |
0326 |
{ |
0327 |
unsigned int address_mask = (nBytes - 1); |
0328 |
unsigned int offset; |
0329 |
unsigned int test_offset; |
0330 |
|
0331 |
unsigned int pattern = 0xAAAAAAAA; |
0332 |
unsigned int antipattern = 0x55555555; |
0333 |
|
0334 |
unsigned int ret_code = 0x0; |
0335 |
|
0336 |
/* Write the default pattern at each of the power-of-two offsets. */ |
0337 |
for (offset = sizeof (unsigned int ); (offset & address_mask) != 0; offset <<= 1) |
0338 |
{ |
0339 |
IOWR_32DIRECT(memory_base, offset, pattern); |
0340 |
} |
0341 |
|
0342 |
/* Check for address bits stuck high. */ |
0343 |
test_offset = 0; |
0344 |
IOWR_32DIRECT(memory_base, test_offset, antipattern); |
0345 |
for (offset = sizeof (unsigned int ); (offset & address_mask) != 0; offset <<= 1) |
0346 |
{ |
0347 |
if (IORD_32DIRECT(memory_base, offset) != pattern) |
0348 |
{ |
0349 |
ret_code = (memory_base+offset); |
0350 |
break ; |
0351 |
} |
0352 |
} |
0353 |
|
0354 |
/* Check for address bits stuck low or shorted. */ |
0355 |
IOWR_32DIRECT(memory_base, test_offset, pattern); |
0356 |
for (test_offset = sizeof (unsigned int ); (test_offset & address_mask) != 0; test_offset <<= 1) |
0357 |
{ |
0358 |
if (!ret_code) |
0359 |
{ |
0360 |
IOWR_32DIRECT(memory_base, test_offset, antipattern); |
0361 |
for (offset = sizeof (unsigned int ); (offset & address_mask) != 0; offset <<= 1) |
0362 |
{ |
0363 |
if ((IORD_32DIRECT(memory_base, offset) != pattern) && (offset != test_offset)) |
0364 |
{ |
0365 |
ret_code = (memory_base + test_offset); |
0366 |
break ; |
0367 |
} |
0368 |
} |
0369 |
IOWR_32DIRECT(memory_base, test_offset, pattern); |
0370 |
} |
0371 |
} |
0372 |
|
0373 |
return ret_code; |
0374 |
} |
0375 |
|
0376 |
|
0377 |
/****************************************************************** |
0378 |
* Function: MemTest8_16BitAccess |
0379 |
* |
0380 |
* Purpose: Tests that the memory at the specified base address |
0381 |
* can be read and written in both byte and half-word |
0382 |
* modes. |
0383 |
* |
0384 |
******************************************************************/ |
0385 |
static int MemTest8_16BitAccess(unsigned int memory_base) |
0386 |
{ |
0387 |
int ret_code = 0x0; |
0388 |
|
0389 |
/* Write 4 bytes */ |
0390 |
IOWR_8DIRECT(memory_base, 0, 0x0A); |
0391 |
IOWR_8DIRECT(memory_base, 1, 0x05); |
0392 |
IOWR_8DIRECT(memory_base, 2, 0xA0); |
0393 |
IOWR_8DIRECT(memory_base, 3, 0x50); |
0394 |
|
0395 |
/* Read it back as one word */ |
0396 |
if (IORD_32DIRECT(memory_base, 0) != 0x50A0050A) |
0397 |
{ |
0398 |
ret_code = memory_base; |
0399 |
} |
0400 |
|
0401 |
/* Read it back as two half-words */ |
0402 |
if (!ret_code) |
0403 |
{ |
0404 |
if ((IORD_16DIRECT(memory_base, 2) != 0x50A0) || |
0405 |
(IORD_16DIRECT(memory_base, 0) != 0x050A)) |
0406 |
{ |
0407 |
ret_code = memory_base; |
0408 |
} |
0409 |
} |
0410 |
|
0411 |
/* Read it back as 4 bytes */ |
0412 |
if (!ret_code) |
0413 |
{ |
0414 |
if ((IORD_8DIRECT(memory_base, 3) != 0x50) || |
0415 |
(IORD_8DIRECT(memory_base, 2) != 0xA0) || |
0416 |
(IORD_8DIRECT(memory_base, 1) != 0x05) || |
0417 |
(IORD_8DIRECT(memory_base, 0) != 0x0A)) |
0418 |
{ |
0419 |
ret_code = memory_base; |
0420 |
} |
0421 |
} |
0422 |
|
0423 |
/* Write 2 half-words */ |
0424 |
if (!ret_code) |
0425 |
{ |
0426 |
IOWR_16DIRECT(memory_base, 0, 0x50A0); |
0427 |
IOWR_16DIRECT(memory_base, 2, 0x050A); |
0428 |
|
0429 |
/* Read it back as one word */ |
0430 |
if (IORD_32DIRECT(memory_base, 0) != 0x050A50A0) |
0431 |
{ |
0432 |
ret_code = memory_base; |
0433 |
} |
0434 |
} |
0435 |
|
0436 |
/* Read it back as two half-words */ |
0437 |
if (!ret_code) |
0438 |
{ |
0439 |
if ((IORD_16DIRECT(memory_base, 2) != 0x050A) || |
0440 |
(IORD_16DIRECT(memory_base, 0) != 0x50A0)) |
0441 |
{ |
0442 |
ret_code = memory_base; |
0443 |
} |
0444 |
} |
0445 |
|
0446 |
/* Read it back as 4 bytes */ |
0447 |
if (!ret_code) |
0448 |
{ |
0449 |
if ((IORD_8DIRECT(memory_base, 3) != 0x05) || |
0450 |
(IORD_8DIRECT(memory_base, 2) != 0x0A) || |
0451 |
(IORD_8DIRECT(memory_base, 1) != 0x50) || |
0452 |
(IORD_8DIRECT(memory_base, 0) != 0xA0)) |
0453 |
{ |
0454 |
ret_code = memory_base; |
0455 |
} |
0456 |
} |
0457 |
|
0458 |
return (ret_code); |
0459 |
} |
0460 |
|
0461 |
|
0462 |
/****************************************************************** |
0463 |
* Function: MemTestDevice |
0464 |
* |
0465 |
* Purpose: Tests that every bit in the memory device within the |
0466 |
* specified address range can store both a '1' and a '0'. |
0467 |
* |
0468 |
******************************************************************/ |
0469 |
static int MemTestDevice(unsigned int memory_base, unsigned int nBytes) |
0470 |
{ |
0471 |
unsigned int offset; |
0472 |
unsigned int pattern; |
0473 |
unsigned int antipattern; |
0474 |
unsigned int ret_code = 0x0; |
0475 |
|
0476 |
/* Fill memory with a known pattern. */ |
0477 |
for (pattern = 1, offset = 0; offset < nBytes; pattern++, offset+=4) |
0478 |
{ |
0479 |
IOWR_32DIRECT(memory_base, offset, pattern); |
0480 |
} |
0481 |
|
0482 |
printf ( " ." ); |
0483 |
|
0484 |
/* Check each location and invert it for the second pass. */ |
0485 |
for (pattern = 1, offset = 0; offset < nBytes; pattern++, offset+=4) |
0486 |
{ |
0487 |
if (IORD_32DIRECT(memory_base, offset) != pattern) |
0488 |
{ |
0489 |
ret_code = (memory_base + offset); |
0490 |
break ; |
0491 |
} |
0492 |
antipattern = ~pattern; |
0493 |
IOWR_32DIRECT(memory_base, offset, antipattern); |
0494 |
} |
0495 |
|
0496 |
printf ( " ." ); |
0497 |
|
0498 |
/* Check each location for the inverted pattern and zero it. */ |
0499 |
for (pattern = 1, offset = 0; offset < nBytes; pattern++, offset+=4) |
0500 |
{ |
0501 |
antipattern = ~pattern; |
0502 |
if (IORD_32DIRECT(memory_base, offset) != antipattern) |
0503 |
{ |
0504 |
ret_code = (memory_base + offset); |
0505 |
break ; |
0506 |
} |
0507 |
IOWR_32DIRECT(memory_base, offset, 0x0); |
0508 |
} |
0509 |
return ret_code; |
0510 |
} |
0511 |
|
0512 |
/****************************************************************** |
0513 |
* Function: dma_done |
0514 |
* |
0515 |
* Purpose: Called when a DMA recieve transaction is complete. |
0516 |
* Increments rx_done to signal to the main program that |
0517 |
* the transaction is done. |
0518 |
* |
0519 |
******************************************************************/ |
0520 |
#ifdef DMA_NAME |
0521 |
static void dma_done ( void * handle, void * data) |
0522 |
{ |
0523 |
rx_done++; |
0524 |
} |
0525 |
#endif /* DMA_NAME */ |
0526 |
|
0527 |
/****************************************************************** |
0528 |
* Function: MemDMATest |
0529 |
* |
0530 |
* Purpose: Tests every bit in the memory device within the |
0531 |
* specified address range using DMA. The DMA controller provides |
0532 |
* a more rigourous test of the memory since it performs back-to- |
0533 |
* back memory accesses at full system speed. |
0534 |
* |
0535 |
******************************************************************/ |
0536 |
#ifdef DMA_NAME |
0537 |
static int MemDMATest(unsigned int memory_base, unsigned int nBytes) |
0538 |
{ |
0539 |
int rc; |
0540 |
int ret_code = 0; |
0541 |
int pattern, offset; |
0542 |
alt_dma_txchan txchan; |
0543 |
alt_dma_rxchan rxchan; |
0544 |
void * data_written; |
0545 |
void * data_read; |
0546 |
|
0547 |
/* Get a couple buffers for the test */ |
0548 |
data_written = ( void *)alt_uncached_malloc(0x1000); |
0549 |
data_read = ( void *)alt_uncached_malloc(0x1000); |
0550 |
|
0551 |
|
0552 |
/* Fill write buffer with known values */ |
0553 |
for (pattern = 1, offset = 0; offset < 0x1000; pattern++, offset+=4) |
0554 |
{ |
0555 |
IOWR_32DIRECT(( int )data_written, offset, pattern); |
0556 |
} |
0557 |
|
0558 |
/* Create the transmit channel */ |
0559 |
if ((txchan = alt_dma_txchan_open( "/dev/dma" )) == NULL) |
0560 |
{ |
0561 |
printf ( "Failed to open transmit channel\n" ); |
0562 |
exit (1); |
0563 |
} |
0564 |
|
0565 |
/* Create the receive channel */ |
0566 |
if ((rxchan = alt_dma_rxchan_open( "/dev/dma" )) == NULL) |
0567 |
{ |
0568 |
printf ( "Failed to open receive channel\n" ); |
0569 |
exit (1); |
0570 |
} |
0571 |
|
0572 |
for (offset = memory_base; offset < (memory_base + nBytes); offset += 0x1000) |
0573 |
{ |
0574 |
/* Use DMA to transfer from write buffer to memory under test */ |
0575 |
/* Post the transmit request */ |
0576 |
if ((rc = alt_dma_txchan_send (txchan, data_written, 0x1000, NULL, NULL)) < 0) |
0577 |
{ |
0578 |
printf ( "Failed to post transmit request, reason = %i\n" , rc); |
0579 |
exit (1); |
0580 |
} |
0581 |
|
0582 |
/* Post the receive request */ |
0583 |
if ((rc = alt_dma_rxchan_prepare (rxchan, ( void *)offset, 0x1000, dma_done, NULL)) < 0) |
0584 |
{ |
0585 |
printf ( "Failed to post read request, reason = %i\n" , rc); |
0586 |
exit (1); |
0587 |
} |
0588 |
|
0589 |
/* Wait for transfer to complete */ |
0590 |
while (!rx_done); |
0591 |
rx_done = 0; |
0592 |
|
0593 |
/* Clear the read buffer before we fill it */ |
0594 |
memset (data_read, 0, 0x1000); |
0595 |
|
0596 |
/* Use DMA to read data back into read buffer from memory under test */ |
0597 |
/* Post the transmit request */ |
0598 |
if ((rc = alt_dma_txchan_send (txchan, ( void *)offset, 0x1000, NULL, NULL)) < 0) |
0599 |
{ |
0600 |
printf ( "Failed to post transmit request, reason = %i\n" , rc); |
0601 |
exit (1); |
0602 |
} |
0603 |
|
0604 |
/* Post the receive request */ |
0605 |
if ((rc = alt_dma_rxchan_prepare (rxchan, data_read, 0x1000, dma_done, NULL)) < 0) |
0606 |
{ |
0607 |
printf ( "Failed to post read request, reason = %i\n" , rc); |
0608 |
exit (1); |
0609 |
} |
0610 |
|
0611 |
/* Wait for transfer to complete */ |
0612 |
while (!rx_done); |
0613 |
rx_done = 0; |
0614 |
|
0615 |
if ( memcmp (data_written, data_read, 0x1000)) |
0616 |
{ |
0617 |
ret_code = offset; |
0618 |
break ; |
0619 |
} |
0620 |
} |
0621 |
alt_uncached_free(data_written); |
0622 |
alt_uncached_free(data_read); |
0623 |
return ret_code; |
0624 |
} |
0625 |
#endif /* DMA_NAME */ |
0626 |
|
0627 |
|
0628 |
/****************************************************************** |
0629 |
* Function: TestRam |
0630 |
* |
0631 |
* Purpose: Performs a full-test on the RAM specified. The tests |
0632 |
* run are: |
0633 |
* - MemTestDataBus |
0634 |
* - MemTestAddressBus |
0635 |
* - MemTest8_16BitAccess |
0636 |
* - MemTestDevice |
0637 |
* - MemDMATest |
0638 |
* |
0639 |
******************************************************************/ |
0640 |
static void TestRam( void ) |
0641 |
{ |
0642 |
|
0643 |
int memory_base, memory_end, memory_size; |
0644 |
int ret_code = 0x0; |
0645 |
|
0646 |
/* Find out what range of memory we are testing */ |
0647 |
MemGetAddressRange(&memory_base, &memory_end); |
0648 |
memory_size = (memory_end - memory_base); |
0649 |
|
0650 |
printf ( "\n" ); |
0651 |
printf ( "Testing RAM from 0x%X to 0x%X\n" , memory_base, (memory_base + memory_size)); |
0652 |
|
0653 |
/* Test Data Bus. */ |
0654 |
ret_code = MemTestDataBus(memory_base); |
0655 |
|
0656 |
if (ret_code) |
0657 |
printf ( " -Data bus test failed at bit 0x%X" , ( int )ret_code); |
0658 |
else |
0659 |
printf ( " -Data bus test passed\n" ); |
0660 |
|
0661 |
/* Test Address Bus. */ |
0662 |
if (!ret_code) |
0663 |
{ |
0664 |
ret_code = MemTestAddressBus(memory_base, memory_size); |
0665 |
if (ret_code) |
0666 |
printf ( " -Address bus test failed at address 0x%X" , ( int )ret_code); |
0667 |
else |
0668 |
printf ( " -Address bus test passed\n" ); |
0669 |
} |
0670 |
|
0671 |
/* Test byte and half-word access. */ |
0672 |
if (!ret_code) |
0673 |
{ |
0674 |
ret_code = MemTest8_16BitAccess(memory_base); |
0675 |
if (ret_code) |
0676 |
printf ( " -Byte and half-word access test failed at address 0x%X" , ( int )ret_code); |
0677 |
else |
0678 |
printf ( " -Byte and half-word access test passed\n" ); |
0679 |
} |
0680 |
|
0681 |
/* Test that each bit in the device can store both 1 and 0. */ |
0682 |
if (!ret_code) |
0683 |
{ |
0684 |
printf ( " -Testing each bit in memory device." ); |
0685 |
ret_code = MemTestDevice(memory_base, memory_size); |
0686 |
if (ret_code) |
0687 |
printf ( " failed at address 0x%X" , ( int )ret_code); |
0688 |
else |
0689 |
printf ( " passed\n" ); |
0690 |
} |
0691 |
|
0692 |
/* Test DMA access to the RAM if DMA exists */ |
0693 |
#ifdef DMA_NAME |
0694 |
if (!ret_code) |
0695 |
{ |
0696 |
printf ( " -Testing memory using DMA." ); |
0697 |
ret_code = MemDMATest(memory_base, memory_size); |
0698 |
if (ret_code) |
0699 |
printf ( " failed at address 0x%X" , ( int )ret_code); |
0700 |
else |
0701 |
printf ( " passed\n" ); |
0702 |
} |
0703 |
#endif /* DMA_NAME */ |
0704 |
|
0705 |
if (!ret_code) |
0706 |
printf ( "Memory at 0x%X Okay\n" , memory_base); |
0707 |
} |
0708 |
|
0709 |
|
0710 |
/****************************************************************** |
0711 |
* Function: FlashCheckIfBlockErased |
0712 |
* |
0713 |
* Purpose: Checks the specified flash block to see if it is |
0714 |
* completely erased (all 0xFFFFFFFF). |
0715 |
* |
0716 |
******************************************************************/ |
0717 |
static int FlashCheckIfBlockErased(alt_flash_fd* fd, int block, flash_region* regions) |
0718 |
{ |
0719 |
int i, j; |
0720 |
int ret_code = 0x0; |
0721 |
char block_is_erased = 0x1; |
0722 |
alt_u8 *data_read; |
0723 |
|
0724 |
/* Get a buffer */ |
0725 |
data_read = malloc (64); |
0726 |
|
0727 |
/* Initialize the flag */ |
0728 |
block_is_erased = 0x1; |
0729 |
|
0730 |
for (i = 0; i < regions->block_size; i += 64) |
0731 |
{ |
0732 |
ret_code = alt_read_flash(fd, ((block * regions->block_size) + i), data_read, 64); |
0733 |
|
0734 |
for (j=0; j < 64; j+=1) |
0735 |
{ |
0736 |
if (*(data_read+j) != 0xFF) |
0737 |
{ |
0738 |
/* If this byte isn't erased, then neither is the block */ |
0739 |
block_is_erased = 0x0; |
0740 |
break ; |
0741 |
} |
0742 |
} |
0743 |
if (block_is_erased == 0x0) |
0744 |
break ; |
0745 |
} |
0746 |
/* Block is erased if we indexed through all block locations */ |
0747 |
if (i == regions->block_size) |
0748 |
ret_code = 1; |
0749 |
else |
0750 |
ret_code = 0; |
0751 |
|
0752 |
free (data_read); |
0753 |
|
0754 |
return ret_code; |
0755 |
} |
0756 |
|
0757 |
|
0758 |
/****************************************************************** |
0759 |
* Function: FlashTestBlockWrite |
0760 |
* |
0761 |
* Purpose: Tests that the function alt_write_flash_block is |
0762 |
* is working properly. |
0763 |
* |
0764 |
******************************************************************/ |
0765 |
static int FlashTestBlockWrite( int block, int *error, alt_flash_fd* fd, flash_region* regions) |
0766 |
{ |
0767 |
int i; |
0768 |
int ret_code = 0x0; |
0769 |
int test_offset; |
0770 |
|
0771 |
alt_u8 *data_written; |
0772 |
alt_u8 *data_read; |
0773 |
|
0774 |
|
0775 |
/* Get a couple buffers for the test */ |
0776 |
data_written = malloc (100); |
0777 |
data_read = malloc (100); |
0778 |
|
0779 |
test_offset = (regions->offset + (block * regions->block_size)); |
0780 |
|
0781 |
/* Fill write buffer with 100 values (incremented by 3) */ |
0782 |
for (i=0; i < 100; i++) |
0783 |
*(data_written + i) = (i * 3); |
0784 |
|
0785 |
/* Write the buffer to flash starting 0x40 bytes from the beginning of the block. */ |
0786 |
printf ( " -Testing \"alt_write_flash_block\"." ); |
0787 |
ret_code = alt_write_flash_block(fd, test_offset, (test_offset + 0x40), data_written, 100); |
0788 |
if (!ret_code) |
0789 |
{ |
0790 |
/* Now read it back into the read_buffer */ |
0791 |
ret_code = alt_read_flash(fd, (test_offset + 0x40), data_read, 100); |
0792 |
if (!ret_code) |
0793 |
{ |
0794 |
/* See if they match */ |
0795 |
if ( memcmp (data_written, data_read, 100)) |
0796 |
{ |
0797 |
printf ( " FAILED.\n" ); |
0798 |
*error++; |
0799 |
} |
0800 |
else |
0801 |
printf ( " passed.\n" ); |
0802 |
} |
0803 |
} |
0804 |
|
0805 |
/* Test unaligned writes */ |
0806 |
if (!ret_code) |
0807 |
{ |
0808 |
/* Erase the block */ |
0809 |
ret_code = alt_erase_flash_block(fd, test_offset, regions->block_size); |
0810 |
|
0811 |
/* Write the buffer to flash on an unaligned address. */ |
0812 |
printf ( " -Testing unaligned writes." ); |
0813 |
ret_code = alt_write_flash_block(fd, test_offset, (test_offset + 0x43), data_written, 100); |
0814 |
if (!ret_code) |
0815 |
{ |
0816 |
/* Now read it back into the read_buffer */ |
0817 |
ret_code = alt_read_flash(fd, (test_offset + 0x43), data_read, 100); |
0818 |
if (!ret_code) |
0819 |
{ |
0820 |
/* See if they match */ |
0821 |
if ( memcmp (data_written, data_read, 100)) |
0822 |
{ |
0823 |
printf ( " FAILED.\n" ); |
0824 |
*error++; |
0825 |
} |
0826 |
else |
0827 |
printf ( " passed.\n" ); |
0828 |
} |
0829 |
} |
0830 |
} |
0831 |
|
0832 |
/* Free up the buffers we allocated. */ |
0833 |
free (data_written); |
0834 |
free (data_read); |
0835 |
|
0836 |
return ret_code; |
0837 |
} |
0838 |
|
0839 |
|
0840 |
/****************************************************************** |
0841 |
* Function: FlashTestReadWrite |
0842 |
* |
0843 |
* Purpose: Tests that the functions alt_write_flash and |
0844 |
* alt_read_flash are working properly, as well as tests |
0845 |
* that every bit in the specified block can store both |
0846 |
* a '1' and '0'. |
0847 |
* |
0848 |
******************************************************************/ |
0849 |
static int FlashTestReadWrite( int block, int *error, alt_flash_fd* fd, flash_region* regions) |
0850 |
{ |
0851 |
int i; |
0852 |
int ret_code = 0x0; |
0853 |
int test_offset; |
0854 |
|
0855 |
alt_u8 *data_written; |
0856 |
alt_u8 *data_read; |
0857 |
|
0858 |
|
0859 |
/* Get a couple buffers for the tests */ |
0860 |
data_written = malloc (regions->block_size); |
0861 |
data_read = malloc (regions->block_size); |
0862 |
|
0863 |
/* Calculate the offset at which the block lives */ |
0864 |
test_offset = (regions->offset + (block * regions->block_size)); |
0865 |
|
0866 |
printf ( "\n -Starting Flash Test.\n" ); |
0867 |
|
0868 |
printf ( " -Testing \"alt_write_flash\" and \"alt_read_flash\".\n" ); |
0869 |
/* Fill buffer with incrementing values */ |
0870 |
for (i=0; i < regions->block_size; i++) |
0871 |
*(data_written + i) = i; |
0872 |
|
0873 |
/* Write the buffer to flash block */ |
0874 |
ret_code = alt_write_flash(fd, test_offset, data_written, regions->block_size); |
0875 |
|
0876 |
if (!ret_code) |
0877 |
{ |
0878 |
/* Read flash block into read buffer */ |
0879 |
ret_code = alt_read_flash(fd, test_offset, data_read, regions->block_size); |
0880 |
if (!ret_code) |
0881 |
{ |
0882 |
/* See if they match */ |
0883 |
if ( memcmp (data_written, data_read, regions->block_size)) |
0884 |
{ |
0885 |
printf ( " pass 1 - FAILED.\n" ); |
0886 |
*error++; |
0887 |
} |
0888 |
else |
0889 |
printf ( " pass 1 - passed.\n" ); |
0890 |
} |
0891 |
|
0892 |
/* Now fill the buffer with decrementing values (invert the incrementing ones) */ |
0893 |
for (i=0; i < regions->block_size; i++) |
0894 |
*(data_written + i) = ~((alt_u8)(i)); |
0895 |
|
0896 |
/* Write the buffer to flash block */ |
0897 |
ret_code = alt_write_flash(fd, test_offset, data_written, regions->block_size); |
0898 |
|
0899 |
if (!ret_code) |
0900 |
{ |
0901 |
/* Read flash block into read buffer */ |
0902 |
ret_code = alt_read_flash(fd, test_offset, data_read, regions->block_size); |
0903 |
if (!ret_code) |
0904 |
{ |
0905 |
/* See if they match */ |
0906 |
if ( memcmp (data_written, data_read, regions->block_size)) |
0907 |
{ |
0908 |
printf ( " pass 2 - FAILED.\n" ); |
0909 |
*error++; |
0910 |
} |
0911 |
else |
0912 |
printf ( " pass 2 - passed.\n" ); |
0913 |
} |
0914 |
} |
0915 |
if (*error) |
0916 |
ret_code = 1; |
0917 |
} |
0918 |
|
0919 |
/* Free up the buffers we allocated */ |
0920 |
free (data_written); |
0921 |
free (data_read); |
0922 |
|
0923 |
return ret_code; |
0924 |
} |
0925 |
|
0926 |
|
0927 |
/****************************************************************** |
0928 |
* Function: FlashTestBlockErase |
0929 |
* |
0930 |
* Purpose: Tests that the function alt_erase_flash_block is |
0931 |
* is working properly. Assumes that the specified |
0932 |
* flash block contains some non-0xFFFFFFFF data before |
0933 |
* this function is called. |
0934 |
* |
0935 |
******************************************************************/ |
0936 |
static int FlashTestBlockErase( int block, int *error, alt_flash_fd* fd, flash_region* regions) |
0937 |
{ |
0938 |
|
0939 |
int ret_code = 0x0; |
0940 |
int test_offset; |
0941 |
|
0942 |
/* Calculate the offset of the block */ |
0943 |
test_offset = (regions->offset + (block * regions->block_size)); |
0944 |
|
0945 |
printf ( " -Testing \"alt_erase_flash_block\"." ); |
0946 |
ret_code = alt_erase_flash_block(fd, test_offset, regions->block_size); |
0947 |
/* Check that the erase was successful. */ |
0948 |
if (!ret_code) |
0949 |
{ |
0950 |
if (FlashCheckIfBlockErased(fd, block, regions)) |
0951 |
printf ( " passed.\n" ); |
0952 |
else |
0953 |
{ |
0954 |
printf ( " FAILED\n" ); |
0955 |
*error++; |
0956 |
} |
0957 |
} |
0958 |
|
0959 |
return ret_code; |
0960 |
} |
0961 |
|
0962 |
|
0963 |
/****************************************************************** |
0964 |
* Function: FlashRunTests |
0965 |
* |
0966 |
* Purpose: Performs a full-test on the Flash specified. The tests |
0967 |
* run are: |
0968 |
* - alt_write_flash |
0969 |
* - alt_read_flash |
0970 |
* - alt_erase_flash_block |
0971 |
* - alt_write_flash_block |
0972 |
* |
0973 |
******************************************************************/ |
0974 |
static void FlashRunTests(alt_flash_fd* fd, int block, flash_region* regions) |
0975 |
{ |
0976 |
int ret_code = 0x0; |
0977 |
int error = 0x0; |
0978 |
int test_offset; |
0979 |
|
0980 |
/* Calculate the offset of the block */ |
0981 |
test_offset = (regions->offset + (block * regions->block_size)); |
0982 |
|
0983 |
/* Test reading and writing functions */ |
0984 |
ret_code = FlashTestReadWrite(block, &error, fd, regions); |
0985 |
|
0986 |
/* Test the erase function */ |
0987 |
if (!ret_code) |
0988 |
{ |
0989 |
ret_code = FlashTestBlockErase(block, &error, fd, regions); |
0990 |
} |
0991 |
/* Test the block write function */ |
0992 |
if (!ret_code) |
0993 |
{ |
0994 |
ret_code = FlashTestBlockWrite(block, &error, fd, regions); |
0995 |
} |
0996 |
|
0997 |
/* Erase the block so we dont fill one up each time we run the test */ |
0998 |
printf ( " -Returning block %d to its erased state.\n" , block); |
0999 |
alt_erase_flash_block(fd, test_offset, regions->block_size); |
1000 |
|
1001 |
printf ( " -Flash tests complete.\n" ); |
1002 |
if (ret_code || error) |
1003 |
{ |
1004 |
printf ( " -At least one test failed.\n\n" ); |
1005 |
} |
1006 |
} |
1007 |
|
1008 |
|
1009 |
/****************************************************************** |
1010 |
* Function: GetFlashName |
1011 |
* |
1012 |
* Purpose: Gets the name of the flash to test from the user |
1013 |
* Defaults to "/dev/ext_flash", the name of the flash |
1014 |
* component in the Nios II example designs. |
1015 |
* |
1016 |
******************************************************************/ |
1017 |
static int GetFlashName( char line[30], int flash_type) |
1018 |
{ |
1019 |
|
1020 |
char ch = 0x0; |
1021 |
int i; |
1022 |
|
1023 |
if (flash_type == CFI) |
1024 |
{ |
1025 |
printf ( "\nEnter the name of the CFI flash device to be opened,\n" ); |
1026 |
printf ( "or just press ); |
1027 |
printf ( ">" ); |
1028 |
} |
1029 |
else if (flash_type == EPCS) |
1030 |
{ |
1031 |
printf ( "\nEnter the name of the EPCS flash device to be opened,\n" ); |
1032 |
printf ( "or just press ); |
1033 |
printf ( ">" ); |
1034 |
} |
1035 |
|
1036 |
for (i = 0; ch != '\n' ; i++) |
1037 |
{ |
1038 |
ch = getc (stdin); |
1039 |
if (ch == '\r' || ch == '\n' ) |
1040 |
{ |
1041 |
/* Hitting |
1042 |
if ( i <= 1 ) |
1043 |
{ |
1044 |
if (flash_type == CFI) |
1045 |
strcpy (line, "/dev/ext_flash\0" ); |
1046 |
else if (flash_type == EPCS) |
1047 |
strcpy (line, "/dev/epcs_controller\0" ); |
1048 |
} |
1049 |
|
1050 |
else |
1051 |
/* Properly terminate the string. */ |
1052 |
line[i] = '\0' ; |
1053 |
} |
1054 |
else |
1055 |
line[i] = ch; |
1056 |
} |
1057 |
|
1058 |
return 0; |
1059 |
} |
1060 |
|
1061 |
|
1062 |
|
1063 |
/****************************************************************** |
1064 |
* Function: FlashErase |
1065 |
* |
1066 |
* Purpose: Erases 1 or all blocks in the specified flash device. |
1067 |
* |
1068 |
******************************************************************/ |
1069 |
static void FlashErase( int flash_type) |
1070 |
{ |
1071 |
alt_flash_fd* fd; |
1072 |
int test_offset; |
1073 |
int ret_code; |
1074 |
flash_region* regions; |
1075 |
int number_of_regions; |
1076 |
alt_u8 entry[4]; |
1077 |
alt_u8 flashname[30]; |
1078 |
unsigned int block; |
1079 |
|
1080 |
/* Get the name of the flash we are erasing */ |
1081 |
ret_code = GetFlashName(flashname, flash_type); |
1082 |
|
1083 |
fd = alt_flash_open_dev(flashname); |
1084 |
if (fd) |
1085 |
{ |
1086 |
/* Find out some useful stuff about the flash */ |
1087 |
ret_code = alt_get_flash_info(fd, ®ions, &number_of_regions); |
1088 |
if (!ret_code) |
1089 |
{ |
1090 |
printf ( " -Region has %d blocks.\n" , regions->number_of_blocks); |
1091 |
printf ( " -Which block would you like to erase?\n" ); |
1092 |
printf ( " -> " ); |
1093 |
|
1094 |
GetInputString( entry, sizeof (entry), stdin ); |
1095 |
|
1096 |
if (entry[0] == 'a' ) |
1097 |
{ |
1098 |
printf ( " -Erase ALL blocks? (y/n) " ); |
1099 |
|
1100 |
GetInputString( entry, sizeof (entry), stdin ); |
1101 |
|
1102 |
if (entry[0] == 'y' ) |
1103 |
{ |
1104 |
/* Erase all blocks */ |
1105 |
printf ( " -Erasing %d blocks. Please Wait.\n" , (regions->number_of_blocks)); |
1106 |
for (block = 0; block < regions->number_of_blocks; block++) |
1107 |
{ |
1108 |
/* Dont erase it if it's already erased silly. */ |
1109 |
if ((FlashCheckIfBlockErased(fd, block, regions)) == 0) |
1110 |
{ |
1111 |
test_offset = (regions->offset + (block * regions->block_size)); |
1112 |
alt_erase_flash_block(fd, test_offset, regions->block_size); |
1113 |
} |
1114 |
/* Just a simple progress meter so we dont get bored waiting for the flash to erase. */ |
1115 |
printf ( "." ); |
1116 |
if (((block + 1) % 80) == 0) |
1117 |
{ |
1118 |
printf ( "\n" ); |
1119 |
} |
1120 |
} |
1121 |
printf ( "\n -All Blocks Erased.\n" ); |
1122 |
} |
1123 |
else |
1124 |
{ |
1125 |
printf ( "Erased zero blocks.\n" ); |
1126 |
} |
1127 |
} |
1128 |
/* Just erase one block */ |
1129 |
if ( sscanf (entry, "%d\n" , &block)) |
1130 |
{ |
1131 |
if ((block >= 0) && (block <= (regions->number_of_blocks - 1))) |
1132 |
{ |
1133 |
test_offset = (regions->offset + (block * regions->block_size)); |
1134 |
alt_erase_flash_block(fd, test_offset, regions->block_size); |
1135 |
printf ( " -Block %d erased.\n" , block); |
1136 |
} |
1137 |
else |
1138 |
{ |
1139 |
printf ( " -Block number entered is %d\n" , block); |
1140 |
printf ( " -Block number must be between 0 and %d.\n" , (regions->number_of_blocks - 1)); |
1141 |
} |
1142 |
} |
1143 |
} |
1144 |
printf ( " -Closing flash \"%s\".\n" , flashname); |
1145 |
alt_flash_close_dev(fd); |
1146 |
} |
1147 |
} |
1148 |
|
1149 |
|
1150 |
/****************************************************************** |
1151 |
* Function: FlashFindErasedBlocks |
1152 |
* |
1153 |
* Purpose: Looks through the specified flash for blocks which |
1154 |
* are completely erased. If the mode parameter is |
1155 |
* TEST, this function simply returns the index of the |
1156 |
* first block which is completely erased. If the mode |
1157 |
* parameter is SHOWMAP, the function prints a list of |
1158 |
* all blocks, indicating which ones are erased. |
1159 |
* |
1160 |
******************************************************************/ |
1161 |
static int FlashFindErasedBlocks(alt_flash_fd* fd, flash_region* regions, int number_of_regions, int mode) |
1162 |
{ |
1163 |
int region_index, block_index; |
1164 |
int block_erased = 0x0; |
1165 |
alt_u8 entry[5]; |
1166 |
unsigned int block; |
1167 |
|
1168 |
/* Currently only supports flashes with 1 region, but region loop is left here for possible */ |
1169 |
/* future implementation */ |
1170 |
for (region_index = 0; region_index < number_of_regions; region_index++) |
1171 |
{ |
1172 |
printf ( " -Checking Region %d for erased blocks.\n" , region_index); |
1173 |
/* SHOWMAP mode has a legend reminding us what little plus and minus signs mean */ |
1174 |
if (mode == SHOWMAP) |
1175 |
{ |
1176 |
printf ( " erased block = '-'\n" ); |
1177 |
printf ( " unerased block = '+'\n\n" ); |
1178 |
} |
1179 |
/* Check those blocks. */ |
1180 |
for (block_index = 0; block_index < (regions->number_of_blocks); block_index++) |
1181 |
{ |
1182 |
block_erased = FlashCheckIfBlockErased(fd, block_index, regions); |
1183 |
/* If it's erased and were running in TEST mode, we're done */ |
1184 |
if (block_erased && (mode == TEST)) |
1185 |
break ; |
1186 |
/* If in SHOWMAP mode, mark block as either erased or not-erased. */ |
1187 |
else if (block_erased && (mode == SHOWMAP)) |
1188 |
printf ( " Block %3d @ 0x%8.8X:\t-\n" , block_index, (regions->offset + (block_index * regions->block_size))); |
1189 |
else if (!block_erased && (mode == SHOWMAP)) |
1190 |
printf ( " Block %3d @ 0x%8.8X:\t+\n" , block_index, (regions->offset + (block_index * regions->block_size))); |
1191 |
} |
1192 |
/* Special case if no blocks are erased (TEST mode only)*/ |
1193 |
if (( block_index == ( regions->number_of_blocks )) && ( mode == TEST )) |
1194 |
{ |
1195 |
printf ( " -Found no erased blocks. Please enter the number of the block\n" ); |
1196 |
printf ( " you would like to test. Enter 'q' to quit without testing flash.\n" ); |
1197 |
printf ( " -> " ); |
1198 |
|
1199 |
GetInputString( entry, sizeof (entry), stdin ); |
1200 |
|
1201 |
if (entry[0] == 'q' ) |
1202 |
{ |
1203 |
block_index = QUIT_WITHOUT_TESTING; |
1204 |
break ; |
1205 |
} |
1206 |
else if ( sscanf (entry, "%d\n" , &block)) |
1207 |
{ |
1208 |
if ((block >= 0) && (block <= (regions->number_of_blocks - 1))) |
1209 |
{ |
1210 |
block_index = block; |
1211 |
break ; |
1212 |
} |
1213 |
else |
1214 |
{ |
1215 |
printf ( " -Block number entered is %d\n" , block); |
1216 |
printf ( " -Block number must be between 0 and %d.\n" , (regions->number_of_blocks - 1)); |
1217 |
} |
1218 |
} |
1219 |
} |
1220 |
/* Break out of the region loop if we've found an erased block to test. */ |
1221 |
if (block_erased && (mode == TEST)) |
1222 |
break ; |
1223 |
} |
1224 |
|
1225 |
return block_index; |
1226 |
} |
1227 |
|
1228 |
|
1229 |
/****************************************************************** |
1230 |
* Function: TestFlash |
1231 |
* |
1232 |
* Purpose: Opens the specified flash device. If the mode |
1233 |
* parameter is TEST, the function finds an erased |
1234 |
* block, then tests it. If the mode parameter is |
1235 |
* SHOWMAP, the function lists all blocks in the flash and |
1236 |
* indicates which ones are erased. The flash is closed |
1237 |
* at the end of the function. |
1238 |
* |
1239 |
******************************************************************/ |
1240 |
static void TestFlash( int mode, int flash_type) |
1241 |
{ |
1242 |
alt_flash_fd* fd; |
1243 |
int number_of_regions; |
1244 |
int block; |
1245 |
flash_region* regions; |
1246 |
int ret_code = 0x0; |
1247 |
alt_u8 entry[4]; |
1248 |
alt_u8 flashname[30]; |
1249 |
|
1250 |
ret_code = GetFlashName(flashname, flash_type); |
1251 |
|
1252 |
fd = alt_flash_open_dev(flashname); |
1253 |
if (fd) |
1254 |
{ |
1255 |
printf ( " -Successfully opened %s\n" , flashname); |
1256 |
|
1257 |
/* Get some useful info about the flash */ |
1258 |
ret_code = alt_get_flash_info(fd, ®ions, &number_of_regions); |
1259 |
|
1260 |
if (!ret_code) |
1261 |
{ |
1262 |
printf ( " -Region 0 contains %d blocks.\n" , regions->number_of_blocks); |
1263 |
|
1264 |
block = FlashFindErasedBlocks(fd, regions, number_of_regions, mode); |
1265 |
|
1266 |
/* If we're in TEST mode, ask if this block is okay to test. */ |
1267 |
if (( mode == TEST ) && ( block != QUIT_WITHOUT_TESTING )) |
1268 |
{ |
1269 |
printf ( " -Block %d, at address 0x%X identified.\n" , block, (regions->offset + (block * regions->block_size))); |
1270 |
printf ( " -Would you like to test this block? (y/n)" ); |
1271 |
|
1272 |
GetInputString(entry, sizeof (entry), stdin); |
1273 |
|
1274 |
if ( entry[0] == 'y' && entry[1] == '\n' ) |
1275 |
{ |
1276 |
/* Test that Flash! */ |
1277 |
FlashRunTests(fd, block, regions); |
1278 |
printf ( " -Closing flash device \"%s\".\n" , flashname); |
1279 |
alt_flash_close_dev(fd); |
1280 |
} |
1281 |
} |
1282 |
} |
1283 |
} |
1284 |
else |
1285 |
{ |
1286 |
printf ( " -ERROR: Could not open %s\n" , flashname); |
1287 |
} |
1288 |
} |
1289 |
|
1290 |
|
1291 |
/****************************************************************** |
1292 |
* Function: TopMenu |
1293 |
* |
1294 |
* Purpose: Generates the top level menu. |
1295 |
* |
1296 |
******************************************************************/ |
1297 |
static int TopMenu( void ) |
1298 |
{ |
1299 |
char ch; |
1300 |
|
1301 |
/* Print the top-level menu to stdout */ |
1302 |
while (1) |
1303 |
{ |
1304 |
MenuBegin( " Memory Test Main Menu" ); |
1305 |
MenuItem( 'a' , "Test RAM" ); |
1306 |
MenuItem( 'b' , "Test Flash" ); |
1307 |
#ifdef EPCS_CONTROLLER_NAME |
1308 |
MenuItem( 'c' , "Test EPCS Serial Flash" ); |
1309 |
ch = MenuEnd( 'a' , 'c' ); |
1310 |
#else |
1311 |
ch = MenuEnd( 'a' , 'b' ); |
1312 |
#endif /* EPCS_CONTROLLER_NAME */ |
1313 |
|
1314 |
switch (ch) |
1315 |
{ |
1316 |
MenuCase( 'a' ,TestRam()); |
1317 |
MenuCase( 'b' ,TestFlash(TEST, CFI)); |
1318 |
MenuCase( 'e' ,FlashErase(CFI)); /* hidden option */ |
1319 |
MenuCase( 'm' ,TestFlash(SHOWMAP, CFI)); /* hidden option */ |
1320 |
#ifdef EPCS_CONTROLLER_NAME |
1321 |
MenuCase( 'c' ,TestFlash(TEST, EPCS)); |
1322 |
MenuCase( 'f' ,FlashErase(EPCS)); /* hidden option */ |
1323 |
MenuCase( 's' ,TestFlash(SHOWMAP, EPCS)); /* hidden option */ |
1324 |
#endif /* EPCS_CONTROLLER_NAME */ |
1325 |
case 'q' : break ; |
1326 |
default : printf ( "\n -ERROR: %c is an invalid entry. Please try again\n" , ch); break ; |
1327 |
} |
1328 |
if (ch == 'q' ) |
1329 |
break ; |
1330 |
printf ( "\nPress enter to continue...\n" ); |
1331 |
while ( (( ch = getc (stdin)) != '\n' ) && ( ch != EOF )); |
1332 |
|
1333 |
} |
1334 |
return (ch); |
1335 |
} |
1336 |
|
1337 |
|
1338 |
/****************************************************************** |
1339 |
* Function: main |
1340 |
* |
1341 |
* Purpose: Continually prints the menu and performs the actions |
1342 |
* requested by the user. |
1343 |
* |
1344 |
******************************************************************/ |
1345 |
int main( void ) |
1346 |
{ |
1347 |
|
1348 |
int ch; |
1349 |
|
1350 |
/* Print the Header */ |
1351 |
MenuHeader(); |
1352 |
/* Print the menu and do what the user requests, until they hit 'q' */ |
1353 |
while (1) |
1354 |
{ |
1355 |
ch = TopMenu(); |
1356 |
if (ch == 'q' ) |
1357 |
{ |
1358 |
printf ( "\nExiting from Memory Test.\n" ); |
1359 |
break ; |
1360 |
} |
1361 |
} |
1362 |
return (0); |
1363 |
} |
1364 |
|
1365 |
|
1366 |
/****************************************************************************** |
1367 |
* * |
1368 |
* License Agreement * |
1369 |
* * |
1370 |
* Copyright (c) 2004 Altera Corporation, San Jose, California, USA. * |
1371 |
* All rights reserved. * |
1372 |
* * |
1373 |
* Permission is hereby granted, free of charge, to any person obtaining a * |
1374 |
* copy of this software and associated documentation files (the "Software"), * |
1375 |
* to deal in the Software without restriction, including without limitation * |
1376 |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * |
1377 |
* and/or sell copies of the Software, and to permit persons to whom the * |
1378 |
* Software is furnished to do so, subject to the following conditions: * |
1379 |
* * |
1380 |
* The above copyright notice and this permission notice shall be included in * |
1381 |
* all copies or substantial portions of the Software. * |
1382 |
* * |
1383 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * |
1384 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * |
1385 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * |
1386 |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * |
1387 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * |
1388 |
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * |
1389 |
* DEALINGS IN THE SOFTWARE. * |
1390 |
* * |
1391 |
* This agreement shall be governed in all respects by the laws of the State * |
1392 |
* of California and by the laws of the United States of America. * |
1393 |
* Altera does not recommend, suggest or require that this reference design * |
1394 |
* file be used in conjunction or combination with any other product. * |
1395 |
******************************************************************************/ |
参考
1. Altera.Nios II Software Developer's Handbook