502 lines
12 KiB
Plaintext
Executable File
502 lines
12 KiB
Plaintext
Executable File
program nmflash;
|
|
|
|
{$IFDEF WINDOWS}
|
|
uses synaser,synautil,synaip,blcksock,dos,crt;
|
|
var
|
|
ser:TBlockSerial;
|
|
TheComPort : string;
|
|
IPAddr : string;
|
|
Socket : TUDPBlockSocket;
|
|
{$ELSE}
|
|
uses dos,crt;
|
|
var TheComPort : word;
|
|
{$ENDIF}
|
|
|
|
{$I SELECTC}
|
|
{$I SELECTIO}
|
|
{I SELECTP}
|
|
{$I SELECTPR}
|
|
{$I INTERFCE}
|
|
|
|
const
|
|
DataStride = 4; {bytes}
|
|
|
|
procedure Error(err : integer);
|
|
begin
|
|
writeln(errorrecord[err].errstr);
|
|
halt(2);
|
|
end;
|
|
|
|
procedure Barfout(es:string);
|
|
begin
|
|
writeln;
|
|
writeln(es);
|
|
halt(2);
|
|
end;
|
|
|
|
type
|
|
configfile = file;
|
|
|
|
const
|
|
|
|
FileBufferSize = 8192;
|
|
PageSize = 256;
|
|
SPICSPort = $70;
|
|
SPISregPort = $74;
|
|
DAVMask = $04;
|
|
FallbackSA = $10000; { fallback start address is sector 1 }
|
|
BootSA = $00000; { boot start address is sector 0 }
|
|
BBSize = 64;
|
|
NSAMSBOffset = 25; { offset of Normal Start Address MS Byte in boot block }
|
|
CBootBlock : array[0..BBSize-1] of byte = ($FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,
|
|
$FF,$FF,$AA,$99,$55,$66,$31,$E1,
|
|
$FF,$FF,$32,$61,$00,$00,$32,$81,
|
|
$0B,$08,$32,$A1,$00,$00,$32,$C1,
|
|
$0B,$01,$30,$A1,$00,$00,$33,$01,
|
|
$21,$00,$32,$01,$00,$1F,$30,$A1,
|
|
$00,$0E,$20,$00,$20,$00,$20,$00,
|
|
$20,$00,$20,$00,$20,$00,$20,$00);
|
|
|
|
var
|
|
BootBlock : array[0..BBSize-1] of byte;
|
|
NormalSA : longint; { normal start address is 1/2 way up }
|
|
NSAMSB : byte;
|
|
VerifyOnly : boolean;
|
|
CardNumber : word;
|
|
Parms : word;
|
|
StartAddress : longint;
|
|
|
|
|
|
FileName : string;
|
|
CFile : configfile;
|
|
CFileSize : longint;
|
|
Timeout : longint;
|
|
Fallback : boolean;
|
|
BBuf: array[0..FileBufferSize-1] of byte;
|
|
|
|
function OpenForRead(var fp: configfile; name: string): boolean;
|
|
begin
|
|
Assign(fp,Name);
|
|
{$I-}
|
|
Reset(fp,1);
|
|
{$I+}
|
|
OpenForRead := IOResult = 0;
|
|
end { Open };
|
|
|
|
procedure Usage;
|
|
begin
|
|
writeln;
|
|
writeln(' NMFLASH - Writes config data to 5I24/5I25/6I25/7I90 EEPROM');
|
|
writeln;
|
|
writeln(' USAGE - NMFLASH file [V]');
|
|
writeln(' Where file is a VALID FPGA configuration file');
|
|
writeln(' Trailing V invoke Verify only option');
|
|
halt(2);
|
|
end;
|
|
|
|
procedure SetCSHigh;
|
|
begin
|
|
Write32(BaseAddr+SPICSPort,1);
|
|
end;
|
|
|
|
procedure SetCSLow;
|
|
begin
|
|
Write32(BaseAddr+SPICSPort,0);
|
|
end;
|
|
|
|
function WaitForSPIData : boolean;
|
|
var
|
|
loops: integer;
|
|
data : longint;
|
|
begin
|
|
data := 0;
|
|
loops := 0;
|
|
while ((data and DAVMask) = 0) and (loops < 5000) do
|
|
begin
|
|
data := Read32(BaseAddr+SPICSPort);
|
|
loops := loops +1;
|
|
end;
|
|
if loops = 5000 then WaitForSPIData := false else WaitForSPIData := true;
|
|
end;
|
|
|
|
procedure SendSPIByte( d: byte);
|
|
begin
|
|
Write32(BaseAddr+SPISRegPort,d);
|
|
if not WaitForSPIData then BarfOut('Timeout waiting for SPI Shift Register');
|
|
end;
|
|
|
|
|
|
function RecvSPIByte(d: byte) : byte;
|
|
var
|
|
data: longint;
|
|
begin
|
|
Write32(BaseAddr+SPISRegPort,d);
|
|
if not WaitForSPIData then BarfOut('Timeout waiting for SPI Shift Register');
|
|
data := Read32(BaseAddr+SPISRegPort);
|
|
RecvSPIByte := byte(data and $FF);
|
|
end;
|
|
|
|
|
|
{$I 25Mlowp.pas }
|
|
|
|
procedure Dump(sa:longint);
|
|
var
|
|
index : longint;
|
|
|
|
begin
|
|
for index := sa to sa+255 do
|
|
begin
|
|
if (index and 15) = 0 then
|
|
begin
|
|
writeln;
|
|
Hexprint(index,8);
|
|
write(': ');
|
|
end;
|
|
Hexprint(ReadByte25(index),2);
|
|
write(' ');
|
|
end;
|
|
writeln;
|
|
end;
|
|
|
|
procedure WriteBlock(add:longint;bufidx:word);
|
|
var
|
|
index : word;
|
|
|
|
begin
|
|
WriteEnable25;
|
|
Prefix25;
|
|
PutByte25(PageProgCom);
|
|
PutAddress25(add); { note that add 0..7 should be 0}
|
|
for index := 0 to PageSize -1 do
|
|
begin
|
|
PutByte25(BBuf[bufidx+index]);
|
|
end;
|
|
Suffix25;
|
|
WaitForWrite25;
|
|
end;
|
|
|
|
function NextByte(n: byte) : byte;
|
|
var
|
|
index,abyte : byte;
|
|
bytesread : word;
|
|
begin
|
|
for index := 1 to n do Blockread((CFile),abyte,1,bytesread);
|
|
NextByte := abyte;
|
|
end;
|
|
|
|
function ReadString : string;
|
|
var
|
|
sleng,count : word;
|
|
tstring : string;
|
|
abyte: byte;
|
|
begin
|
|
sleng := NextByte(1) * 256;
|
|
sleng := sleng + NextByte(1);
|
|
if (sleng > 255) then sleng := 255;
|
|
tstring := '';
|
|
for count := 1 to sleng do
|
|
begin
|
|
abyte := NextByte(1);
|
|
if (abyte <> 0) then tstring := tstring + chr(abyte);
|
|
end;
|
|
ReadString := tstring;
|
|
end;
|
|
|
|
procedure PrintBitFileHeader;
|
|
var
|
|
sleng,bytesread : word;
|
|
tstring : string;
|
|
conflength : longint;
|
|
fbyte : byte;
|
|
ft : (bit,bin,unk);
|
|
begin
|
|
ft := unk;
|
|
if (NextByte(1) = 0) then
|
|
begin
|
|
if (Nextbyte(1) = 9) then
|
|
begin
|
|
writeln('Looks like a BIT file');
|
|
fbyte := NextByte(9); {skip over 9 header bytes}
|
|
if (NextByte(1) = 0) then
|
|
begin
|
|
if (NextByte(1) = 1) then
|
|
begin
|
|
if (NextByte(1) = $61) then
|
|
begin
|
|
writeln('Design name: ',ReadString);
|
|
fbyte := NextByte(1); {Skip over 'b'}
|
|
writeln('Part name: ',ReadString);
|
|
fbyte := NextByte(1); {Skip over 'c'}
|
|
writeln('Design date: ',ReadString);
|
|
fbyte := NextByte(1); {Skip over 'd'}
|
|
writeln('Design time: ',ReadString);
|
|
fbyte := NextByte(1);; {Skip over 'e'}
|
|
conflength := longint(NextByte(1))*16777216;
|
|
conflength := conflength +longint(NextByte(1))*65536;
|
|
conflength := conflength +longint(NextByte(1))*256;
|
|
conflength := conflength +longint(NextByte(1));
|
|
writeln('Config Length: ',conflength);
|
|
ft := bit;
|
|
end; {valid bitfile header}
|
|
end;
|
|
end;
|
|
end; {starting to look like a bit file }
|
|
end; {looks like a bit file}
|
|
if ft = unk then
|
|
begin
|
|
if (NextByte(1) = $FF) and (NextByte(1) = $FF) and (NextByte(1) = $FF) and (NextByte(1) = $FF) then
|
|
begin
|
|
writeln('Looks like a BIN file');
|
|
Reset(Cfile,1);
|
|
ft := bin;
|
|
end;
|
|
end;
|
|
if ft = unk then
|
|
begin
|
|
writeln('Invalid bitfile header!');
|
|
halt(2);
|
|
end;
|
|
end;
|
|
|
|
procedure GetParms;
|
|
var
|
|
thefile : string;
|
|
begin
|
|
Fallback := false;
|
|
VerifyOnly := false;
|
|
if ParamCount < 1 then Usage;
|
|
thefile := paramStr(1);
|
|
FileName := thefile;
|
|
if Length(ParamStr(2)) <> 0 then
|
|
begin
|
|
if UpString(ParamStr(2)) = 'V' then VerifyOnly := true;
|
|
end;
|
|
if Length(ParamStr(3)) <> 0 then
|
|
begin
|
|
if UpString(ParamStr(3)) = 'V' then VerifyOnly := true;
|
|
end;
|
|
if Length(ParamStr(2)) <> 0 then
|
|
begin
|
|
if (ParamStr(2)) = 'FallBack' then Fallback := true;
|
|
end;
|
|
if Length(ParamStr(3)) <> 0 then
|
|
begin
|
|
if (ParamStr(3)) = 'FallBack' then Fallback := true;
|
|
end;
|
|
if not OpenForRead(CFile,FileName) then
|
|
begin
|
|
writeln('Can''t open configuration file');
|
|
halt(2);
|
|
end;
|
|
end;
|
|
|
|
procedure IdentifyEEPROM;
|
|
var
|
|
eepromid : byte;
|
|
begin
|
|
SetCSHigh;
|
|
eepromid:= ReadID25;
|
|
if (eepromid <> OneMegID) and (eepromid <> TwoMegID) and
|
|
(eepromid <> FourMegID) and (eepromid <> EightMegID) and
|
|
(eepromid <> SixteenMegID) then
|
|
begin
|
|
write('Bad EEPROM ID, expected ');
|
|
HexPrint(FourMegID,2);
|
|
write(' or ');
|
|
HexPrint(EightMegID,2);
|
|
write(' or ');
|
|
HexPrint(SixteenMegID,2);
|
|
write(' but got ');
|
|
HexPrint(eepromid,2);
|
|
writeln;
|
|
halt(2);
|
|
end;
|
|
if eepromid = FourMegID then
|
|
begin
|
|
writeln('4M Bit EEPROM Found');
|
|
NormalSA := $40000;
|
|
end;
|
|
if eepromid = EightMegID then
|
|
begin
|
|
writeln('8M Bit EEPROM Found');
|
|
NormalSA := $80000;
|
|
end;
|
|
if eepromid = SixteenMegID then
|
|
begin
|
|
writeln('16M Bit EEPROM Found');
|
|
NormalSA := $100000;
|
|
end;
|
|
NSAMSB := (NormalSA shr 16);
|
|
end;
|
|
|
|
procedure MakeBootBlock;
|
|
var index : word;
|
|
begin
|
|
for index := 0 to BBSize -1 do BootBlock[index] := CBootBlock[index];
|
|
BootBlock[NSAMSBOffset] := NSAMSB; { insert top address byte to match EEPROM size }
|
|
end;
|
|
|
|
procedure StartProgramming(sa: longint);
|
|
var
|
|
sectorsize,esectors,sector,secadd,esspace : longint;
|
|
begin
|
|
SetCSHigh;
|
|
sectorsize := 65536;
|
|
esspace := (NormalSA div sectorsize);
|
|
if sa = FallBackSA then esspace := esspace - 1;
|
|
writeln('About to erase EEPROM sectors => ');
|
|
esectors := (CFilesize-1) div sectorsize;
|
|
if esectors > esspace then BarfOut('File Size too large to fit');
|
|
secadd := sa;
|
|
for sector := 0 to esectors do
|
|
begin
|
|
EraseSector25(secadd);
|
|
secadd := secadd + sectorsize;
|
|
write('Sector ',sector+(sa div sectorsize),' erased ',chr(13));
|
|
end;
|
|
writeln;
|
|
if sa = FallBackSA then
|
|
writeln('Fallback area of EEPROM erased')
|
|
else
|
|
writeln('Configuration area of EEPROM erased');
|
|
SetCSHigh;
|
|
end;
|
|
|
|
procedure DoneProgramming;
|
|
begin
|
|
SetCSHigh;
|
|
end;
|
|
|
|
procedure VerifyIt;
|
|
var
|
|
index,bindex : longint;
|
|
bytesread : word;
|
|
rdata : byte;
|
|
begin
|
|
if OpenForRead(CFile,FileName) then
|
|
begin
|
|
IdentifyEEPROM;
|
|
reset(CFile,1);
|
|
CFileSize := FileSize(CFile);
|
|
PrintBitFileHeader;
|
|
if Fallback then index := FallbackSA else index := NormalSA;
|
|
while not EOF(CFile) do
|
|
begin
|
|
bytesread := 0;
|
|
blockread(CFile,BBuf,FileBufferSize,bytesread);
|
|
bindex := 0;
|
|
while bindex < bytesread do
|
|
begin
|
|
rdata := ReadByte25(bindex+index);
|
|
if BBuf[bindex] <> rdata then
|
|
begin
|
|
write('Error at ');
|
|
HexPrint(index+bindex,8);
|
|
write(' expected: ');
|
|
Hexprint(BBuf[bindex],2);
|
|
write(' but read: ');
|
|
HexPrint(rdata,2);
|
|
writeln;
|
|
dump(bindex+index);
|
|
halt(2);
|
|
end;
|
|
bindex := bindex + 1;
|
|
end;
|
|
index := index + FileBufferSize;
|
|
write('V ');
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
writeln('Can''t open configuration file');
|
|
halt(2);
|
|
end;
|
|
end;
|
|
|
|
procedure WriteBoot;
|
|
var index : word;
|
|
begin
|
|
writeln('Erasing sector 0 for boot block');
|
|
EraseSector25(BootSA);
|
|
for index := 0 to BBSize -1 do BBuf[index] := BootBlock[index];
|
|
for index := BBsize to PageSize-1 do BBuf[index] := 0;
|
|
WriteBlock(0,0);
|
|
writeln('BootBlock installed');
|
|
end;
|
|
|
|
function CheckBoot : boolean;
|
|
var
|
|
index : longint;
|
|
bootok: boolean;
|
|
begin
|
|
bootok := true;
|
|
for index := 0 to BBSize -1 do
|
|
begin
|
|
if ReadByte25(index) <> BootBlock[index] then bootok := false;
|
|
end;
|
|
CheckBoot := bootok;
|
|
end;
|
|
|
|
|
|
procedure WriteIt;
|
|
var
|
|
cbyte : byte;
|
|
bytesread,index : word;
|
|
bytecount : longint;
|
|
eepromadd : longint;
|
|
begin
|
|
if OpenForRead(CFile,FileName) then
|
|
begin
|
|
IdentifyEEPROM;
|
|
MakeBootBlock;
|
|
if not CheckBoot then WriteBoot else writeln('BootSector OK');
|
|
if not CheckBoot then BarfOut('Failed to write valid boot sector');
|
|
reset(CFile,1);
|
|
CFileSize := FileSize(CFile);
|
|
PrintBitfileHeader;
|
|
if Fallback then
|
|
begin
|
|
StartAddress := FallbackSA;
|
|
writeln('Writing fallback configuration');
|
|
end
|
|
else
|
|
begin
|
|
StartAddress := NormalSA;
|
|
writeln('Writing user configuration');
|
|
end;
|
|
StartProgramming(StartAddress);
|
|
writeln(':');
|
|
eepromadd:= StartAddress;
|
|
while not EOF(CFile) do
|
|
begin
|
|
bytesread := 0;
|
|
blockread(CFile,BBuf,FileBufferSize,bytesread);
|
|
index := 0;
|
|
write('W ');
|
|
while index < bytesread do
|
|
begin
|
|
WriteBlock(eepromadd,index);
|
|
index := index + PageSize;
|
|
eepromadd := eepromadd + Pagesize;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
writeln('Can''t open configuration file');
|
|
halt(2);
|
|
end;
|
|
writeln;
|
|
DoneProgramming;
|
|
end;
|
|
|
|
begin
|
|
GetParms;
|
|
GetOurEnv;
|
|
if not InitializeInterface(message) then bumout(message);
|
|
if VerifyOnly then VerifyIt else WriteIt;
|
|
writeln('Done');
|
|
CloseInterface;
|
|
halt(0);
|
|
end.
|