Browse Source

Merge commit 'legko/master^' into littlefury

Conflicts:
	driver-bitfury.c
	libbitfury.c
	miner.h
Luke Dashjr 12 years ago
parent
commit
7cc6a0bbd2
6 changed files with 201 additions and 126 deletions
  1. 46 40
      driver-bitfury.c
  2. 108 80
      libbitfury.c
  3. 26 3
      libbitfury.h
  4. 4 0
      miner.h
  5. 12 2
      spidevc.c
  6. 5 1
      spidevc.h

+ 46 - 40
driver-bitfury.c

@@ -33,13 +33,21 @@ static bool bitfury_prepare(struct thr_info *thr);
 
 
 static void bitfury_detect(void)
 static void bitfury_detect(void)
 {
 {
+	int chip_n;
 	struct cgpu_info *bitfury_info;
 	struct cgpu_info *bitfury_info;
 	applog(LOG_INFO, "INFO: bitfury_detect");
 	applog(LOG_INFO, "INFO: bitfury_detect");
-	libbitfury_detectChips();
+	chip_n = libbitfury_detectChips();
+	if (!chip_n) {
+		applog(LOG_WARNING, "No Bitfury chips detected!");
+		return;
+	} else {
+		applog(LOG_WARNING, "BITFURY: %d chips detected!", chip_n);
+	}
 
 
 	bitfury_info = calloc(1, sizeof(struct cgpu_info));
 	bitfury_info = calloc(1, sizeof(struct cgpu_info));
 	bitfury_info->drv = &bitfury_drv;
 	bitfury_info->drv = &bitfury_drv;
 	bitfury_info->threads = 1;
 	bitfury_info->threads = 1;
+	bitfury_info->chip_n = chip_n;
 	add_cgpu(bitfury_info);
 	add_cgpu(bitfury_info);
 }
 }
 
 
@@ -49,51 +57,49 @@ static uint32_t bitfury_checkNonce(struct work *work, uint32_t nonce)
 	applog(LOG_INFO, "INFO: bitfury_checkNonce");
 	applog(LOG_INFO, "INFO: bitfury_checkNonce");
 }
 }
 
 
+
 static int64_t bitfury_scanHash(struct thr_info *thr)
 static int64_t bitfury_scanHash(struct thr_info *thr)
 {
 {
-	int i;
-	unsigned char sendbuf[44];
-	unsigned int res[16];
-	unsigned char flipped_data[81];
-	unsigned char work_hex[161];
-	unsigned char *mid_hex;
-	unsigned hashMerkleRoot7;
-	unsigned ntime, nbits, nnonce;
-	static struct work *owork; //old work
-	struct work *work;
-	int j;
-
-	work = get_queued(thr->cgpu);
-	if (work == NULL) {
-		return 0;
+	static struct bitfury_device devices[100];
+	int chip_n;
+	int chip;
+	uint64_t hashes = 0;
+
+	chip_n = thr->cgpu->chip_n;
+
+	for (chip = 0; chip < chip_n; chip++) {
+		if(!devices[chip].work) {
+			devices[chip].work = get_queued(thr->cgpu);
+			if (devices[chip].work == NULL) {
+				return 0;
+			}
+			work_to_payload(&(devices[chip].payload), devices[chip].work);
+		}
 	}
 	}
 
 
-	flipped_data[80]= '\0';
-	swap32yes(flipped_data, work->data, 80 / 4);
-	bin2hex(work_hex, flipped_data, 80);
-
-	hashMerkleRoot7 = *(unsigned *)(flipped_data + 64);
-	ntime = *(unsigned *)(flipped_data + 68);
-	nbits = *(unsigned *)(flipped_data + 72);
-	nnonce = *(unsigned *)(flipped_data + 76);
-	applog(LOG_INFO, "INFO bitfury_scanHash MS0: %08x, ", ((unsigned int *)work->midstate)[0]);
-	applog(LOG_INFO, "INFO merkle[7]: %08x, ntime: %08x, nbits: %08x, nnonce: %08x",
-		  hashMerkleRoot7, ntime, nbits, nnonce);
-
-	libbitfury_sendHashData(work->midstate, hashMerkleRoot7, ntime, nbits, nnonce);
-
-	i = libbitfury_readHashData(res);
-	for (j = i - 1; j >= 0; j--) {
-		if (owork) {
-			submit_nonce(thr, owork, bswap_32(res[j]));
+	libbitfury_sendHashData(devices, chip_n);
+
+	for (chip = 0; chip < chip_n; chip++) {
+		if (devices[chip].job_switched) {
+			int i,j;
+			int *res = devices[chip].results;
+			struct work *owork = devices[chip].owork;
+			i = devices[chip].results_n;
+			for (j = i - 1; j >= 0; j--) {
+				if (owork) {
+					submit_nonce(thr, owork, bswap_32(res[j]));
+				}
+			}
+
+			if (owork)
+				work_completed(thr->cgpu, owork);
+
+			devices[chip].owork = devices[chip].work;
+			devices[chip].work = NULL;
+			hashes += 0xffffffffull * i;
 		}
 		}
 	}
 	}
-
-	if (owork)
-		work_completed(thr->cgpu, owork);
-
-	owork = work;
-	return 0xffffffffull * i;
+	return hashes;
 }
 }
 
 
 static bool bitfury_prepare(struct thr_info *thr)
 static bool bitfury_prepare(struct thr_info *thr)

