From e9d005213e6212ebc2d1d8046e96fbb80c49cf79 Mon Sep 17 00:00:00 2001 From: ole00 Date: Sat, 25 Mar 2023 19:53:13 +0000 Subject: [PATCH] Added support for Power-Down pin on ATF16V8C The PD feature is now selectively enabled or disabled based on the JED contents. Also, when fuses are read the printout of the JED file reflects the PD fuse bit state. So, when the PD fuse bit is enabled then the JED file contains an extra fuse bit set to 1. The ATF22V10C now behaves the same way regarding the PD fuse bit (previously Afterburner always disabled the PD function). credits: GALmate software --- afterburner.ino | 97 ++++++++++++++++++++++++++++++++++++++++---- src_pc/afterburner.c | 42 +++++++++++++++---- 2 files changed, 123 insertions(+), 16 deletions(-) diff --git a/afterburner.ino b/afterburner.ino index 2d7e3fe..6b602a2 100644 --- a/afterburner.ino +++ b/afterburner.ino @@ -39,7 +39,7 @@ */ -#define VERSION "0.4.1" +#define VERSION "0.4.2" //#define DEBUG_PES //#define DEBUG_VERIFY @@ -84,6 +84,8 @@ #define COMMAND_ENABLE_CHECK_TYPE 'f' #define COMMAND_DISABLE_CHECK_TYPE 'F' #define COMMAND_ENABLE_SECURITY 's' +#define COMMAND_ENABLE_APD 'z' +#define COMMAND_DISABLE_APD 'Z' #define READGAL 0 #define VERIFYGAL 1 @@ -103,6 +105,9 @@ // ATF16V8C flavour #define FLAG_BIT_ATF16V8C (1 << 1) +// Keep the power-down feature enabled for ATF C GALs +#define FLAG_BIT_APD (1 << 2) + // contents of pes[3] // Atmel PES is text string eg. 1B8V61F1 or 3Z01V22F1 // ^ ^ @@ -136,6 +141,9 @@ typedef enum { #define CFG_STROBE_ROW 0 #define CFG_SET_ROW 1 +// Atmel power-down row +#define CFG_ROW_APD 59 + // 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 @@ -166,6 +174,7 @@ static const unsigned char cfgV8AB[]= // common CFG fuse address map for cfg22V10 // starting address: 5808 +// total size 20 static const unsigned char cfgV10[]= { 1,0,3,2,5,4,7,6,9,8,11,10,13,12,15,14,17,16,19,18, @@ -214,7 +223,7 @@ galinfo[]= }; // MAXFUSES calculated as the biggest required space to hold the fuse bitmap + UES bitmap + CFG bitmap -// MAXFUSES = ((132 * 44 bits) / 8) + uesbytes + (20 / 8) +// MAXFUSES = ((132 * 44 bits) / 8) + uesbytes + ((20 + 1) / 8) // +1 is the power-down extra fuse // 726 + 8 + 3 #define MAXFUSES 737 @@ -479,7 +488,8 @@ void parseUploadLine() { //checksum case 'c': { unsigned short val = parse4hex(3); - unsigned short cs = checkSum(galinfo[gal].fuses); + unsigned char apdFuse = (flagBits & FLAG_BIT_APD) ? 1 : 0; + unsigned short cs = checkSum(galinfo[gal].fuses + apdFuse); if (cs == val) { Serial.println(F("OK checksum matches")); } else { @@ -974,6 +984,21 @@ static void readGalFuseMap(const unsigned char* cfgArray, char useDelay, char do setFuseBit(cfgAddr + cfgArray[bit]); } } + + //check APD fuse bit - only for ATF16V8C or ATF22V10C + if ((flagBits & FLAG_BIT_ATF16V8C) || gal == ATF22V10C) { + setPV(0); + if (gal == ATF22V10C) { + setRow(0); + sendAddress(6, CFG_ROW_APD); + strobe(1); + } else { //ATF16V8C + setRow(CFG_ROW_APD); + strobe(1); + setPV(1); + } + setFlagBit(FLAG_BIT_APD, receiveBit()); + } } // generic fuse-map verification, fuse map bits are compared against read bits @@ -1068,6 +1093,30 @@ static unsigned short verifyGalFuseMap(const unsigned char* cfgArray, char useDe errors++; } } + + //verify PD fuse on Atmel's C GALs + if ((flagBits & FLAG_BIT_ATF16V8C) || gal == ATF22V10C) { + setPV(0); + if (gal == ATF22V10C) { + setRow(0); + sendAddress(6, CFG_ROW_APD); + strobe(1); + } else { //ATF16V8C + setRow(CFG_ROW_APD); + strobe(1); + setPV(1); + } + + mapBit = (flagBits & FLAG_BIT_APD)? 1 : 0; + fuseBit = receiveBit(); + if (mapBit != fuseBit) { +#ifdef DEBUG_VERIFY + Serial.println(F("C pd")); +#endif + errors++; + } + } + return errors; } @@ -1170,6 +1219,13 @@ static void writeGalFuseMapV8(const unsigned char* cfgArray) { } strobe(progtime); setPV(0); + + // disable power-down if the APD flag is not set (only for ATF16V8C) + if (skipLastClk && (flagBits & FLAG_BIT_APD) == 0) { + setPV(1); + strobeRow(CFG_ROW_APD, BIT_ZERO); // strobe row and send one bit with value 0 + setPV(0); + } } // fuse-map writing function for V10 GAL chips @@ -1222,15 +1278,14 @@ static void writeGalFuseMapV10(const unsigned char* cfgArray, char fillUesStart, strobe(progtime); setPV(0); - if (useSdin) { + if (useSdin && (flagBits & FLAG_BIT_APD) == 0) { // disable power-down feature (JEDEC bit #5892) setRow(0); - sendAddress(6, 59); + sendAddress(6, CFG_ROW_APD); setPV(1); strobe(progtime); setPV(0); } - } // main fuse-map writing function @@ -1450,11 +1505,12 @@ static void printJedec() { unsigned short i, j, k, n; unsigned char unused, start; + uint8_t apdFuse = (flagBits & FLAG_BIT_APD) ? 1 : 0; Serial.print(F("JEDEC file for ")); printGalName(); Serial.print(F("*QP")); Serial.print(galinfo[gal].pins, DEC); - Serial.print(F("*QF")); Serial.print(galinfo[gal].fuses, DEC); + Serial.print(F("*QF")); Serial.print(galinfo[gal].fuses + apdFuse, DEC); Serial.println(F("*QV0*F0*G0*X0*")); for( i = k = 0; i < galinfo[gal].bits; i++) { @@ -1503,6 +1559,7 @@ static void printJedec() line[0] = 0; + // UES in byte form Serial.print(F("N UES")); for (j = 0;j < galinfo[gal].uesbytes; j++) { n = 0; @@ -1521,6 +1578,7 @@ static void printJedec() } Serial.println(F("*")); + // UES in bit form Serial.print(F("L")); printFormatedNumberDec4(k); Serial.print(F(" ")); @@ -1534,7 +1592,7 @@ static void printJedec() } Serial.println(F("*")); - + // CFG bits if (k < galinfo[gal].fuses) { Serial.print(F("L")); printFormatedNumberDec4(k); @@ -1547,7 +1605,17 @@ static void printJedec() Serial.print(F("0")); } } + //ATF16V8C + if (apdFuse) { + Serial.print(F("1")); + setFuseBit(k); // set for correct check-sum calculation + } Serial.println(F("*")); + } else if (apdFuse) { //ATF22V10C + Serial.print(F("L")); + printFormatedNumberDec4(k); + Serial.println(F(" 1*")); + setFuseBit(k); // set for correct check-sum calculation } Serial.print(F("N PES")); @@ -1557,7 +1625,7 @@ static void printJedec() } Serial.println(F("*")); Serial.print(F("C")); - printFormatedNumberHex4(checkSum(galinfo[gal].fuses)); + printFormatedNumberHex4(checkSum(galinfo[gal].fuses + apdFuse)); Serial.println(); Serial.println(F("*")); } @@ -1688,6 +1756,17 @@ void loop() { } } break; + // keep atmel power-down feature enabled during write + case COMMAND_ENABLE_APD: { + setFlagBit(FLAG_BIT_APD, 1); + Serial.println(F("OK APD set")); + } break; + + case COMMAND_DISABLE_APD: { + setFlagBit(FLAG_BIT_APD, 0); + Serial.println(F("OK APD cleared")); + } break; + // toggles terminal echo case COMMAND_ECHO : { echoEnabled = 1 - echoEnabled; diff --git a/src_pc/afterburner.c b/src_pc/afterburner.c index f4176c7..ea048a9 100644 --- a/src_pc/afterburner.c +++ b/src_pc/afterburner.c @@ -51,7 +51,7 @@ To compile: gcc -g3 -O0 afterburner afterburner.c #include "serial_port.h" -#define VERSION "v.0.4.1" +#define VERSION "v.0.4.2" #define MAX_LINE 200 @@ -118,6 +118,7 @@ char opInfo = 0; char opVerify = 0; char opTestVPP = 0; char opSecureGal = 0; +char flagEnableApd = 0; static int waitForSerialPrompt(char* buf, int bufSize, int maxDelay); @@ -451,6 +452,18 @@ static int parseFuseMap(char *ptr) { } } } + if (lastfuse == 2195 && gal == ATF16V8B) { + flagEnableApd = fusemap[2194]; + if (verbose) { + printf("PD fuse detected: %i\n", fusemap[2194]); + } + } + if (lastfuse == 5893 && gal == ATF22V10C) { + flagEnableApd = fusemap[5892]; + if (verbose) { + printf("PD fuse detected: %i\n", fusemap[5892]); + } + } return n; } @@ -655,9 +668,12 @@ static char upload() { char buf[MAX_LINE]; char line[64]; unsigned int i, j, n; + unsigned short csum; + int apdFuse = flagEnableApd; + int totalFuses = galinfo[gal].fuses; - if (openSerial() != 0) { - return -1; + if (apdFuse) { + totalFuses++; } // Start upload @@ -671,7 +687,7 @@ static char upload() { //fuse map buf[0] = 0; fuseSet = 0; - for (i = 0; i < galinfo[gal].fuses;) { + for (i = 0; i < totalFuses;) { unsigned char f = 0; if (i % 32 == 0) { if (i != 0) { @@ -689,7 +705,7 @@ static char upload() { sprintf(buf, "#f %04i ", i); } f = 0; - for (j = 0; j < 8 && i < galinfo[gal].fuses; j++,i++) { + for (j = 0; j < 8 && i < totalFuses; j++,i++) { if (fusemap[i]) { f |= (1 << j); fuseSet = 1; @@ -711,10 +727,11 @@ static char upload() { } //checksum + csum = checkSum(totalFuses); if (verbose) { - printf("sending csum: %04X\n", checkSum(galinfo[gal].fuses)); + printf("sending csum: %04X\n", csum); } - sprintf(buf, "#c %04X\r", checkSum(galinfo[gal].fuses)); + sprintf(buf, "#c %04X\r", csum); sendLine(buf, MAX_LINE, 300); //end of upload @@ -722,6 +739,7 @@ static char upload() { } +//returns 0 on success static char sendGenericCommand(const char* command, const char* errorText, int maxDelay, char printResult) { char buf[MAX_LINE]; int readSize; @@ -760,6 +778,16 @@ static char operationWriteOrVerify(char doWrite) { if (verbose) { printf("parse result=%i\n", result); } + + if (openSerial() != 0) { + return -1; + } + + // set power-down fuse bit (do it before upload to correctly calculate check-sum) + result = sendGenericCommand(flagEnableApd ? "z\r" : "Z\r", "APD set failed ?", 4000, 0); + if (result) { + goto finish; + } result = upload(); if (result) { return result;