GALプログラマ最初の一歩

FT2232を使ってGALプログラマを作ることにしました。

結線は以下のとおり。

|FT Pin|GAL Pin|
|:--|:--|
|AD0|SDIN|
|AD1-AD6|RA0-RA5|
|AD7|SCLK|
|BD0|SDOUT|
|BD1|STB-|
|BD2|P/V-|

パラレルポートを使ったプログラマーはバッファを入れているケースがあるが、これはおそらくマシンによってパラレルポートのドライブ能力に差があったので、入れていたのではないかと思われる。

![写真（2020-06-08 17.19）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/806f35c0-30c6-f085-ecae-67183330f05f.jpeg)

VPPはストックがあったMAX662Aを使いました。12Vと20Vのデュアル電源にして、書き込み用は20Vから作ろうと思います。(これかなり思案しました)

Mac OS Xでftdiのライブラリを使ってプログラム書いてみました。

```c
/*
  Hiroki Mori
*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include "ftd2xx.h"

typedef enum {UNKNOWN,GAL16V8,GAL20V8,GAL22V10,ATF16V8B,ATF22V10B,ATF22V10C,GAL26CV12,GAL6001,GAL6002} GALTYPE;

/* config bit numbers */
static int cfg16V8[]=
{
    2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,2140,2141,2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2155,2156,2157,2158,2159,
    2048,2049,2050,2051,
    2193,
    2120,2121,2122,2123,2124,2125,2126,2127,
    2192,
    2052,2053,2054,2055,
    2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,2189,2190,2191
};
static int cfg16V8AB[]=
{
    2048,2049,2050,2051,
    2193,
    2120,2121,2122,2123,
    2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,2140,2141,2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2155,2156,2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,2189,2190,2191,
    2124,2125,2126,2127,
    2192,
    2052,2053,2054,2055
};
static int cfg20V8[]=
{
    2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,2669,2670,2671,
    2560,2561,2562,2563,
    2705,
    2632,2633,2634,2635,2636,2637,2638,2639,
    2704,
    2564,2565,2566,2567,
    2672,2673,2674,2675,2676,2677,2678,2679,2680,2681,2682,2683,2684,2685,2686,2687,2688,2689,2690,2691,2692,2693,2694,2695,2696,2697,2698,2699,2700,2701,2702,2703
};
static int cfg20V8AB[]=
{
    2560,2561,2562,2563,
    2705,
    2632,2633,2634,2635,
    2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,2669,2670,2671,2672,2673,2674,2675,2676,2677,2678,2679,2680,2681,2682,2683,2684,2685,2686,2687,2688,2689,2690,2691,2692,2693,2694,2695,2696,2697,2698,2699,2700,2701,2702,2703,
    2636,2637,2638,2639,
    2704,
    2564,2565,2566,2567
};
static int cfg22V10[]=
{
    5809,5808,
    5811,5810,
    5813,5812,
    5815,5814,
    5817,5816,
    5819,5818,
    5821,5820,
    5823,5822,
    5825,5824,
    5827,5826
};
static int cfg26CV12[]=
{
    6345,6344,
    6347,6346,
    6349,6348,
    6351,6350,
    6353,6352,
    6355,6354,
    6357,6356,
    6359,6358,
    6361,6360,
    6363,6362,
    6365,6364,
    6367,6366
};
static int cfg6001[]=
{
    8221,8220,
    8179,8183,8187,8191,8195,8199,8203,8207,8211,8215,
    8214,8210,8206,8202,8198,8194,8190,8186,8182,8178,
    8216,8217,8212,8213,8208,8209,8204,8205,8200,8201,
      8196,8197,8192,8193,8188,8189,8184,8185,8180,8181,
    8156,8159,8162,8165,8168,8171,8174,8177,
    8154,8157,8160,8163,8166,8169,8172,8175,
    8176,8173,8170,8167,8164,8161,8158,8155,
    8218,8219
};
static int cfg6002[]=
{
    8257,8256,

    8179,8183,8187,8191,8195,8199,8203,8207,8211,8215,
    8214,8210,8206,8202,8198,8194,8190,8186,8182,8178,
    8216,8217,8212,8213,8208,8209,8204,8205,8200,8201,
      8196,8197,8192,8193,8188,8189,8184,8185,8180,8181,
    8255,8254,8253,8252,8251,8250,8249,8248,8247,
      8246,8245,8244,8243,8242,8241,8240,8239,8238,
    8220,8221,8222,8223,8224,8225,8226,8227,8228,
      8229,8230,8231,8232,8233,8234,8235,8236,8237,
    8156,8159,8162,8165,8168,8171,8174,8177,
    8154,8157,8160,8163,8166,8169,8172,8175,
    8176,8173,8170,8167,8164,8161,8158,8155,
    8218,8219
};

/* GAL info */
static struct
{
    GALTYPE type;
    unsigned char id0,id1; /* variant 1, variant 2 (eg. 16V8=0x00, 16V8A+=0x1A)*/
    char *name;       /* pointer to chip name               */
    int fuses;        /* total number of fuses              */
    int pins;         /* number of pins on chip             */
    int rows;         /* number of fuse rows                */
    int bits;         /* number of fuses per row            */
    int uesrow;       /* UES row number                     */
    int uesfuse;      /* first UES fuse number              */
    int uesbytes;     /* number of UES bytes                */
    int eraserow;     /* row adddeess for erase             */
    int eraseallrow;  /* row address for erase all          */
    int pesrow;       /* row address for PES read/write     */
    int pesbytes;     /* number of PES bytes                */
    int cfgrow;       /* row address of config bits         */
    int *cfg;         /* pointer to config bit numbers      */
    int cfgbits;      /* number of config bits              */
}
galinfo[]=
{
    {UNKNOWN,   0x00,0x00,"unknown",     0, 0, 0,  0, 0,   0,0, 0, 0, 0, 8, 0,NULL,0},
    {GAL16V8,   0x00,0x1A,"GAL16V8",  2194,20,32, 64,32,2056,8,63,54,58, 8,60,cfg16V8AB,sizeof(cfg16V8AB)/sizeof(int)},
    {GAL20V8,   0x20,0x3A,"GAL20V8",  2706,24,40, 64,40,2568,8,63,59,58, 8,60,cfg20V8AB,sizeof(cfg20V8AB)/sizeof(int)},
    {GAL22V10,  0x48,0x49,"GAL22V10", 5892,24,44,132,44,5828,8,61,60,58,10,16,cfg22V10,sizeof(cfg22V10)/sizeof(int)},
    {ATF16V8B,  0x00,0x00,"ATF16V8B", 2194,20,32, 64,32,2056,8,63,54,58, 8,60,cfg16V8AB,sizeof(cfg16V8AB)/sizeof(int)},
    {ATF22V10B, 0x00,0x00,"ATF22V10B",5892,24,44,132,44,5828,8,61,60,58,10,16,cfg22V10,sizeof(cfg22V10)/sizeof(int)},
    {ATF22V10C, 0x00,0x00,"ATF22V10C",5892,24,44,132,44,5828,8,61,60,58,10,16,cfg22V10,sizeof(cfg22V10)/sizeof(int)},
    {GAL26CV12,0x58,0x59,"GAL26CV12",6432,28,52,122,52,6368,8,61,60,58,12,16,cfg26CV12,sizeof(cfg26CV12)/sizeof(int)},
    {GAL6001,  0x40,0x41,"GAL6001",  8294,24,78, 75,97,8222,9,63,62,96, 8, 8,cfg6001,sizeof(cfg6001)/sizeof(int)},
    {GAL6002,  0x44,0x44,"GAL6002",  8330,24,78, 75,97,8258,9,63,62,96, 8, 8,cfg6002,sizeof(cfg6002)/sizeof(int)},

};

static GALTYPE gal;
static unsigned char pes[12];

// Globals
FT_HANDLE datHandle = NULL;
FT_HANDLE ctlHandle = NULL;

unsigned char porta;
unsigned char portb;

DWORD dwBytesInQueue = 0;

static void Delay(int msec)
{

	usleep(1000 * msec);
}

static BOOL GetACK(void)
{
unsigned char data;

	FT_GetBitMode(ctlHandle, &data);

	return (data & 0x01) != 0;
}

static BOOL GetSDOUT(void)
{
	return GetACK();
}

static void SetFEED(BOOL on)
{

}

static void SetINIT(BOOL on)
{

}

static void SetSTROBE(BOOL on)
{
	if(on)
		portb |= 0x02;
	else
		portb &= ~0x02;
    	FT_Write(ctlHandle, &portb, 1, &dwBytesInQueue);
}

static void SetSTB(BOOL on)
{
	SetSTROBE(on);
}

static void SetSEL(BOOL on)
{
	if(on)
		portb |= 0x04;
	else
		portb &= ~0x04;
    	FT_Write(ctlHandle, &portb, 1, &dwBytesInQueue);
}

static void SetPV(BOOL on)
{
	SetSEL(on);
}

static void SetSDIN(BOOL on)
{
	if(on)
		porta |= 0x01;
	else
		porta &= ~0x01;
    	FT_Write(datHandle, &porta, 1, &dwBytesInQueue);
}

static void SetRow(int row)
{
	porta = (porta & 0x81) | (row << 1);
	FT_Write(datHandle, &porta, 1, &dwBytesInQueue);
}

static void SetSCLK(BOOL on)
{
	if(on)
		porta |= 0x80;
	else
		porta &= ~0x80;
    	FT_Write(datHandle, &porta, 1, &dwBytesInQueue);
}

static void SetVPP(BOOL on)
{

	if (on)
		SetFEED(1);  // FEED Low = programming voltage
	else
		SetFEED(0);  // FEED high = +12V
}

static void SetVCC(BOOL on)
{
	SetINIT(!on);
}

/* pulse /STB low for some milliseconds */
static void Strobe(int msec)
{
//    Delay(2);
    SetSTB(0);
    Delay(msec);
    SetSTB(1);
//    Delay(2);
}

/* clock bit out to SDIN */
static void SendBit(int bit)
{
    SetSDIN(bit);
    SetSCLK(1);
    SetSCLK(0);
}

static void SendBits(int n,int bit)
{
    while(n-- >0) SendBit(bit);
}

/* send row address bits to SDIN */
/* ATF22V10C MSb first, other 22V10 LSb first */
static void SendAddress(int n, int row)
{
    switch (gal)
    {
    case ATF22V10C:
        while(n-- >1)
        {
            SendBit(row&32);   // clock in row number bits 5-1
            row<<=1;
        }
        SetSDIN(row&32);       // SDIN = row number bit 0
        break;
    default:
        while(n-- >0)
        {
            SendBit(row&1);    // clock in row number bits 0-5
            row>>=1;
        }
        SetSDIN(0); // SDIN = low
    }
}

static void StrobeRow(int row)
{
    switch((int)gal)
    {
    case GAL16V8:
    case GAL20V8:
    case ATF16V8B:
       SetRow(row);         // set RA0-5 to row number
       Strobe(2);           // pulse /STB for 2ms
        break;
    case GAL22V10:
    case ATF22V10B:
    case ATF22V10C:
       SetRow(0);           // set RA0-5 low
       SendAddress(6,row);  // send row number (6 bits)
       SetSTB(0);
       SetSTB(1);           // pulse /STB
       SetSDIN(0);          // SDIN low
    }
}

// clock bit in from SDOUT
static BOOL ReceiveBit(void)
{
    BOOL bit;
    bit=GetSDOUT();
    SetSCLK(1);
    SetSCLK(0);
    return bit;
}

static void GetPES(unsigned char pes[])
{
    int bitmask,byte;

    StrobeRow(galinfo[gal].pesrow);
    for(byte=0;byte<galinfo[gal].pesbytes;byte++)
        {
        pes[byte]=0;
        for(bitmask=0x1;bitmask<=0x80;bitmask<<=1)
            {
            if(ReceiveBit()) pes[byte]|=bitmask;
        }
    }
}

static void TurnOff(void)
{
    Delay(100);
    SetPV(0);    // P/V- low
    SetRow(0x3F);// RA0-5 high
    SetSDIN(1);  // SDIN high
    SetVPP(0);   // Vpp off (+12V)
    SetPV(1);    // P/V- high
    Delay(2);
    SetVCC(0);   // turn off VCC (if controlled)
}


static BOOL TurnOn(void)
{
    SetVPP(0);    // VPP off
    SetPV(0);     // P/V- low
    SetRow(0x3F); // RA0-5 high
    SetSDIN(1);   // SDIN high
    SetSCLK(1);   // SCLK high
    SetSTB(1);    // STB high
    SetVCC(1);    // turn on VCC (if controlled)
    Delay(100);
    SetSCLK(0);   // SCLK low
    SetVPP(0); // VPP = +12V
    Delay(20);
    return TRUE;
}


void quit()
{  
	if(datHandle != NULL) {
		FT_Close(datHandle);
		datHandle = NULL;
		printf("Closed device\n");
	}

	exit(1);
}

int main(int argc, char *argv[])
{
	int i, j;
	FT_STATUS	ftStatus;
	int iport;

	signal(SIGINT, quit);		// trap ctrl-c call quit fn 
	
	iport = 0;
	ftStatus = FT_Open(iport, &datHandle);
	if(ftStatus != FT_OK) {
		/* 
			This can fail if the ftdi_sio driver is loaded
		 	use lsmod to check this and rmmod ftdi_sio to remove
			also rmmod usbserial
		 */
		printf("FT_Open(%d) failed = %d\n", iport, ftStatus);
		return 1;
	}
	iport = 1;
	ftStatus = FT_Open(iport, &ctlHandle);
	if(ftStatus != FT_OK) {
		/* 
			This can fail if the ftdi_sio driver is loaded
		 	use lsmod to check this and rmmod ftdi_sio to remove
			also rmmod usbserial
		 */
		printf("FT_Open(%d) failed = %d\n", iport, ftStatus);
		return 1;
	}

	ftStatus = FT_SetBitMode(datHandle, 0xff, 0x01);
	if(ftStatus != FT_OK) {
		printf("Failed to set Asynchronous Bit bang Mode");
	}

	ftStatus = FT_SetBitMode(ctlHandle, 0x06, 0x01);
	if(ftStatus != FT_OK) {
		printf("Failed to set Asynchronous Bit bang Mode");
	}

	usleep(1000*200);
	ftStatus = FT_Purge(datHandle, FT_PURGE_RX);
	if(ftStatus != FT_OK) {
		printf("Failed to FT_Purge\n");	
	}
	ftStatus = FT_SetBaudRate(datHandle, 9600);
	if(ftStatus != FT_OK) {
		printf("Failed to FT_SetBaudRate\n");	
	}
	usleep(1000*200);
	ftStatus = FT_Purge(ctlHandle, FT_PURGE_RX);
	if(ftStatus != FT_OK) {
		printf("Failed to FT_Purge\n");	
	}
	ftStatus = FT_SetBaudRate(ctlHandle, 9600);
	if(ftStatus != FT_OK) {
		printf("Failed to FT_SetBaudRate\n");	
	}

	gal = GAL22V10;
	TurnOn();
	GetPES(pes);
	TurnOff();
	for (i = 0; i < galinfo[gal].pesbytes; ++i)
		printf("%02x ",pes[i]);
	printf("\n");

	if(datHandle != NULL) {
		FT_Close(datHandle);
		datHandle = NULL;
	}
	if(ctlHandle != NULL) {
		FT_Close(ctlHandle);
		ctlHandle = NULL;
	}
	
	return 0;
}
```

ビルドしてEDITをMAX662Aの12Vに接続して実行してみました。

```
$ ./main
00 05 49 a1 cd a4 03 00 00 00 
```

Programmers Electronic Signatureが拾えたようです。デバイスハックの最初の一歩は固定の値が拾えるところからです。