+ 108 - 80
libbitfury.c

@@ -31,15 +31,15 @@
 
 
 #include <time.h>
 #include <time.h>
 
 
+#define BITFURY_REFRESH_DELAY 100
+#define BITFURY_DETECT_TRIES 3000 / BITFURY_REFRESH_DELAY
+
 // 0 .... 31 bit
 // 0 .... 31 bit
 // 1000 0011 0101 0110 1001 1010 1100 0111
 // 1000 0011 0101 0110 1001 1010 1100 0111
 
 
 // 1100 0001 0110 1010 0101 1001 1110 0011
 // 1100 0001 0110 1010 0101 1001 1110 0011
 // C16A59E3
 // C16A59E3
 
 
-unsigned results[16];
-unsigned results_num = 0;
-
 unsigned char enaconf[4] = { 0xc1, 0x6a, 0x59, 0xe3 };
 unsigned char enaconf[4] = { 0xc1, 0x6a, 0x59, 0xe3 };
 unsigned char disconf[4] = { 0, 0, 0, 0 };
 unsigned char disconf[4] = { 0, 0, 0, 0 };
 
 
@@ -68,7 +68,7 @@ char outbuf[16];
 /* Thermal runaway in this case could produce nice flames of chippy fries */
 /* Thermal runaway in this case could produce nice flames of chippy fries */
 
 
 // Thermometer code from left to right - more ones ==> faster clock!
 // Thermometer code from left to right - more ones ==> faster clock!
