version 0.3

* fixed reading of configuration bits for 22V10 chips
* fixed reporting of errors during bitstream upload
* added GAL type set commmand
* added NO-CHECK of GAL type command
* 'i' command now requires to pass the GAL type on
  command line
* adjusted reporting of VPP to match Afterburner's
  readings
This commit is contained in:
ole00 2019-04-09 19:56:49 +01:00
parent a52b313150
commit a6bdca4908
2 changed files with 211 additions and 70 deletions

View File

@ -33,6 +33,10 @@ Changelog:
* 2019.03.24 - version 0.2
- added support for Win32 and Win64 builds
- fixed serial port setup for Mac OSX
* 2019.04.09 - version 0.3
- fixed error detection
- 'i' command now requires GAL type to be passed
on the command line
This is the PC part that communicates with Arduino UNO by serial line.
To compile: gcc -g3 -O0 afterburner afterburner.c
@ -47,7 +51,7 @@ To compile: gcc -g3 -O0 afterburner afterburner.c
#include "serial_port.h"
#define VERSION "v.0.2"
#define VERSION "v.0.3"
#define MAX_LINE 200
@ -105,6 +109,7 @@ int security = 0;
unsigned short checksum;
char galbuffer[GALBUFSIZE];
char fusemap[MAXFUSES];
char noGalCheck = 0;
char opRead = 0;
char opWrite = 0;
@ -115,6 +120,7 @@ char opTestVPP = 0;
static int waitForSerialPrompt(char* buf, int bufSize, int maxDelay);
static char sendGenericCommand(const char* command, const char* errorText, int maxDelay, char printResult);
static void printHelp() {
@ -134,17 +140,18 @@ static void printHelp() {
printf(" -f <file> : JEDEC fuse map file\n");
printf(" -d <serial_device> : name of the serial device. Default is: %s\n", DEFAULT_SERIAL_DEVICE_NAME);
printf(" serial params are: 38400, 8N1\n");
printf(" -nc : do not check device GAL type before operation: force the GAL type set on command line\n");
printf("examples:\n");
printf(" afterburner i : reads and prints the device info\n");
printf(" afterburner i -t ATF16V8B : reads and prints the device info\n");
printf(" afterburner r -t ATF16V8B : reads the fuse map from the GAL chip and displays it\n");
printf(" afterburner wv -f fuses.jed -t ATF16V8B : reads fuse map from file and writes it to \n");
printf(" the GAL chip. Does the fuse map verification at the end.\n");
printf("hints:\n");
printf(" - use the 'i' command first to check and set the right programming voltage (VPP)\n");
printf(" of the chip. If the programing voltage is unknown use 12 V.\n");
printf(" - ensure programmer (Arduino) is powered by a dedicated power supply, not just by.\n");
printf(" the USB serial cable. Without proper power programming errors may occur.\n");
printf(" of the chip. If the programing voltage is unknown use 10V.\n");
printf(" - known VPP voltages as tested on Afterburner with Arduino UNO: \n");
printf(" Lattice GAL16V8D, GAL22V10D: 12V \n");
printf(" Atmel ATF16V8D, ATF22V10C: 10V \n");
}
static char checkArgs(int argc, char** argv) {
@ -167,6 +174,8 @@ static char checkArgs(int argc, char** argv) {
} else if (strcmp("-d", param) == 0) {
i++;
deviceName = argv[i];
} else if (strcmp("-nc", param) == 0) {
noGalCheck = 1;
} else if (param[0] != '-') {
modes = param;
}
@ -210,7 +219,7 @@ static char checkArgs(int argc, char** argv) {
printf("Error: missing JED filename\n");
return -1;
}
if (0 == type && (opWrite || opRead || opErase || opVerify)) {
if (0 == type && (opWrite || opRead || opErase || opVerify || opInfo)) {
printf("Error: missing GAL type. Use -t <type> to specify.\n");
return -1;
} else if (0 != type) {
@ -415,12 +424,7 @@ static int parseFuseMap(char *ptr) {
if (lastfuse || pins) {
int cs = checkSum(lastfuse);
if (checksum && checksum != cs) {
/*
if (message("Checksum given %04X calculated %04X",NULL,MB_OKCANCEL,checksum,CheckSum(lastfuse)))
{
return checksumpos;
}
*/
printf("Checksum does not match! given=0x%04X calculated=0x%04X last fuse=%i\n", checksum, cs, lastfuse);
}
for (type = 0, i = 1; i < sizeof(galinfo) / sizeof(galinfo[0]); i++) {
@ -556,6 +560,22 @@ static char* stripPrompt(char* buf) {
return buf;
}
//finds beginnig of the last line
static char* findLastLine(char* buf) {
int i;
char* result = buf;
if (buf == 0) {
return 0;
}
for (i = 0; buf[i] != 0; i++) {
if (buf[i] == '\r' || buf[i] == '\n') {
result = buf + i + 1;
}
}
return result;
}
static int waitForSerialPrompt(char* buf, int bufSize, int maxDelay) {
char* bufStart = buf;
int bufTotal = bufSize;
@ -624,7 +644,7 @@ static char upload() {
char fuseSet;
char buf[MAX_LINE];
char line[64];
unsigned short i, j, k, n;
unsigned int i, j, n;
if (openSerial() != 0) {
return -1;
@ -641,21 +661,25 @@ static char upload() {
//fuse map
buf[0] = 0;
fuseSet = 0;
for (i = k = 0; i < galinfo[gal].fuses;) {
for (i = 0; i < galinfo[gal].fuses;) {
unsigned char f = 0;
if (i % 32 == 0) {
if (i != 0) {
strcat(buf, "\r");
//the buffer contains at least one fuse set to 1
if (fuseSet) {
#ifdef DEBUG_UPLOAD
printf("%s\n", buf);
#endif
sendLine(buf, MAX_LINE, 100);
buf[0] = 0;
}
fuseSet = 0;
}
sprintf(buf, "#f %04i ", k);
sprintf(buf, "#f %04i ", i);
}
for (j = 0; j < 8 && i < galinfo[gal].fuses; j++, k++, i++) {
f = 0;
for (j = 0; j < 8 && i < galinfo[gal].fuses; j++,i++) {
if (fusemap[i]) {
f |= (1 << j);
fuseSet = 1;
@ -664,11 +688,15 @@ static char upload() {
sprintf(line, "%02X", f);
strcat(buf, line);
}
// send last unfinished fuse line
if (k % 32) {
if (i % 32 && fuseSet) {
strcat(buf, "\r");
#ifdef DEBUG_UPLOAD
printf("%s\n", buf);
#endif
sendLine(buf, MAX_LINE, 100);
}
@ -680,10 +708,8 @@ static char upload() {
sendLine(buf, MAX_LINE, 300);
//end of upload
sprintf(buf, "#e\r");
sendLine(buf, MAX_LINE, 300);
return sendGenericCommand("#e\r", "Upload failed", 300, 0);
return 0;
}
static char sendGenericCommand(const char* command, const char* errorText, int maxDelay, char printResult) {
@ -699,7 +725,8 @@ static char sendGenericCommand(const char* command, const char* errorText, int m
return -1;
} else {
char* response = stripPrompt(buf);
if (response[0] == 'E' && response[1] == 'R') {
char* lastLine = findLastLine(response);
if (lastLine == 0 || (lastLine[0] == 'E' && lastLine[1] == 'R')) {
printf("%s\n", response);
return -1;
} else if (printResult) {
@ -786,6 +813,33 @@ static char operationTestVpp(void) {
return result;
}
static char operationSetGalCheck(void) {
int readSize;
char result;
if (openSerial() != 0) {
return -1;
}
result = sendGenericCommand(noGalCheck ? "F\r" : "f\r", "noGalCheck failed ?", 4000, 0);
closeSerial();
return result;
}
static char operationSetGalType(Galtype type) {
char buf[MAX_LINE];
int readSize;
char result;
if (openSerial() != 0) {
return -1;
}
sprintf(buf, "g%i\r", (int)type);
result = sendGenericCommand(buf, "setGalType failed ?", 4000, 0);
closeSerial();
return result;
}
static char operationEraseGal(void) {
char buf[MAX_LINE];
int readSize;
@ -864,7 +918,13 @@ int main(int argc, char** argv) {
printf("Afterburner " VERSION " \n");
}
if (opErase) {
result = operationSetGalCheck();
if (gal != UNKNOWN && 0 == result) {
result = operationSetGalType(gal);
}
if (opErase && 0 == result) {
result = operationEraseGal();
}

View File

@ -29,13 +29,17 @@
Changelog:
* 2019.02.02 - initial version 0.1
* 2019.04.09 - v. 0.3,
- added set & check of gal type,
- fixed ATF22V10 and GAL22V10 CFG reading bug (porting bug)
*/
#define VERSION "0.1"
#define VERSION "0.3"
//#define DEBUG_PES
//#define DEBUG_VERIFY
//ARDUINO UNO pin mapping
// GAL PIN NAME | ARDUINO UNO PIN NUMBER
@ -73,7 +77,9 @@
#define COMMAND_UTX '#'
#define COMMAND_ECHO 'e'
#define COMMAND_TEST_VOLTAGE 't'
#define COMMAND_SET_GAL_TYPE 'g'
#define COMMAND_ENABLE_CHECK_TYPE 'f'
#define COMMAND_DISABLE_CHECK_TYPE 'F'
#define READGAL 0
#define VERIFYGAL 1
@ -95,7 +101,7 @@
#define NATIONAL 0x8F
#define SGSTHOMSON 0x20
#define ATMEL16 'V'
#define ATMEL22 '3'
#define ATMEL22 '1'
typedef enum {
UNKNOWN,
@ -104,7 +110,8 @@ typedef enum {
GAL22V10,
ATF16V8B,
ATF22V10B,
ATF22V10C
ATF22V10C,
LAST_GAL_TYPE //dummy
} GALTYPE;
@ -114,6 +121,9 @@ typedef enum {
#define CFG_BASE_20 2560
#define CFG_BASE_22 5808
#define CFG_STROBE_ROW 0
#define CFG_SET_ROW 1
// common CFG fuse address map for cfg16V8 and cfg20V8
// the only difference is the starting address: 2048 for cfg16V8 and 2560 for cfg20V8
// total size: 82
@ -175,20 +185,21 @@ static struct
unsigned short cfgbase; /* base address of the config bit numbers */
const unsigned char *cfg; /* pointer to config bit numbers */
unsigned char cfgbits; /* number of config bits */
unsigned char cfgmethod; /* strobe or set row for reading config */
}
galinfo[]=
{
// + fuses + bits +uesbytes +pesrow +cfgbase
// | +pins | +uesrow | +eraserow| +pesbytes | +cfg
// +-- type + id0 + id1 +- name | | +rows | | +uesfuse | +eraseallrow +cfgrow | | + cfgbits
// | | | | | | | | | | | | | | | | | | |
{UNKNOWN, 0x00, 0x00, "unknown", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, NULL, 0},
{GAL16V8, 0x00, 0x1A, "GAL16V8", 2194, 20, 32, 64, 32, 2056, 8, 63, 54, 58, 8, 60, CFG_BASE_16, cfgV8AB, sizeof(cfgV8AB)},
{GAL20V8, 0x20, 0x3A, "GAL20V8", 2706, 24, 40, 64, 40, 2568, 8, 63, 59, 58, 8, 60, CFG_BASE_20, cfgV8AB, sizeof(cfgV8AB)},
{GAL22V10, 0x48, 0x49, "GAL22V10", 5892, 24, 44, 132, 44, 5828, 8, 61, 60, 58, 10, 16, CFG_BASE_22, cfgV10, sizeof(cfgV10)},
{ATF16V8B, 0x00, 0x00, "ATF16V8B", 2194, 20, 32, 64, 32, 2056, 8, 63, 54, 58, 8, 60, CFG_BASE_16, cfgV8AB, sizeof(cfgV8AB)},
{ATF22V10B, 0x00, 0x00, "ATF22V10B",5892, 24, 44, 132, 44, 5828, 8, 61, 60, 58, 10, 16, CFG_BASE_22, cfgV10, sizeof(cfgV10)},
{ATF22V10C, 0x00, 0x00, "ATF22V10C",5892, 24, 44, 132, 44, 5828, 8, 61, 60, 58, 10, 16, CFG_BASE_22, cfgV10, sizeof(cfgV10)},
// +-- type + id0 + id1 +- name | | +rows | | +uesfuse | +eraseallrow +cfgrow | | + cfgbits +cfgmethod
// | | | | | | | | | | | | | | | | | | | |
{UNKNOWN, 0x00, 0x00, "unknown", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, NULL, 0 , 0},
{GAL16V8, 0x00, 0x1A, "GAL16V8", 2194, 20, 32, 64, 32, 2056, 8, 63, 54, 58, 8, 60, CFG_BASE_16, cfgV8AB, sizeof(cfgV8AB), CFG_STROBE_ROW},
{GAL20V8, 0x20, 0x3A, "GAL20V8", 2706, 24, 40, 64, 40, 2568, 8, 63, 59, 58, 8, 60, CFG_BASE_20, cfgV8AB, sizeof(cfgV8AB), CFG_STROBE_ROW},
{GAL22V10, 0x48, 0x49, "GAL22V10", 5892, 24, 44, 132, 44, 5828, 8, 61, 60, 58, 10, 16, CFG_BASE_22, cfgV10, sizeof(cfgV10) , CFG_SET_ROW },
{ATF16V8B, 0x00, 0x00, "ATF16V8B", 2194, 20, 32, 64, 32, 2056, 8, 63, 54, 58, 8, 60, CFG_BASE_16, cfgV8AB, sizeof(cfgV8AB), CFG_STROBE_ROW},
{ATF22V10B, 0x00, 0x00, "ATF22V10B",5892, 24, 44, 132, 44, 5828, 8, 61, 60, 58, 10, 16, CFG_BASE_22, cfgV10, sizeof(cfgV10) , CFG_SET_ROW },
{ATF22V10C, 0x00, 0x00, "ATF22V10C",5892, 24, 44, 132, 44, 5828, 8, 61, 60, 58, 10, 16, CFG_BASE_22, cfgV10, sizeof(cfgV10) , CFG_SET_ROW },
};
// MAXFUSES calculated as the biggest required space to hold the fuse bitmap + UES bitmap + CFG bitmap
@ -198,7 +209,7 @@ galinfo[]=
GALTYPE gal; //the gal device index pointing to galinfo
static short security = 0, erasetime = 0, progtime = 0, vpp = 0;
static short security = 0, erasetime = 100, progtime = 100, vpp = 0;
char echoEnabled;
unsigned char pes[12];
@ -208,13 +219,16 @@ short lineIndex;
char endOfLine;
char mapUploaded;
char isUploading;
char uploadError;
unsigned char fusemap[MAXFUSES];
char typeCheck; //check GAL type before starting an operation
static void setFuseBit(unsigned short bitPos);
static unsigned short checkSum(unsigned short n);
static char checkGalTypeViaPes(void);
static void turnOff(void);
static void printFormatedNumberHex2(unsigned char num) ;
// print some help on the serial console
void printHelp(char full) {
@ -244,6 +258,7 @@ void setup() {
gal = ATF16V8B;
echoEnabled = 0;
mapUploaded = 0;
typeCheck = 1; //do type check
// Serial output from the GAL chip, input for Arduino
pinMode(PIN_SDOUT, INPUT);
@ -313,7 +328,9 @@ char handleTerminalCommands() {
} else if (lineIndex > 2) {
c = line[0];
if (!isUploading || c != '#') {
c = COMMAND_UNKNOWN;
if (c != COMMAND_SET_GAL_TYPE) {
c = COMMAND_UNKNOWN;
}
}
}
if (!isUploading) {
@ -385,19 +402,24 @@ unsigned short parse4hex(char i) {
void parseUploadLine() {
switch (line[1]) {
case 'e': {
Serial.println("upload finished");
if (uploadError) {
Serial.print(F("ER upload failed"));
} else {
Serial.print(F("OK upload finished"));
}
isUploading = 0;
} break;
// gal type
case 't': {
short v = line[3] - '0';
if (v > 0 && v <= (short)ATF22V10C) {
if (v > 0 && v < LAST_GAL_TYPE) {
gal = (GALTYPE) v;
Serial.print(F("OK gal set: "));
Serial.println((short) gal, DEC);
} else {
Serial.println(F("ER unknown gal index"));
uploadError = 1;
}
} break;
@ -433,8 +455,9 @@ void parseUploadLine() {
unsigned short val = parse4hex(3);
unsigned short cs = checkSum(galinfo[gal].fuses);
if (cs == val) {
Serial.println(F("OK"));
Serial.println(F("OK checksum matches"));
} else {
uploadError = 1;
Serial.print(F("ER checksum:"));
Serial.print(cs, HEX);
Serial.print(F(" expected:"));
@ -442,7 +465,9 @@ void parseUploadLine() {
}
} break;
default: Serial.println(F("ER unknown upload cmd"));
default:
uploadError = 1;
Serial.println(F("ER unknown upload cmd"));
}
lineIndex = 0;
@ -635,11 +660,17 @@ static void strobeRow(char row)
}
}
// read PES: programmer electronic signature (ATF = text string, others = Vendor/Vpp/timing)
void readPes() {
static void readPes(void) {
unsigned short bitmask;
short byteIndex;
#ifdef DEBUG_PES
Serial.print(F("testing gal "));
Serial.print(gal, DEC);
Serial.println();
#endif
turnOn(READPES);
strobeRow(galinfo[gal].pesrow);
@ -657,9 +688,9 @@ void readPes() {
}
turnOff();
}
static unsigned char getDuration(unsigned char index) {
switch (index) {
case 0: return 1;
@ -689,11 +720,6 @@ void parsePes(char type) {
switch (type) {
case ATF16V8B:
progtime = 10;
erasetime = 100;
vpp = 40; /* 12.0V */
break;
case ATF22V10B:
case ATF22V10C:
progtime = 10;
@ -756,6 +782,9 @@ void parsePes(char type) {
}
}
}
//Afterburnes seems to work with programming voltages reduced by 2V
vpp -= 8; // -2V
}
@ -862,7 +891,12 @@ static void readGalFuseMap(const unsigned char* cfgArray, char useDelay, char do
}
// read CFG
strobeRow(galinfo[gal].cfgrow);
if (galinfo[gal].cfgmethod == CFG_STROBE_ROW) {
strobeRow(galinfo[gal].cfgrow);
} else {
setRow(galinfo[gal].cfgrow);
strobe(1);
}
for(bit = 0; bit < galinfo[gal].cfgbits; bit++) {
if (receiveBit()) {
setFuseBit(cfgAddr + cfgArray[bit]);
@ -889,6 +923,10 @@ static unsigned short verifyGalFuseMap(const unsigned char* cfgArray, char useDe
mapBit = getFuseBit(addr);
fuseBit = receiveBit();
if (mapBit != fuseBit) {
#ifdef DEBUG_VERIFY
Serial.print(F("f a="));
Serial.println((row * galinfo[gal].bits) + bit, DEC);
#endif
errors++;
}
}
@ -908,6 +946,10 @@ static unsigned short verifyGalFuseMap(const unsigned char* cfgArray, char useDe
mapBit = getFuseBit(addr);
fuseBit = receiveBit();
if (mapBit != fuseBit) {
#ifdef DEBUG_VERIFY
Serial.print(F("U a="));
Serial.println(bit, DEC);
#endif
errors++;
}
}
@ -916,11 +958,20 @@ static unsigned short verifyGalFuseMap(const unsigned char* cfgArray, char useDe
}
// read CFG
strobeRow(galinfo[gal].cfgrow);
if (galinfo[gal].cfgmethod == CFG_STROBE_ROW) {
strobeRow(galinfo[gal].cfgrow);
} else {
setRow(galinfo[gal].cfgrow);
strobe(1);
}
for(bit = 0; bit < galinfo[gal].cfgbits; bit++) {
mapBit = getFuseBit(cfgAddr + cfgArray[bit]);
fuseBit = receiveBit();
if (mapBit != fuseBit) {
#ifdef DEBUG_VERIFY
Serial.print(F("C a="));
Serial.println(bit, DEC);
#endif
errors++;
}
}
@ -1016,7 +1067,7 @@ static void writeGalFuseMapV8(const unsigned char* cfgArray) {
}
strobe(progtime);
// write CFG
// write CFG (all ICs use setRow)
setRow(galinfo[gal].cfgrow);
for(rbit = 0; rbit < galinfo[gal].cfgbits; rbit++) {
sendBit(getFuseBit(cfgAddr + cfgArray[rbit]));
@ -1138,6 +1189,16 @@ static char checkGalTypeViaPes(void)
{
char type = UNKNOWN;
#ifdef DEBUG_PES
char i;
Serial.println(F("PES raw bytes:"));
for (i = 0; i < 10; i++) {
printFormatedNumberHex2(pes[i]);
Serial.print(F(" "));
}
Serial.println();
#endif
if (pes[7] == 'F' && pes[6]== '2' && pes[5]== '2' && pes[4]== 'V' && pes[3]== '1' && pes[2]=='0') {
if (pes[1] == 'B') {
type = ATF22V10B;
@ -1169,7 +1230,6 @@ static char testProperGAL(void)
}
else if (type != gal) {
//PES indicates a different GAL type than selected. Change to detected GAL type?
// gal = type;
goto error;
}
@ -1389,7 +1449,19 @@ static void testVoltage(int seconds) {
setVPP(0);
}
// Arduino main loop - where the magic happens :-)
// returns 1 if type check if OK, 0 if gal type does not match the type read from PES
static char doTypeCheck(void) {
if (0 == typeCheck) {
return 1; // no need to do type check
}
readPes();
parsePes(UNKNOWN);
return testProperGAL();
}
// Arduino main loop
void loop() {
@ -1418,9 +1490,9 @@ void loop() {
// verify fuse-map bits and bits read from the GAL chip
case COMMAND_VERIFY_FUSES: {
if (mapUploaded) {
readPes();
parsePes(UNKNOWN);
readOrVerifyGal(1); //just verify, do not overwrite fusemap
if (doTypeCheck()) {
readOrVerifyGal(1); //just verify, do not overwrite fusemap
}
} else {
printNoFusesError();
}
@ -1434,6 +1506,7 @@ void loop() {
fusemap[i] = 0;
}
isUploading = 1;
uploadError = 0;
} break;
// command of the upload protocol
@ -1452,9 +1525,7 @@ void loop() {
// read fuse-map from the GAL and print it in the JEDEC form
case COMMAND_READ_FUSES : {
readPes();
parsePes(UNKNOWN);
if (testProperGAL()) {
if (doTypeCheck()) {
readOrVerifyGal(0); //just read, no verification
printJedec();
}
@ -1463,9 +1534,7 @@ void loop() {
// write current fuse-map to the GAL chip
case COMMAND_WRITE_FUSES : {
if (mapUploaded) {
readPes();
parsePes(UNKNOWN);
if (testProperGAL()) {
if (doTypeCheck()) {
writeGal();
//TODO security
}
@ -1476,9 +1545,7 @@ void loop() {
// erases the fuse-map on the GAL chip
case COMMAND_ERASE_GAL: {
readPes();
parsePes(UNKNOWN);
if (testProperGAL()) {
if (doTypeCheck()) {
eraseGAL();
}
} break;
@ -1490,8 +1557,22 @@ void loop() {
case COMMAND_TEST_VOLTAGE : {
testVoltage(20);
}break;
} break;
case COMMAND_SET_GAL_TYPE : {
char type = line[1] - '0';
if (type >= 1 && type < LAST_GAL_TYPE) {
gal = (GALTYPE) type;
} else {
Serial.println(F("ER Unknown gal type"));
}
} break;
case COMMAND_ENABLE_CHECK_TYPE: {
typeCheck = 1;
} break;
case COMMAND_DISABLE_CHECK_TYPE: {
typeCheck = 0;
} break;
default: {
if (command != COMMAND_NONE) {
Serial.print(F("ER Unknown command: "));