|
楼主 |
发表于 2008-10-30 13:25:39
|
显示全部楼层
//JFLASH V1.2
#define VERSION "1.2"
#include <stdio.h>
#include <windows.h>
#include <time.h>
#include <conio.h>
#include "sa1110jtag.h"
#define LPT1 0x3bc // hardware base address for parallel port
#define LPT2 0x378 // the search order is LPT1 then 2 then 3
#define LPT3 0x278 // first valid address found is used (re-order if needed for multiple ports)
#define SA1110ID "**** 1001001001100001 00000001001 1" // JTAG ID-codes for the SA-1110
#define XCR3032XLID "**** 0100100000001110 00001001001 1" // support both the 'A' and non 'A' versions of the part
#define READ 0 // Flags used to modify the SA-1110 JTAG chain data depending on
#define WRITE 1 // the access mode of the Flash Memory
#define SETUP 2
#define HOLD 3
#define RS 4
#define IP 0 // Flag used when accessing the parallel port
#define RP 1 // RP = 'read port', IP = 'ignore port', using IP will speed access
#define MAX_IN_LENGTH 100 // max length for user input strings
#define STATUS_UPDATE 0.1 // time between updates of program/verify status in seconds
int lpt_address; // Global variable assigned to parallel port address
FILE *in_file;
int putp(int,int, int); // writes the JTAG data on the parallel port
void id_command(void); // issues the JTAG command to read the device ID for all 3 chips
void bypass_all(void); // issues the JTAG command to put all 3 device in bypass mode
void extest(void); // issues the JTAG command EXTEST to the SA-1110
DWORD access_rom(int, DWORD, DWORD, int); // Passes read/write/setup data for the Flash memory
DWORD access_bus(int, DWORD, DWORD, int); // Read/write access to the SA-1110 pins
int test_port(void); // Looks for and finds a valid parallel port address
int check_id(char*); // Compares the device IDs for the 3 JTAG chips to expected values
void error_out(char*); // Prints error and exits program
void erase_flash(DWORD, DWORD, DWORD, DWORD, int);
void program_flash(DWORD, DWORD, DWORD);
void verify_flash(DWORD, DWORD);
void read_flash(DWORD, DWORD);
void test_logic_reset(void);
void test_lock_flash(DWORD, DWORD, DWORD, DWORD, int);
void set_lock_flash(DWORD, DWORD, DWORD, DWORD, int);
int main( int argc, char *argv[] )
{
time_t start;
printf("JFLASH Version %s\n",VERSION);
//Test operating system, if WinNT or Win2000 then get device driver handle
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
HANDLE h;
h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(h == INVALID_HANDLE_VALUE)
error_out("Couldn't access giveio device");
CloseHandle(h);
}
lpt_address = test_port(); // find a valid parallel port address
if(!lpt_address)
error_out("Error, unable to find parallel port");
char filename[MAX_IN_LENGTH];
if(argc>= 2)
strcpy_s(filename,argv[1]);
else
{
printf("enter binary file name: ");
gets_s(filename);
}
test_logic_reset();
id_command();
bypass_all();
access_rom(SETUP, 0, 0x500050L, IP); // clear status register
access_rom(WRITE, 0, 0x500050L, IP);
access_rom(HOLD, 0, 0x500050L, IP);
access_rom(SETUP, 0, 0x980098L, IP); // read query
access_rom(WRITE, 0, 0x980098L, IP);
access_rom(HOLD, 0, 0x980098L, IP);
// To read data from the Flash Memory you must first fill the SA-1110 JTAG chain
// with the Address, then pump the entire chain out.
// however while pumping data out you can be pumping the next cycle's Address in
// Therefore the JTAG chain looks like a pipeline, valid read data always coming
// out one cycle late.
// Note that both Flash Memory devices are accessed in parallel (i.e. 32 data bits)
access_rom(READ, 0x10, 0, IP); // Test to see if the Flash supports Query Structured Output
if(access_rom(READ, 0x11, 0, RP) != 0x510051L) //Q
error_out("error reading flash attribute space\ncheck cables, power and flash sockets");
if(access_rom(READ, 0x12, 0, RP) != 0x520052L) //R
error_out("error reading flash attribute space R");
if(access_rom(READ, 0x25, 0, RP) != 0x590059L) //Y
error_out("error reading flash attribute space Y\n");
DWORD max_erase_time = access_rom(READ, 0x27, 0, RP); // "n" such that the max block erase time = 2^n
if((max_erase_time & 0xffffL) != (max_erase_time>> 16)) // both devices should be the same time
error_out("error, max erase time of E11 and E12 are different");
max_erase_time = 1 << (max_erase_time & 0xffffL); // convert erase time 2^n to the number of seconds
DWORD dsize = access_rom(READ, 0x2a, 0, RP); // "n" such that the device size = 2^n in number of bytes
if((dsize & 0xffffL) != (dsize>> 16)) // both devices should be the same size
error_out("error, device size of E11 and E12 are different");
dsize = 1 << (dsize & 0xffffL); // convert data size from 2^n to the number of bytes
DWORD max_write_buffer = access_rom(READ, 0x2d, 0, RP); // "n" such that the max num of bytes in write buffer = 2^n
if((max_write_buffer & 0xffffL) != (max_write_buffer>> 16)) // both devices should have the same write buffer size
error_out("error, write buffer size of E11 and E12 are different");
max_write_buffer = (1 << (max_write_buffer & 0xffffL)) / 2; // convert from 2^n bytes to the number of words
int nblocks = access_rom(READ, 0x2e, 0, RP); // get the number of erase blocks in Flash - 1
if((nblocks & 0xffffL) != (nblocks>> 16)) // both devices should have the same number
error_out("error, number of blocks of E11 and E12 are different");
nblocks = (nblocks & 0xffffL) + 1L; // need to add '1' for true number
int block_number = 0;
DWORD block_size = dsize / 2 / nblocks;
printf("Number of blocks in device = %ld\n",nblocks);
printf("Block size = %ld 0x%lx\n",block_size,block_size);
printf("Device size = %ld 0x%lx\n",dsize,dsize);
if(argc>= 4)
block_number = atoi(argv[3]);
DWORD base_address = block_number * block_size;
if(block_number>= nblocks || block_number < 0)
error_out("error specifying block number");
if(argc>= 5)
block_number = atoi(argv[4]);
DWORD rsize = block_number * block_size;
if(block_number> nblocks || block_number < 0)
error_out("error specifying block number");
char option = 'R';
if(argc>= 3)
option = toupper(*argv[2]);
if(option == 'R')
{
fopen_s(&in_file,filename, "wb" );
if( in_file == NULL)
error_out("error, can not open binary input file");
access_rom(SETUP, 0, 0xff00ffL, IP); // put back into read mode
access_rom(WRITE, 0, 0xff00ffL, IP);
access_rom(HOLD, 0, 0xff00ffL, IP);
access_rom(READ, base_address, 0x0L, IP); //extra read to get the pipeline going
time(&start);
read_flash(base_address, rsize);
fclose(in_file);
}
if(option == 'P')
{
DWORD fsize = 0;
DWORD last_non_zero = 0 ;
DWORD last_non_ff = 0;
DWORD li;
fopen_s(&in_file,filename, "rb" );
if( in_file == NULL)
error_out("error, can not open binary input file");
for(;;)
{
int n = fread((DWORD *)&li, sizeof(DWORD) , 1, in_file);
if(feof(in_file))break; // Any bytes not on a 4 byte boundry at end-of-file will be ignored
fsize++;
if(li != 0 && li != 0xffffffff) // Find point in file were only 0's and ff's remain
last_non_zero = fsize;
if(li != 0xffffffff) // Find point in file were only ff's remain
last_non_ff = fsize;
}
rewind(in_file);
if(fsize * 2> dsize)
error_out("error, file size is bigger than device size");
fsize = last_non_ff; // Don't wast time programming ff's at the end of the file this is the erase state
if(100 - (last_non_zero * 100)/last_non_ff> 20)
{
printf("The last %2ld percent of image file is all zeros\n",100 - (last_non_zero * 100)/last_non_ff);
printf("Would you like to save time by not programming that area? [y/n]: ");
if(toupper(_getche()) == 'Y')
fsize = last_non_zero;
}
printf("\n");
test_lock_flash(base_address, fsize, block_size, max_erase_time, block_number);
erase_flash(base_address, fsize, block_size, max_erase_time, block_number);
program_flash(max_write_buffer, base_address, fsize);
access_rom(SETUP, 0, 0xff00ffL, IP); // put back into read mode
access_rom(WRITE, 0, 0xff00ffL, IP);
access_rom(HOLD, 0, 0xff00ffL, IP);
access_rom(READ, base_address, 0x0L, IP); //extra read to get the pipeline going
time(&start);
verify_flash(base_address, fsize);
fclose(in_file);
}
test_logic_reset();
}
int putp(int tdi, int tms, int rp)
{
// Cable used had 100 ohm resistors between the following pins
// (Cable shipped as part of SA-1110 Development Kit)
// Output pins (LPT driving)
// LPT D0 Pin 2 and TCK J10 Pin 4
// LPT D1 Pin 3 and TDI J10 Pin 11
// LPT D2 Pin 4 and TMS J10 Pin 9
//
// Input pin (SA-1110 board drives)
// LPT Busy Pin 11 and TDO J10 Pin 13
int tdo = -1;
_outp(lpt_address, tms*4+tdi*2); // TCK low
_outp(lpt_address, tms*4+tdi*2+1); // TCK high
if(rp == RP)_outp(lpt_address, tms*4+tdi*2); // TCK low
if(rp == RP)tdo = !((int)_inp(lpt_address + 1)>> 7); // get TDO data
return tdo;
}
void id_command(void)
{
putp(1,0,IP); //Run-Test/Idle;使JTAG复位
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,1,IP);
putp(1,1,IP); //select IR scan;选择指令寄存器
putp(1,0,IP); //capture IR;捕获指令寄存器
putp(1,0,IP); //shift IR;移位指令寄存器
putp(0,0,IP); //SA1110 IDCODE;SA1110JTAG口指令长度5位,IDCODE为00110
putp(1,0,IP); //
putp(1,0,IP); //
putp(0,0,IP); //
putp(0,0,IP); //
putp(1,0,IP); //XCR3032 IDCODE为00001
putp(0,0,IP); //
putp(0,0,IP); //
putp(0,0,IP); //
putp(0,0,IP); //
putp(1,0,IP); //XCR3032 IDCODE
putp(0,0,IP); //
putp(0,0,IP); //
putp(0,0,IP); //
putp(0,1,IP); //Exit1-IR;退出指令寄存器
putp(1,1,IP); //Update-IR;更新指令寄存器,执行指令寄存器中的指令
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,1,IP);
putp(1,0,IP);
if(check_id(SA1110ID))
error_out("failed to read device ID for the SA-1110");
if(check_id(XCR3032XLID))
error_out("failed to read device ID for the XCR3032XL");
if(check_id(XCR3032XLID))
error_out("failed to read device ID for the XCR3032XL");
putp(1,1,IP); //Exit1-DR;退出数据寄存器
putp(1,1,IP); //Update-DR;更新数据寄存器
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
}
void bypass_all(void)
{
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,1,IP);
putp(1,1,IP); //select IR scan
putp(1,0,IP); //capture IR
putp(1,0,IP); //shift IR
putp(1,0,IP); //SA1110 BYPASS
putp(1,0,IP); //
putp(1,0,IP); //
putp(1,0,IP); //
putp(1,0,IP); //
putp(1,0,IP); //XCR3032 BYPASS
putp(1,0,IP); //
putp(1,0,IP); //
putp(1,0,IP); //
putp(1,0,IP); //
putp(1,0,IP); //XCR3032 BYPASS
putp(1,0,IP); //
putp(1,0,IP); //
putp(1,0,IP); //
putp(1,1,IP); //Exit1-IR
putp(1,1,IP); //Update-IR
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
}
void extest(void)
{
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,1,IP);
putp(1,1,IP); //select IR scan
putp(1,0,IP); //capture IR
putp(1,0,IP); //shift IR
putp(0,0,IP); //SA1110 extest
putp(0,0,IP); //
putp(0,0,IP); //
putp(0,0,IP); //
putp(0,0,IP); //
putp(1,0,IP); //XCR3032 BYPASS
putp(1,0,IP); //
putp(1,0,IP); //
putp(1,0,IP); //
putp(1,0,IP); //
putp(1,0,IP); //XCR3032 BYPASS
putp(1,0,IP); //
putp(1,0,IP); //
putp(1,0,IP); //
//putp(1,0,IP); //
putp(1,1,IP); //Exit1-IR
putp(1,1,IP); //Update-IR
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
}
DWORD access_rom(int rw, DWORD address, DWORD data, int rp)
{
// Shift Flash address making A2 the LSB
return(access_bus(rw, address << 2, data, rp));
}
DWORD access_bus(int rw, DWORD address, DWORD data, int rp)
{
// Preset SA-1110 pins to default values (all others set in sa1110jtag.h)
pin[nCS0_OUT] = 1;
pin[nCS1_OUT] = 1;
pin[nCS2_OUT] = 1;
pin[nCS3_OUT] = 1;
pin[nCS4_OUT] = 1;
pin[nCS5_OUT] = 1;
pin[nOE_OUT] = 0;
pin[nWE_OUT] = 1;
pin[RD_nWR_OUT] = 0;
pin[D31_0_EN] = 1;
for(int i = 0; i < 26; i++)
pin[i+28] = (int)((address>> i) & 1); // set address 0 thru 25
if(rw == READ)
{
pin[RD_nWR_OUT] = 1;
switch(address>> 27)
{
case 0:{pin[nCS0_OUT] = 0; break;}
case 1:{pin[nCS1_OUT] = 0; break;}
case 2:{pin[nCS2_OUT] = 0; break;}
case 3:{pin[nCS3_OUT] = 0; break;}
case 4:{pin[nCS4_OUT] = 0; break;}
case 5:{pin[nCS5_OUT] = 0; break;}
}
}
if(rw == WRITE)
{
pin[nWE_OUT] = 0;
pin[nOE_OUT] = 1;
pin[D31_0_EN] = 0; // switch data pins to drive
switch(address>> 27) // set CS pin for corresponding address
{
case 0:{pin[nCS0_OUT] = 0; break;}
case 1:{pin[nCS1_OUT] = 0; break;}
case 2:{pin[nCS2_OUT] = 0; break;}
case 3:{pin[nCS3_OUT] = 0; break;}
case 4:{pin[nCS4_OUT] = 0; break;}
case 5:{pin[nCS5_OUT] = 0; break;}
}
for(DWORD li = 0L; li < 32L; li++)
pin[dat_order[li]] = (int)((data>> li) & 1L); // set data pins
}
if(rw == SETUP || rw == HOLD) // just like a write except WE, WE needs setup time
{
pin[nOE_OUT] = 1;
pin[D31_0_EN] = 0;
for(DWORD li = 0L; li < 32L; li++)
pin[dat_order[li]] = (int)((data>> li) & 1L); // serialize data pins
}
if(rw == RS) // setup prior to RD_nWR_OUT
{
pin[nOE_OUT] = 1;
}
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,1,IP); //select DR scan
putp(1,0,IP); //capture DR
putp(1,0,IP); //shift IR
int out_dat[300];
for(int i = 0; i < 291; i++) // shift write data in to JTAG port and read data out
out_dat = putp(pin,0,rp);
putp(0,0,IP);
putp(0,0,IP);
putp(0,1,IP); //Exit1-DR
putp(1,1,IP); //Update-DR
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
putp(1,0,IP); //Run-Test/Idle
DWORD busdat = 0;
for(int i = 0; i < 32; i++) // convert serial data to single DWORD
{
busdat = busdat | (DWORD)(out_dat[dat_order - 2] << i);
}
extest();
return(busdat);
}
int test_port(void)
{
// search for valid parallel port
_outp(LPT1, 0x55);
if((int)_inp(LPT1) == 0x55)return LPT1;
_outp(LPT2, 0x55);
if((int)_inp(LPT2) == 0x55)return LPT2;
_outp(LPT1, 0x55);
if((int)_inp(LPT3) == 0x55)return LPT3;
return(0); // return zero if none found
}
int check_id(char *device_id)
{
// compare passed device ID to the one returned from the ID command
char in_id[40];
BOOL error_flag = FALSE;
for(int i = 34; i>= 0; i--)
{
if(i == 4 || i == 21 || i == 33)
{
in_id = ' ';
i--;
}
if(putp(1,0,RP) == 0)
in_id = '0';
else
in_id = '1';
if((in_id != *(device_id + i)) && (*(device_id + i) != '*'))
{
error_flag = TRUE;
}
}
in_id[35] = 0;
if(error_flag)
{
printf("error, failed to read device ID\n");
printf("check cables and power\n");
printf("ACT: %s\n",in_id);
printf("EXP: %s\n\n",device_id);
return -1;
}
if(!strcmp(device_id,SA1110ID)) // print SA-1110 device revision
{
int sa_rev =
(int)(in_id[0] - '0') * 8 +
(int)(in_id[1] - '0') * 4 +
(int)(in_id[2] - '0') * 2 +
(int)(in_id[3] - '0');
switch(sa_rev)
{
case 0: printf("SA-1110 revision A0\n"); break;
case 4: printf("SA-1110 revision B0\n"); break;
case 5: printf("SA-1110 revision B1\n"); break;
case 6: printf("SA-1110 revision B2\n"); break;
case 8: printf("SA-1110 revision B4\n"); break;
default: printf("SA-1110 revision B4 + %d\n",sa_rev - 8);
}
}
return 0;
}
void error_out(char *error_string)
{
printf("%s\n",error_string);
exit(0);
}
void erase_flash(DWORD base_address, DWORD fsize, DWORD block_size, DWORD max_erase_time, int block_number)
{
time_t start, now;
printf("Starting erase\n");
for(DWORD lj = base_address; lj < fsize + base_address; lj = lj + block_size) // Erase only blocks to be programmed
{
access_rom(SETUP, 0, 0x200020L, IP); // Erase block command
access_rom(WRITE, 0, 0x200020L, IP);
access_rom(HOLD, 0, 0x200020L, IP);
access_rom(SETUP, lj, 0xd000d0L, IP); // Erase confirm at the block address
access_rom(WRITE, lj, 0xd000d0L, IP);
access_rom(HOLD, lj, 0xd000d0L, IP);
time(&start);
printf("Erasing block %3d \r",block_number++);
while(access_rom(RS, 0, 0, RP) != 0x800080L) // Loop until successful status return
{
access_rom(READ, 0, 0, RP);
time(&now);
if(difftime(now,start)> max_erase_time + 1) // Check for erase timeout
error_out("Error, Block erase timed out");
}
}
printf("Erasing done \n");
}
void program_flash(DWORD max_write_buffer, DWORD base_address, DWORD fsize)
{
time_t start, now;
DWORD li;
printf("Starting programming\n");
// "Write Buffer" flow.
// This uses almost half the cycles required by "word programming" flow
// Status register is not read to save time. There is also no checking to see
// if maximum "Write Buffer Program Time" is violated. However even with the
// fastest parallel port bus speed this should not be a problem
// (i.e. 16 words * 300 JTAG chain length * 4 parallel port cycles * 1uS fast
// parallel port cycle = 19mS, typical write buffer program times are in the 200uS range).
DWORD write_word_count = (max_write_buffer - 1) + ((max_write_buffer - 1) << 16);
time(&start);
for(DWORD lj = base_address; lj < fsize + base_address; lj = lj + max_write_buffer)
&nb |
|