-unsigned char osc6[8] = { 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+unsigned char osc6[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00 };
 
 
 /* Test vectors to calculate (using address-translated loads) */
 /* Test vectors to calculate (using address-translated loads) */
 unsigned atrvec[] = {
 unsigned atrvec[] = {
@@ -130,18 +130,23 @@ void ms3_compute(unsigned *p)
 	p[15] = a; p[14] = b; p[13] = c; p[12] = d; p[11] = e; p[10] = f; p[9] = g; p[8] = h;
 	p[15] = a; p[14] = b; p[13] = c; p[12] = d; p[11] = e; p[10] = f; p[9] = g; p[8] = h;
 }
 }
 
 
-int libbitfury_detectChips(void) {
+int detect_chip(int chip_n) {
 	unsigned w[16];
 	unsigned w[16];
 	int i;
 	int i;
+	unsigned newbuf[17], oldbuf[17];
+
+	memset(newbuf, 0, 17 * 4);
+	memset(oldbuf, 0, 17 * 4);
 
 
 	ms3_compute(&atrvec[0]);
 	ms3_compute(&atrvec[0]);
 	ms3_compute(&atrvec[20]);
 	ms3_compute(&atrvec[20]);
 	ms3_compute(&atrvec[40]);
 	ms3_compute(&atrvec[40]);
 	spi_init();
 	spi_init();
 
 
-	spi_clear_buf();
 
 
+	spi_clear_buf();
 	spi_emit_break(); /* First we want to break chain! Otherwise we'll get all of traffic bounced to output */
 	spi_emit_break(); /* First we want to break chain! Otherwise we'll get all of traffic bounced to output */
+	spi_emit_fasync(chip_n);
 	spi_emit_data(0x6000, (void*)osc6, 8); /* Program internal on-die slow oscillator frequency */
 	spi_emit_data(0x6000, (void*)osc6, 8); /* Program internal on-die slow oscillator frequency */
 	config_reg(7,0); config_reg(8,0); config_reg(9,0); config_reg(10,0); config_reg(11,0);
 	config_reg(7,0); config_reg(8,0); config_reg(9,0); config_reg(10,0); config_reg(11,0);
 	config_reg(6,1);
 	config_reg(6,1);
@@ -158,10 +163,38 @@ int libbitfury_detectChips(void) {
 	spi_emit_data(0x1900, (void*)&w[0],8*4); /* Prepare MS and W buffers! */
 	spi_emit_data(0x1900, (void*)&w[0],8*4); /* Prepare MS and W buffers! */
 
 
 	spi_emit_data(0x3000, (void*)&atrvec[0], 19*4);
 	spi_emit_data(0x3000, (void*)&atrvec[0], 19*4);
-
 	spi_txrx(spi_gettxbuf(), spi_getrxbuf(), spi_getbufsz());
 	spi_txrx(spi_gettxbuf(), spi_getrxbuf(), spi_getbufsz());
 
 
-	return 1;
+	for (i = 0; i < BITFURY_DETECT_TRIES; i++) {
+		spi_clear_buf();
+		spi_emit_break();
+		spi_emit_fasync(chip_n);
+		spi_emit_data(0x3000, (void*)&atrvec[0], 19*4);
+		spi_txrx(spi_gettxbuf(), spi_getrxbuf(), spi_getbufsz());
+		memcpy(newbuf, spi_getrxbuf() + 4 + chip_n, 17*4);
+		if (newbuf[16] != 0 && newbuf[16] != 0xFFFFFFFF) {
+			return 0;
+		}
+		if (i && newbuf[16] != oldbuf[16])
+			return 1;
+		cgsleep_ms(BITFURY_REFRESH_DELAY);
+		memcpy(oldbuf, newbuf, 17 * 4);
+	}
+	return 0;
+}
+
+int libbitfury_detectChips(void) {
+	int n = 0;
+	int detected;
+	do {
+		detected = detect_chip(n);
+		if (detected) {
+			n++;
+		applog(LOG_WARNING, "BITFURY chip #%d detected", n);
+		} else {
+		}
+	} while (detected);
+	return n;
 }
 }
 
 
 unsigned decnonce(unsigned in)
 unsigned decnonce(unsigned in)
@@ -204,103 +237,98 @@ int rehash(unsigned char *midstate, unsigned m7,
 	ctx.len = 0;
 	ctx.len = 0;
 
 
 	nnonce = bswap_32(nnonce);
 	nnonce = bswap_32(nnonce);
-	in32[0] = m7;
-	in32[1] = ntime;
-	in32[2] = nbits;
+	in32[0] = bswap_32(m7);
+	in32[1] = bswap_32(ntime);
+	in32[2] = bswap_32(nbits);
 	in32[3] = nnonce;
 	in32[3] = nnonce;
 
 
 	sha256_update(&ctx, in, 16);
 	sha256_update(&ctx, in, 16);
 	sha256_final(&ctx, out);
 	sha256_final(&ctx, out);
 	sha256(out, 32, out);
 	sha256(out, 32, out);
+
 	if (out32[7] == 0) {
 	if (out32[7] == 0) {
 		bin2hex(hex, midstate, 32);
 		bin2hex(hex, midstate, 32);
 		bin2hex(hex, out, 32);
 		bin2hex(hex, out, 32);
-		applog(LOG_INFO, "!!!!!!!!!!!! MS0: %08x, m7: %08x, ntime: %08x, nbits: %08x, nnonce: %08x\n\t\t\t out: %s\n", mid32[0], m7, ntime, nbits, nnonce, hex);
+		applog(LOG_INFO, "! MS0: %08x, m7: %08x, ntime: %08x, nbits: %08x, nnonce: %08x\n\t\t\t out: %s\n", mid32[0], m7, ntime, nbits, nnonce, hex);
 		return 1;
 		return 1;
 	}
 	}
 	return 0;
 	return 0;
 }
 }
 
 
-int libbitfury_sendHashData(unsigned char *midstate, unsigned m7,
-						 unsigned ntime, unsigned nbits,
-						 unsigned nnonce) {
-	int i;
+void work_to_payload(struct bitfury_payload *p, struct work *w) {
+	unsigned char flipped_data[80];
 
 
-	/* Communication routine with the chip! */
-	static unsigned oldbuf[17], newbuf[17];
-	unsigned char hash[32];
-	unsigned char mids[32];
-	unsigned int *mids32 = (unsigned int *) mids;
-	unsigned int *mid32 = (unsigned int *) midstate;
-	static unsigned char om[32]; // old midstate
-	static unsigned int *omid32 = (unsigned int *)om;
-	static unsigned om7;
-	static unsigned ontime;
-	static unsigned onbits;
-	int job;
-
-/*	mids32[0] = 0xf4f07c9f;
-	mids32[1] = 0x7ecd6e06;
-	mids32[2] = 0xfeef14a1;
-	mids32[3] = 0x84e244d6;
-	mids32[4] = 0x6f1dcc58;
-	mids32[5] = 0x0a97b253;
-	mids32[6] = 0x20d3de1f;
-	mids32[7] = 0xc907cd69;
-	hashMerkleRoot7 = bswap_32(0xaec2a48e);
-	ntime = bswap_32(0x2da02c4f);
-	nbits = bswap_32(0x3fd40c1a);
-	nnonce = bswap_32(0x50591118);
-	nnonce = 0;
-	memcpy(midstate, mids, 32); */
-
-	/* Programming next value */
-	for (i = 0; i < 8; i++) { atrvec[8+i] = 0; atrvec[i] = mid32[i]; }
-	atrvec[16] = bswap_32(m7);
-	atrvec[17] = bswap_32(ntime);
-	atrvec[18] = bswap_32(nbits); atrvec[19] = 0; //Nonce
-	ms3_compute(&atrvec[0]);
+	memset(p, 0, sizeof(struct bitfury_payload));
+	swap32yes(flipped_data, w->data, 80 / 4);
+
+	memcpy(p->midstate, w->midstate, 32);
+	p->m7 = bswap_32(*(unsigned *)(flipped_data + 64));
+	p->ntime = bswap_32(*(unsigned *)(flipped_data + 68));
+	p->nbits = bswap_32(*(unsigned *)(flipped_data + 72));
+	applog(LOG_INFO, "INFO nonc: %08x bitfury_scanHash MS0: %08x, ", p->nnonce, ((unsigned int *)w->midstate)[0]);
+	applog(LOG_INFO, "INFO merkle[7]: %08x, ntime: %08x, nbits: %08x", p->m7, p->ntime, p->nbits);
+}
+
+int libbitfury_sendHashData(struct bitfury_device *bf, int chip_n) {
+	int chip;
+	static unsigned second_run;
+
+	for (chip = 0; chip < chip_n; chip++) {
+		unsigned char *hexstr;
+		struct bitfury_device *d = bf + chip;
+		unsigned *newbuf = d->newbuf;
+		unsigned *oldbuf = d->oldbuf;
+		struct bitfury_payload *p = &(d->payload);
+		struct bitfury_payload *op = &(d->opayload);
+
+
+		/* Programming next value */
+		memcpy(atrvec, p, 20*4);
+		ms3_compute(atrvec);
 
 
-	results_num = 0;
-	while(newbuf[16] == oldbuf[16]) {
 		spi_clear_buf(); spi_emit_break();
 		spi_clear_buf(); spi_emit_break();
+		spi_emit_fasync(chip);
 		spi_emit_data(0x3000, (void*)&atrvec[0], 19*4);
 		spi_emit_data(0x3000, (void*)&atrvec[0], 19*4);
 		spi_txrx(spi_gettxbuf(), spi_getrxbuf(), spi_getbufsz());
 		spi_txrx(spi_gettxbuf(), spi_getrxbuf(), spi_getbufsz());
 
 
-		memcpy(newbuf, spi_getrxbuf()+4, 17*4);
-
-		cgsleep_ms(100);
-	}
-
-	for (i = 0; i < 16; i++) {
-		if (oldbuf[i] != newbuf[i]) {
-			unsigned pn; //possible nonce
-			unsigned int s = 0; //TODO zero may be solution
-			pn = decnonce(newbuf[i]);
-			s |= rehash(om, om7, ontime, onbits, pn) ? pn : 0;
-			s |= rehash(om, om7, ontime, onbits, pn-0x400000) ? pn - 0x400000 : 0;
-			s |= rehash(om, om7, ontime, onbits, pn-0x800000) ? pn - 0x800000 : 0;
-			s |= rehash(om, om7, ontime, onbits, pn+0x2800000)? pn + 0x2800000 : 0;
-			s |= rehash(om, om7, ontime, onbits, pn+0x2C00000)? pn + 0x2C00000 : 0;
-			s |= rehash(om, om7, ontime, onbits, pn+0x400000) ? pn + 0x400000 : 0;
-			if (s) {
-				results[results_num++] = bswap_32(s);
+		memcpy(newbuf, spi_getrxbuf()+4 + chip, 17*4);
+
+		d->job_switched = newbuf[16] != oldbuf[16];
+
+		if (second_run && d->job_switched) {
+			int i;
+			int results_num = 0;
+			unsigned * results = d->results;
+			for (i = 0; i < 16; i++) {
+				if (oldbuf[i] != newbuf[i]) {
+					unsigned pn; //possible nonce
+					unsigned int s = 0; //TODO zero may be solution
+					pn = decnonce(newbuf[i]);
+					s |= rehash(op->midstate, op->m7, op->ntime, op->nbits, pn) ? pn : 0;
+					s |= rehash(op->midstate, op->m7, op->ntime, op->nbits, pn-0x400000) ? pn - 0x400000 : 0;
+					s |= rehash(op->midstate, op->m7, op->ntime, op->nbits, pn-0x800000) ? pn - 0x800000 : 0;
+					s |= rehash(op->midstate, op->m7, op->ntime, op->nbits, pn+0x2800000)? pn + 0x2800000 : 0;
+					s |= rehash(op->midstate, op->m7, op->ntime, op->nbits, pn+0x2C00000)? pn + 0x2C00000 : 0;
+					s |= rehash(op->midstate, op->m7, op->ntime, op->nbits, pn+0x400000) ? pn + 0x400000 : 0;
+					if (s) {
+						results[results_num++] = bswap_32(s);
+					}
+				}
 			}
 			}
-		}
-	}
+			d->results_n = results_num;
 
 
-	om7 = m7;
-	ontime = ntime;
-	onbits = nbits;
-	memcpy(om, midstate, 32);
+			memcpy(op, p, sizeof(struct bitfury_payload));
+			memcpy(oldbuf, newbuf, 17 * 4);
+		}
 
 
-	memcpy(oldbuf, newbuf, sizeof(oldbuf));
+		cgsleep_ms(BITFURY_REFRESH_DELAY);
+	}
+	second_run = 1;
 
 
-	return 0;
+	return;
 }
 }
 
 
 int libbitfury_readHashData(unsigned int *res) {
 int libbitfury_readHashData(unsigned int *res) {
-	memcpy(res, results, 16*4);
-	return results_num;
+	return 0;
 }
 }
 
 

+ 26 - 3
libbitfury.h

@@ -19,11 +19,34 @@
 #ifndef __LIBBITFURY_H__
 #ifndef __LIBBITFURY_H__
 #define __LIBBITFURY_H__
 #define __LIBBITFURY_H__
 
 
+#include "miner.h"
+
 extern int libbitfury_detectChips(void);
 extern int libbitfury_detectChips(void);
-int libbitfury_sendHashData(unsigned char *midstate, unsigned m7,
-						 unsigned ntime, unsigned nbits,
-						 unsigned nnonce);
+
+struct bitfury_payload {
+	unsigned char midstate[32];
+	unsigned int junk[8];
+	unsigned m7;
+	unsigned ntime;
+	unsigned nbits;
+	unsigned nnonce;
+};
+
+struct bitfury_device {
+	unsigned char osc[8];
+	unsigned newbuf[17];
+	unsigned oldbuf[17];
+	struct work * work;
+	struct work * owork;
+	int job_switched;
+	struct bitfury_payload payload;
+	struct bitfury_payload opayload;
+	unsigned int results[16];
+	int results_n;
+};
 
 
 int libbitfury_readHashData(unsigned int *res);
 int libbitfury_readHashData(unsigned int *res);
+int libbitfury_sendHashData(struct bitfury_device *bf, int chip_n);
+void work_to_payload(struct bitfury_payload *p, struct work *w);
 
 
 #endif /* __LIBBITFURY_H__ */
 #endif /* __LIBBITFURY_H__ */

+ 4 - 0
miner.h

@@ -486,6 +486,10 @@ struct cgpu_info {
 	pthread_mutex_t		device_mutex;
 	pthread_mutex_t		device_mutex;
 	pthread_cond_t	device_cond;
 	pthread_cond_t	device_cond;
 
 
+#ifdef USE_BITFURY
+	int chip_n;
+#endif
+
 	enum dev_enable deven;
 	enum dev_enable deven;
 	int accepted;
 	int accepted;
 	int rejected;
 	int rejected;

+ 12 - 2
spidevc.c

@@ -1,3 +1,7 @@
+/*
+ *  Copyright 2013 www.bitfury.org
+ */
+
 #include "spidevc.h"
 #include "spidevc.h"
 #include <sys/mman.h>
 #include <sys/mman.h>
 #include <stdint.h>
 #include <stdint.h>
@@ -88,7 +92,7 @@ int spi_txrx(const char *wrbuf, char *rdbuf, int bufsz)
 	struct spi_ioc_transfer tr[16];
 	struct spi_ioc_transfer tr[16];
 
 
 	memset(&tr,0,sizeof(tr));
 	memset(&tr,0,sizeof(tr));
-	mode = 0; bits = 8; speed = 2000000;
+	mode = 0; bits = 8; speed = 200000;
 
 
 	spi_reset();
 	spi_reset();
 	fd = open("/dev/spidev0.0", O_RDWR);
 	fd = open("/dev/spidev0.0", O_RDWR);
@@ -165,7 +169,13 @@ void spi_emit_buf(const char *str, unsigned sz)
 /* TODO: in production, emit just bit-sequences! Eliminate padding to byte! */
 /* TODO: in production, emit just bit-sequences! Eliminate padding to byte! */
 void spi_emit_break(void) { spi_emit_buf("\x4", 1); }
 void spi_emit_break(void) { spi_emit_buf("\x4", 1); }
 void spi_emit_fsync(void) { spi_emit_buf("\x6", 1); }
 void spi_emit_fsync(void) { spi_emit_buf("\x6", 1); }
-void spi_emit_fasync(void) { spi_emit_buf("\x5", 1); }
+
+void spi_emit_fasync(int n) {
+	int i;
+	for (i = 0; i < n; i++) {
+		spi_emit_buf("\x5", 1);
+	}
+}
 
 
 void spi_emit_data(unsigned addr, const char *buf, unsigned len)
 void spi_emit_data(unsigned addr, const char *buf, unsigned len)
 {
 {

+ 5 - 1
spidevc.h

@@ -1,3 +1,7 @@
+/*
+ *  Copyright 2013 www.bitfury.org
+ */
+
 #ifndef SPIDEVC_H
 #ifndef SPIDEVC_H
 #define SPIDEVC_H
 #define SPIDEVC_H
 
 
@@ -18,7 +22,7 @@ void spi_emit_buf(const char *str, unsigned sz); /* INTERNAL USE: EMIT BYTE SEQU
 
 
 void spi_emit_break(void); /* BREAK CONNECTIONS AFTER RESET */
 void spi_emit_break(void); /* BREAK CONNECTIONS AFTER RESET */
 void spi_emit_fsync(void); /* FEED-THROUGH TO NEXT CHIP SYNCHRONOUSLY (WITH FLIP-FLOP) */
 void spi_emit_fsync(void); /* FEED-THROUGH TO NEXT CHIP SYNCHRONOUSLY (WITH FLIP-FLOP) */
-void spi_emit_fasync(void); /* FEED-THROUGH TO NEXT CHIP ASYNCHRONOUSLY (WITHOUT FLIP-FLOP INTERMEDIATE) */
+void spi_emit_fasync(int n); /* FEED-THROUGH TO NEXT CHIP ASYNCHRONOUSLY (WITHOUT FLIP-FLOP INTERMEDIATE) */
 
 
 /* TRANSMIT PROGRAMMING SEQUENCE (AND ALSO READ-BACK) */
 /* TRANSMIT PROGRAMMING SEQUENCE (AND ALSO READ-BACK) */
 /* addr is the destination address in bits (16-bit - 0 to 0xFFFF valid ones)
 /* addr is the destination address in bits (16-bit - 0 to 0xFFFF valid ones)