Another piece of information. A couple of pages above @migry briefly described serial stream decoding algorithm for EPM7032(V).
I dumbly implement it in plain C (Linux+GCC) and check with mine and his data. Code:
#include <stdio.h>
#include <stdint.h>
uint8_t my_scoa[10] = { 0x01, 0x46, 0x8A, 0xAB, 0xB5, 0x31, 0x60, 0x84, 0x36, 0x43 };
uint8_t my_scob[10] = { 0xFF, 0xF6, 0xFF, 0xFF, 0xFF, 0xF5, 0xFF, 0xFC, 0xFF, 0xFB };
uint8_t mirgy_scoa[10] = { 0x01, 0x46, 0x8A, 0xAB, 0xF5, 0x33, 0x60, 0x83, 0x36, 0x43 };
uint8_t mirgy_scob[10] = { 0xFF, 0xF6, 0xFF, 0xE3, 0xFF, 0xF7, 0xFF, 0xE3, 0xFF, 0xF3 };
uint8_t resa[10] = { };
uint8_t resb[10] = { };
uint8_t original_map[80] =
{ 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75,
1, 6, 11, 16, 21, 26, 31, 36, 41, 46, 51, 56, 61, 66, 71, 76,
2, 7, 12, 17, 22, 27, 32, 37, 42, 47, 52, 57, 62, 67, 72, 77,
3, 8, 13, 18, 23, 28, 33, 38, 43, 48, 53, 58, 63, 68, 73, 78,
4, 9, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64, 69, 74, 79, };
uint8_t adjusted_map[80] =
{ 40, 45, 50, 55, 60, 65, 70, 75, 0, 5, 10, 15, 20, 25, 30, 35,
41, 46, 51, 56, 61, 66, 71, 76, 1, 6, 11, 16, 21, 26, 31, 36,
42, 47, 52, 57, 62, 67, 72, 77, 2, 7, 12, 17, 22, 27, 32, 37,
43, 48, 53, 58, 63, 68, 73, 78, 3, 8, 13, 18, 23, 28, 33, 38,
44, 49, 54, 59, 64, 69, 74, 79, 4, 9, 14, 19, 24, 29, 34, 39, };
void hexdump(uint8_t *buf, uint16_t cnt) {
uint8_t strbuf[16];
uint8_t stridx = 0;
for (uint16_t addr = 0; addr < cnt; addr++) {
if ((addr & 0x0F)==0) printf("%04X: ", addr);
printf("%02X ", buf[addr]);
strbuf[stridx++] = ((buf[addr] < ' ') || (buf[addr]>=0x80)) ? '.' : buf[addr];
if ( (addr==(cnt-1)) || ( ((addr & 0x0F)==0) && (addr!=0)) ) {
strbuf[stridx] = 0;
printf(" %s\n", strbuf);
stridx = 0;
}
}
}
#define MAP adjusted_map
void decode(uint8_t *psrc, uint8_t *pdst, uint8_t sz) {
//Zero result buffer
for (uint8_t i=0; i<sz; i++) pdst[i]=0;
//Pass through all 80 bits
for (uint8_t srcbitno=0; srcbitno<sizeof(MAP); srcbitno++) {
//Locate bit in source stream
uint8_t srcbyteno = srcbitno >> 3;
uint8_t srcmask = 0x80 >> (0x07 - (srcbitno & 0x07));
//Locate bit in destination stream
uint8_t dstbitno = MAP[srcbitno];
uint8_t dstbyteno = dstbitno >> 3;
uint8_t dstmask = 0x80 >> (0x07 - (dstbitno & 0x07));
//Set bit in destination stream if it is set in source stream
if (psrc[srcbyteno] & srcmask) {
pdst[dstbyteno] |= dstmask;
}
}
}
void main(int argc, char * argv[]) {
printf(" My SCOA:"); hexdump(&my_scoa[0], sizeof(my_scoa));
printf(" My SCOB:"); hexdump(&my_scob[0], sizeof(my_scob));
decode(&my_scoa[0], &resa[0], sizeof(my_scoa));
decode(&my_scob[0], &resb[0], sizeof(my_scob));
printf(" My RESA:"); hexdump(&resa[0], sizeof(resa));
printf(" My RESB:"); hexdump(&resb[0], sizeof(resb));
printf("\n");
printf("Migry's SCOA:"); hexdump(&mirgy_scoa[0], sizeof(mirgy_scoa));
printf("Migry's SCOB:"); hexdump(&mirgy_scob[0], sizeof(mirgy_scob));
decode(&mirgy_scoa[0], &resa[0], sizeof(mirgy_scoa));
decode(&mirgy_scob[0], &resb[0], sizeof(mirgy_scob));
printf("Migry's RESA:"); hexdump(&resa[0], sizeof(resa));
printf("Migry's RESB:"); hexdump(&resb[0], sizeof(resb));
It works, but with one interesting thing: substitution map for bitstream that I've created exactly using the Migry's description (original_map) provide "5 byte-swapped output":
My SCOA:0000: 01 46 8A AB B5 31 60 84 36 43 .F...1`.6C
My SCOB:0000: FF F6 FF FF FF F5 FF FC FF FB ..........
My RESA:0000: 45 52 41 39 32 76 26 41 4C 54 ERA92v&ALT
My RESB:0000: FF FF FF FF FF 76 3E FD FF FF .....v>...
Migry's SCOA:0000: 01 46 8A AB F5 33 60 83 36 43 .F...3`.6C
Migry's SCOB:0000: FF F6 FF E3 FF F7 FF E3 FF F3 ..........
Migry's RESA:0000: 45 52 41 39 33 FE 07 41 4C 54 ERA93..ALT
Migry's RESB:0000: FF FF FF FF FF FE 17 50 FF FF .......P..
It can be easily fixed by swapping left and right halves of map, see adjusted_map in the code. With adjusted map I got the right results:
My SCOA:0000: 01 46 8A AB B5 31 60 84 36 43 .F...1`.6C
My SCOB:0000: FF F6 FF FF FF F5 FF FC FF FB ..........
My RESA:0000: 76 26 41 4C 54 45 52 41 39 32 v&ALTERA92
My RESB:0000: 76 3E FD FF FF FF FF FF FF FF v>........
Migry's SCOA:0000: 01 46 8A AB F5 33 60 83 36 43 .F...3`.6C
Migry's SCOB:0000: FF F6 FF E3 FF F7 FF E3 FF F3 ..........
Migry's RESA:0000: FE 07 41 4C 54 45 52 41 39 33 ..ALTERA93
Migry's RESB:0000: FE 17 50 FF FF FF FF FF FF FF ..P.......
So in addition to description, we now have a working code.
ADDED:
Just a thought that came to me after thinking about ReadID in parallel mode for 7000S (All one's serial output) and re-reading this thread.
I don't know the whole Altera product line of that time, but got this summary to myself:
1. 'Old/classic' 7000 family, that supports only high-voltage, clumsy and mysterious parallel programming mode.
2. 'Intermediate' 7000S family, that introduce JTAG programming, but not get rid completely from HV mode. My assumption is that they (7000S) doesn't support parallel programming, only high-voltage erase.
3. 'Modern' 7000AE/3000S and Atmel's ATF15xx that take a step further and support JTAG reenabling with HV appiled. No more needed for HV parallel programming, even for simple pin manipulations for BulkErase.
Why I made such conclusion?
1. EPM7032LC44 (and other family members) provide serial output and I think that it is a vital data:
- ID block is possibly erased during HV BulkErase and need to be reprogrammed to keep ID/VPP/Tbe/etc.
- Reprogramming is really performed after HV BulkErase (see traces, that I provided earlier).
2. EPM7032SLC44 does not provide any serial data for ReadID. Let's think what it means:
- we don't need actual VPP value and timings - programming via JTAG does not require such parameters.
- we don't need Chip ID as it can be read by JTAG.
3. So the only reason for 7000S to use HV parallel programming is BulkErase procedure.
4. Successors, like 7000AE/3000S/ATF15xx make this "revival" procedure even more simpler.