Browse Source

Merge remote-tracking branch 'legko/master' into littlefury

Conflicts:
	Makefile.am
	driver-bitfury.c
	libbitfury.c
	miner.h
Luke Dashjr 12 years ago
parent
commit
7a3ce8668d
9 changed files with 766 additions and 97 deletions
  1. 1 1
      Makefile.am
  2. 164 10
      driver-bitfury.c
  3. 404 57
      libbitfury.c
  4. 27 2
      libbitfury.h
  5. 1 3
      miner.h
  6. 17 24
      spidevc.c
  7. 1 0
      spidevc.h
  8. 106 0
      tm_i2c.c
  9. 45 0
      tm_i2c.h

+ 1 - 1
Makefile.am

@@ -211,7 +211,7 @@ bfgminer_SOURCES += driver-ztex.c libztex.c libztex.h
 endif
 
 if HAS_BITFURY
-bfgminer_SOURCES += driver-bitfury.c libbitfury.c libbitfury.h spidevc.h spidevc.c
+bfgminer_SOURCES += driver-bitfury.c libbitfury.c libbitfury.h spidevc.h spidevc.c tm_i2c.h tm_i2c.c
 endif
 
 bin_PROGRAMS += bfgminer-rpc

+ 164 - 10
driver-bitfury.c

@@ -37,13 +37,21 @@ struct device_drv bitfury_drv;
 // Forward declarations
 static void bitfury_disable(struct thr_info* thr);
 static bool bitfury_prepare(struct thr_info *thr);
+int calc_stat(time_t * stat_ts, time_t stat, struct timeval now);
+double shares_to_ghashes(int shares, int seconds);
 
 static void bitfury_detect(void)
 {
 	int chip_n;
+	int i;
 	struct cgpu_info *bitfury_info;
+
+	bitfury_info = calloc(1, sizeof(struct cgpu_info));
+	bitfury_info->drv = &bitfury_drv;
+	bitfury_info->threads = 1;
+
 	applog(LOG_INFO, "INFO: bitfury_detect");
-	chip_n = libbitfury_detectChips();
+	chip_n = libbitfury_detectChips(bitfury_info->devices);
 	if (!chip_n) {
 		applog(LOG_WARNING, "No Bitfury chips detected!");
 		return;
@@ -51,30 +59,47 @@ static void bitfury_detect(void)
 		applog(LOG_WARNING, "BITFURY: %d chips detected!", chip_n);
 	}
 
-	bitfury_info = calloc(1, sizeof(struct cgpu_info));
-	bitfury_info->drv = &bitfury_drv;
-	bitfury_info->threads = 1;
 	bitfury_info->chip_n = chip_n;
 	add_cgpu(bitfury_info);
 }
 
-
 static uint32_t bitfury_checkNonce(struct work *work, uint32_t nonce)
 {
 	applog(LOG_INFO, "INFO: bitfury_checkNonce");
 }
 
-
 static int64_t bitfury_scanHash(struct thr_info *thr)
 {
-	static struct bitfury_device devices[100];
+	static struct bitfury_device *devices; // TODO Move somewhere to appropriate place
 	int chip_n;
 	int chip;
 	uint64_t hashes = 0;
+	struct timeval now;
+	unsigned char line[2048];
+	int short_stat = 10;
+	static time_t short_out_t;
+	int long_stat = 1800;
+	static time_t long_out_t;
+	int long_long_stat = 60 * 30;
+	static time_t long_long_out_t;
+	static first = 0; //TODO Move to detect()
+	int i;
 
+	devices = thr->cgpu->devices;
 	chip_n = thr->cgpu->chip_n;
 
+	if (!first) {
+		for (i = 0; i < chip_n; i++) {
+			devices[i].osc6_bits = 54;
+		}
+		for (i = 0; i < chip_n; i++) {
+			send_reinit(devices[i].slot, devices[i].fasync, devices[i].osc6_bits);
+		}
+	}
+	first = 1;
+
 	for (chip = 0; chip < chip_n; chip++) {
+		devices[chip].job_switched = 0;
 		if(!devices[chip].work) {
 			devices[chip].work = get_queued(thr->cgpu);
 			if (devices[chip].work == NULL) {
@@ -85,30 +110,153 @@ static int64_t bitfury_scanHash(struct thr_info *thr)
 	}
 
 	libbitfury_sendHashData(devices, chip_n);
+	cgsleep_ms(5);
 
-	for (chip = 0; chip < chip_n; chip++) {
+	cgtime(&now);
+	chip = 0;
+	for (;chip < chip_n; chip++) {
 		if (devices[chip].job_switched) {
 			int i,j;
 			int *res = devices[chip].results;
+			struct work *work = devices[chip].work;
 			struct work *owork = devices[chip].owork;
+			struct work *o2work = devices[chip].o2work;
 			i = devices[chip].results_n;
 			for (j = i - 1; j >= 0; j--) {
 				if (owork) {
 					submit_nonce(thr, owork, bswap_32(res[j]));
+					devices[chip].stat_ts[devices[chip].stat_counter++] =
+						now.tv_sec;
+					if (devices[chip].stat_counter == BITFURY_STAT_N) {
+						devices[chip].stat_counter = 0;
+					}
+				}
+				if (o2work) {
+					// TEST
+					//submit_nonce(thr, owork, bswap_32(res[j]));
 				}
 			}
+			devices[chip].results_n = 0;
+			devices[chip].job_switched = 0;
+			if (devices[chip].old_nonce && o2work) {
+					submit_nonce(thr, o2work, bswap_32(devices[chip].old_nonce));
+					i++;
+			}
+			if (devices[chip].future_nonce) {
+					submit_nonce(thr, work, bswap_32(devices[chip].future_nonce));
+					i++;
+			}
 
-			if (owork)
-				work_completed(thr->cgpu, owork);
+			if (o2work)
+				work_completed(thr->cgpu, o2work);
 
+			devices[chip].o2work = devices[chip].owork;
 			devices[chip].owork = devices[chip].work;
 			devices[chip].work = NULL;
 			hashes += 0xffffffffull * i;
 		}
 	}
+
+	if (now.tv_sec - short_out_t > short_stat) {
+		int shares_first = 0, shares_last = 0, shares_total = 0;
+		char stat_lines[32][256] = {0};
+		int len, k;
+		double gh[32][8] = {0};
+		double ghsum = 0, gh1h = 0, gh2h = 0;
+
+		for (chip = 0; chip < chip_n; chip++) {
+			int shares_found = calc_stat(devices[chip].stat_ts, short_stat, now);
+			double ghash;
+			len = strlen(stat_lines[devices[chip].slot]);
+			ghash = shares_to_ghashes(shares_found, short_stat);
+			gh[devices[chip].slot][chip & 0x07] = ghash;
+			snprintf(stat_lines[devices[chip].slot] + len, 256 - len, "%.1f-%3.0f ", ghash, devices[chip].mhz);
+
+			if(short_out_t && ghash < 1.0) {
+				applog(LOG_WARNING, "Chip_id %d FREQ CHANGE\n", chip);
+				send_freq(devices[chip].slot, devices[chip].fasync, devices[chip].osc6_bits - 1);
+				cgsleep_ms(1);
+				send_freq(devices[chip].slot, devices[chip].fasync, devices[chip].osc6_bits);
+			}
+			shares_total += shares_found;
+			shares_first += chip < 4 ? shares_found : 0;
+			shares_last += chip > 3 ? shares_found : 0;
+		}
+		sprintf(line, "vvvvwww SHORT stat %ds: wwwvvvv", short_stat);
+		applog(LOG_WARNING, line);
+		for(i = 0; i < 32; i++)
+			if(strlen(stat_lines[i])) {
+				len = strlen(stat_lines[i]);
+				ghsum = 0;
+				gh1h = 0;
+				gh2h = 0;
+				for(k = 0; k < 4; k++) {
+					gh1h += gh[i][k];
+					gh2h += gh[i][k+4];
+					ghsum += gh[i][k] + gh[i][k+4];
+				}
+				snprintf(stat_lines[i] + len, 256 - len, "- %2.1f + %2.1f = %2.1f slot %i ", gh1h, gh2h, ghsum, i);
+				applog(LOG_WARNING, stat_lines[i]);
+			}
+		short_out_t = now.tv_sec;
+	}
+
+	if (now.tv_sec - long_out_t > long_stat) {
+		int shares_first = 0, shares_last = 0, shares_total = 0;
+		char stat_lines[32][256] = {0};
+		int len, k;
+		double gh[32][8] = {0};
+		double ghsum = 0, gh1h = 0, gh2h = 0;
+
+		for (chip = 0; chip < chip_n; chip++) {
+			int shares_found = calc_stat(devices[chip].stat_ts, long_stat, now);
+			double ghash;
+			len = strlen(stat_lines[devices[chip].slot]);
+			ghash = shares_to_ghashes(shares_found, long_stat);
+			gh[devices[chip].slot][chip & 0x07] = ghash;
+			snprintf(stat_lines[devices[chip].slot] + len, 256 - len, "%.1f-%3.0f ", ghash, devices[chip].mhz);
+
+			shares_total += shares_found;
+			shares_first += chip < 4 ? shares_found : 0;
+			shares_last += chip > 3 ? shares_found : 0;
+		}
+		sprintf(line, "!!!_________ LONG stat %ds: ___________!!!", long_stat);
+		applog(LOG_WARNING, line);
+		for(i = 0; i < 32; i++)
+			if(strlen(stat_lines[i])) {
+				len = strlen(stat_lines[i]);
+				ghsum = 0;
+				gh1h = 0;
+				gh2h = 0;
+				for(k = 0; k < 4; k++) {
+					gh1h += gh[i][k];
+					gh2h += gh[i][k+4];
+					ghsum += gh[i][k] + gh[i][k+4];
+				}
+				snprintf(stat_lines[i] + len, 256 - len, "- %2.1f + %2.1f = %2.1f slot %i ", gh1h, gh2h, ghsum, i);
+				applog(LOG_WARNING, stat_lines[i]);
+			}
+		long_out_t = now.tv_sec;
+	}
+
 	return hashes;
 }
 
+double shares_to_ghashes(int shares, int seconds) {
+	return (double)shares / (double)seconds * 4.84387;  //orig: 4.77628
+}
+
+int calc_stat(time_t * stat_ts, time_t stat, struct timeval now) {
+	int j;
+	int shares_found = 0;
+	for(j = 0; j < BITFURY_STAT_N; j++) {
+		if (now.tv_sec - stat_ts[j] < stat) {
+			shares_found++;
+		}
+	}
+	return shares_found;
+}
+
 static bool bitfury_prepare(struct thr_info *thr)
 {
 	struct cgpu_info *cgpu = thr->cgpu;
@@ -121,7 +269,13 @@ static bool bitfury_prepare(struct thr_info *thr)
 
 static void bitfury_shutdown(struct thr_info *thr)
 {
+	int chip_n;
+	int i;
+
+	chip_n = thr->cgpu->chip_n;
+
 	applog(LOG_INFO, "INFO bitfury_shutdown");
+	libbitfury_shutdownChips(thr->cgpu->devices, chip_n);
 }
 
 static void bitfury_disable(struct thr_info *thr)

+ 404 - 57
libbitfury.c

@@ -31,6 +31,7 @@
 #include <string.h>
 
 #include "miner.h"
+#include "tm_i2c.h"
 #include "libbitfury.h"
 
 #include "spidevc.h"
@@ -50,6 +51,8 @@
 unsigned char enaconf[4] = { 0xc1, 0x6a, 0x59, 0xe3 };
 unsigned char disconf[4] = { 0, 0, 0, 0 };
 
+unsigned decnonce(unsigned in);
+
 /* Configuration registers - control oscillators and such stuff. PROGRAMMED when magic number is matches, UNPROGRAMMED (default) otherwise */
 void config_reg(int cfgreg, int ena)
 {
@@ -75,7 +78,6 @@ char outbuf[16];
 /* Thermal runaway in this case could produce nice flames of chippy fries */
 
 // Thermometer code from left to right - more ones ==> faster clock!
-unsigned char osc6[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00 };
 
 /* Test vectors to calculate (using address-translated loads) */
 unsigned atrvec[] = {
@@ -121,6 +123,41 @@ static const unsigned SHA_K[64] = {
         0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
 };
 
+void t_print(struct timespec d_time) {
+	printf(" %ds %.2fms\n", (int)d_time.tv_sec, (double)d_time.tv_nsec / 1000000.0);
+}
+
+
+
+struct  timespec t_add(struct  timespec  time1, struct  timespec  time2) {
+    struct  timespec  result ;
+
+    result.tv_sec = time1.tv_sec + time2.tv_sec ;
+    result.tv_nsec = time1.tv_nsec + time2.tv_nsec ;
+    if (result.tv_nsec >= 1000000000L) {
+        result.tv_sec++ ;  result.tv_nsec = result.tv_nsec - 1000000000L ;
+    }
+
+    return (result) ;
+}
+
+
+
+struct timespec t_diff(struct timespec start, struct timespec end)
+{
+	struct timespec temp;
+	if (end.tv_nsec < start.tv_nsec) {
+		temp.tv_sec = end.tv_sec-start.tv_sec-1;
+		temp.tv_nsec = 1000000000LU;
+		temp.tv_nsec -= start.tv_nsec;
+		temp.tv_nsec += end.tv_nsec;
+	} else {
+		temp.tv_sec = end.tv_sec-start.tv_sec;
+		temp.tv_nsec = end.tv_nsec-start.tv_nsec;
+	}
+	return temp;
+}
+
 void ms3_compute(unsigned *p)
 {
 	unsigned a,b,c,d,e,f,g,h, ne, na,  i;
@@ -137,10 +174,102 @@ 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;
 }
 
-int detect_chip(int chip_n) {
+void send_conf() {
+	config_reg(7,0); config_reg(8,0); config_reg(9,0); config_reg(10,0); config_reg(11,0);
+	config_reg(6,0); /* disable OUTSLK */
+	config_reg(4,1); /* Enable slow oscillator */
+	config_reg(1,0); config_reg(2,0); config_reg(3,0);
+	spi_emit_data(0x0100, (void*)counters, 16); /* Program counters correctly for rounds processing, here baby should start consuming power */
+}
+
+void send_init() {
+	/* Prepare internal buffers */
+	/* PREPARE BUFFERS (INITIAL PROGRAMMING) */
 	unsigned w[16];
+	unsigned atrvec[] = {
+		0xb0e72d8e, 0x1dc5b862, 0xe9e7c4a6, 0x3050f1f5, 0x8a1a6b7e, 0x7ec384e8, 0x42c1c3fc, 0x8ed158a1, /* MIDSTATE */
+		0,0,0,0,0,0,0,0,
+		0x8a0bb7b7, 0x33af304f, 0x0b290c1a, 0xf0c4e61f, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
+	};
+
+	ms3_compute(&atrvec[0]);
+	memset(&w, 0, sizeof(w)); w[3] = 0xffffffff; w[4] = 0x80000000; w[15] = 0x00000280;
+	spi_emit_data(0x1000, (void*)w, 16*4);
+	spi_emit_data(0x1400, (void*)w,  8*4);
+	memset(w, 0, sizeof(w)); w[0] = 0x80000000; w[7] = 0x100;
+	spi_emit_data(0x1900, (void*)&w[0],8*4); /* Prepare MS and W buffers! */
+	spi_emit_data(0x3000, (void*)&atrvec[0], 19*4);
+}
+
+void set_freq(int bits) {
+	uint64_t freq;
+	unsigned char *osc6;
+	int i;
+
+	osc6 = (unsigned char *)&freq;
+	freq = (1ULL << bits) - 1ULL;
+
+	spi_emit_data(0x6000, (void*)osc6, 8); /* Program internal on-die slow oscillator frequency */
+	config_reg(4,1); /* Enable slow oscillator */
+}
+
+void send_reinit(int slot, int chip_n, int n) {
+	spi_clear_buf();
+	spi_emit_break();
+	spi_emit_fasync(chip_n);
+	set_freq(n);
+	send_conf();
+	send_init();
+	tm_i2c_set_oe(slot);
+	spi_txrx(spi_gettxbuf(), spi_getrxbuf(), spi_getbufsz());
+	tm_i2c_clear_oe(slot);
+}
+
+void send_shutdown(int slot, int chip_n) {
+	spi_clear_buf();
+	spi_emit_break();
+	spi_emit_fasync(chip_n);
+	config_reg(4,0); /* Disable slow oscillator */
+	tm_i2c_set_oe(slot);
+	spi_txrx(spi_gettxbuf(), spi_getrxbuf(), spi_getbufsz());
+	tm_i2c_clear_oe(slot);
+}
+
+void send_freq(int slot, int chip_n, int bits) {
+	spi_clear_buf();
+	spi_emit_break();
+	spi_emit_fasync(chip_n);
+	set_freq(bits);
+	tm_i2c_set_oe(slot);
+	spi_txrx(spi_gettxbuf(), spi_getrxbuf(), spi_getbufsz());
+	tm_i2c_clear_oe(slot);
+}
+
+unsigned int c_diff(unsigned ocounter, unsigned counter) {
+	return counter >  ocounter ? counter - ocounter : (0x003FFFFF - ocounter) + counter;
+}
+
+int get_counter(unsigned int *newbuf, unsigned int *oldbuf) {
+	int j;
+	unsigned counter;
+	for(j = 0; j < 16; j++) {
+		if (newbuf[j] != oldbuf[j]) {
+			int counter = decnonce(newbuf[j]);
+			if ((counter & 0xFFC00000) == 0xdf800000) {
+				counter -= 0xdf800000;
+				return counter;
+			}
+		}
+	}
+	return 0;
+}
+
+int detect_chip(int chip_n) {
 	int i;
 	unsigned newbuf[17], oldbuf[17];
+	unsigned ocounter;
+	int odiff;
+	struct timespec t1, t2, td;
 
 	memset(newbuf, 0, 17 * 4);
 	memset(oldbuf, 0, 17 * 4);
@@ -154,54 +283,97 @@ int detect_chip(int chip_n) {
 	spi_clear_buf();
 	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 */
-	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(4,1); /* Enable slow oscillator */
-	config_reg(1,0); config_reg(2,0); config_reg(3,0);
-	spi_emit_data(0x0100, (void*)counters, 16); /* Program counters correctly for rounds processing, here baby should start consuming power */
-
-	/* Prepare internal buffers */
-	/* PREPARE BUFFERS (INITIAL PROGRAMMING) */
-	memset(&w, 0, sizeof(w)); w[3] = 0xffffffff; w[4] = 0x80000000; w[15] = 0x00000280;
-	spi_emit_data(0x1000, (void*)w, 16*4);
-	spi_emit_data(0x1400, (void*)w,  8*4);
-	memset(w, 0, sizeof(w)); w[0] = 0x80000000; w[7] = 0x100;
-	spi_emit_data(0x1900, (void*)&w[0],8*4); /* Prepare MS and W buffers! */
-
-	spi_emit_data(0x3000, (void*)&atrvec[0], 19*4);
+	set_freq(52);  //54 - 3F, 53 - 1F
+	send_conf();
+	send_init();
 	spi_txrx(spi_gettxbuf(), spi_getrxbuf(), spi_getbufsz());
 
+	ocounter = 0;
 	for (i = 0; i < BITFURY_DETECT_TRIES; i++) {
+		int j;
+		int counter;
+
 		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);
+
+		clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t1);
+		counter = get_counter(newbuf, oldbuf);
+		if (ocounter) {
+			unsigned int cdiff = c_diff(ocounter, counter);
+			unsigned per_ms;
+
+			td = t_diff(t2, t1);
+			per_ms = cdiff / (td.tv_nsec / 1000);
+			if (cdiff > 5000 && cdiff < 100000 && odiff > 5000 && odiff < 100000)
+				return 1;
+			odiff = cdiff;
+		}
+		ocounter = counter;
+		t2 = t1;
 		if (newbuf[16] != 0 && newbuf[16] != 0xFFFFFFFF) {
 			return 0;
 		}
-		if (i && newbuf[16] != oldbuf[16])
-			return 1;
-		cgsleep_ms(BITFURY_REFRESH_DELAY);
+		cgsleep_ms(BITFURY_REFRESH_DELAY / 10);
 		memcpy(oldbuf, newbuf, 17 * 4);
 	}
 	return 0;
 }
 
-int libbitfury_detectChips(void) {
+int libbitfury_detectChips(struct bitfury_device *devices) {
 	int n = 0;
-	int detected;
-	do {
-		detected = detect_chip(n);
-		if (detected) {
-			n++;
-		applog(LOG_WARNING, "BITFURY chip #%d detected", n);
-		} else {
+	int i;
+	static slot_on[32];
+	struct timespec t1, t2;
+
+	if (tm_i2c_init() < 0) {
+		printf("I2C init error\n");
+		return(1);
+	}
+
+
+	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t1);
+	for (i = 0; i < 32; i++) {
+		int slot_detected = tm_i2c_detect(i) != -1;
+		slot_on[i] = slot_detected;
+		tm_i2c_clear_oe(i);
+		cgsleep_ms(1);
+	}
+
+	for (i = 0; i < 32; i++) {
+		if (slot_on[i]) {
+			int chip_n = 0;
+			int chip_detected;
+			tm_i2c_set_oe(i);
+			do {
+				chip_detected = detect_chip(chip_n);
+				if (chip_detected) {
+					applog(LOG_WARNING, "BITFURY slot: %d, chip #%d detected", i, n);
+					devices[n].slot = i;
+					devices[n].fasync = chip_n;
+					n++;
+					chip_n++;
+				}
+			} while (chip_detected);
+			tm_i2c_clear_oe(i);
 		}
-	} while (detected);
-	return n;
+	}
+
+	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t2);
+
+	return n; //!!!
+	//return 1;
+}
+
+int libbitfury_shutdownChips(struct bitfury_device *devices, int chip_n) {
+	int i;
+	for (i = 0; i < chip_n; i++) {
+		send_shutdown(devices[i].slot, devices[i].fasync);
+	}
+	tm_i2c_close();
 }
 
 unsigned decnonce(unsigned in)
@@ -235,9 +407,12 @@ int rehash(unsigned char *midstate, unsigned m7,
 	unsigned int *mid32 = (unsigned int *)midstate;
 	unsigned out32[8];
 	unsigned char *out = (unsigned char *) out32;
+	static unsigned history[512];
+	static unsigned history_p;
 	int i;
 	sha256_ctx ctx;
 
+
 	memset( &ctx, 0, sizeof( sha256_ctx ) );
 	memcpy(ctx.h, mid32, 8*4);
 	ctx.tot_len = 64;
@@ -256,7 +431,9 @@ int rehash(unsigned char *midstate, unsigned m7,
 	if (out32[7] == 0) {
 		bin2hex(hex, midstate, 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);
+//		history[history_p] = nnonce;
+//		history_p++; history_p &= 512 - 1;
 		return 1;
 	}
 	return 0;
@@ -272,63 +449,233 @@ void work_to_payload(struct bitfury_payload *p, struct work *w) {
 	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;
+	int chip_id;
 	static unsigned second_run;
 
-	for (chip = 0; chip < chip_n; chip++) {
+	for (chip_id = 0; chip_id < chip_n; chip_id++) {
 		unsigned char *hexstr;
-		struct bitfury_device *d = bf + chip;
+		struct bitfury_device *d = bf + chip_id;
 		unsigned *newbuf = d->newbuf;
 		unsigned *oldbuf = d->oldbuf;
 		struct bitfury_payload *p = &(d->payload);
 		struct bitfury_payload *op = &(d->opayload);
+		struct bitfury_payload *o2p = &(d->o2payload);
+		struct timespec d_time;
+		struct timespec time;
+		int smart = 0;
+		int i;
+		int chip = d->fasync;
+		int slot = d->slot;
 
-
-		/* Programming next value */
 		memcpy(atrvec, p, 20*4);
 		ms3_compute(atrvec);
 
-		spi_clear_buf(); spi_emit_break();
-		spi_emit_fasync(chip);
-		spi_emit_data(0x3000, (void*)&atrvec[0], 19*4);
-		spi_txrx(spi_gettxbuf(), spi_getrxbuf(), spi_getbufsz());
-
-		memcpy(newbuf, spi_getrxbuf()+4 + chip, 17*4);
+		clock_gettime(CLOCK_REALTIME, &(time));
+
+		if (!second_run) {
+			d->predict2 = d->predict1 = time;
+			d->counter1 = d->counter2 = 0;
+			d->req2_done = 0;
+		};
+
+		d_time = t_diff(time, d->predict1);
+		if (d_time.tv_sec < 0 && (d->req2_done || !smart)) {
+			d->otimer1 = d->timer1;
+			d->timer1 = time;
+			/* Programming next value */
+			spi_clear_buf(); spi_emit_break();
+			spi_emit_fasync(chip);
+			spi_emit_data(0x3000, (void*)&atrvec[0], 19*4);
+			if (smart) {
+				config_reg(3,0);
+			}
+			tm_i2c_set_oe(slot);
+			clock_gettime(CLOCK_REALTIME, &(time));
+			d_time = t_diff(time, d->predict1);
+			spi_txrx(spi_gettxbuf(), spi_getrxbuf(), spi_getbufsz());
+			tm_i2c_clear_oe(slot);
+			memcpy(newbuf, spi_getrxbuf()+4 + chip, 17*4);
 
-		d->job_switched = newbuf[16] != oldbuf[16];
+			d->job_switched = newbuf[16] != oldbuf[16];
 
-		if (second_run && d->job_switched) {
 			int i;
 			int results_num = 0;
+			int found = 0;
 			unsigned * results = d->results;
+
+			d->old_nonce = 0;
+			d->future_nonce = 0;
 			for (i = 0; i < 16; i++) {
-				if (oldbuf[i] != newbuf[i]) {
+				if (oldbuf[i] != newbuf[i] && op && o2p) {
 					unsigned pn; //possible nonce
 					unsigned int s = 0; //TODO zero may be solution
+					unsigned int old_f = 0;
+					if ((newbuf[i] & 0xFF) == 0xE0)
+						continue;
 					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;
+					s |= rehash(op->midstate, op->m7, op->ntime, op->nbits, pn-0x00400000) ? pn - 0x00400000 : 0;
+					s |= rehash(op->midstate, op->m7, op->ntime, op->nbits, pn-0x00800000) ? pn - 0x00800000 : 0;
+					s |= rehash(op->midstate, op->m7, op->ntime, op->nbits, pn+0x02800000) ? pn + 0x02800000 : 0;
+					s |= rehash(op->midstate, op->m7, op->ntime, op->nbits, pn+0x02C00000) ? pn + 0x02C00000 : 0;
+					s |= rehash(op->midstate, op->m7, op->ntime, op->nbits, pn+0x00400000) ? pn + 0x00400000 : 0;
+					if (s) {
+						int k;
+						int dup = 0;
+						for (k = 0; k < results_num; k++) {
+							if (results[k] == bswap_32(s)) {
+								dup = 1;
+							}
+						}
+						if (!dup) {
+							results[results_num++] = bswap_32(s);
+							found++;
+						}
+					}
+
+					s = 0;
+					pn = decnonce(newbuf[i]);
+					s |= rehash(o2p->midstate, o2p->m7, o2p->ntime, o2p->nbits, pn) ? pn : 0;
+					s |= rehash(o2p->midstate, o2p->m7, o2p->ntime, o2p->nbits, pn-0x400000) ? pn - 0x400000 : 0;
+					s |= rehash(o2p->midstate, o2p->m7, o2p->ntime, o2p->nbits, pn-0x800000) ? pn - 0x800000 : 0;
+					s |= rehash(o2p->midstate, o2p->m7, o2p->ntime, o2p->nbits, pn+0x2800000)? pn + 0x2800000 : 0;
+					s |= rehash(o2p->midstate, o2p->m7, o2p->ntime, o2p->nbits, pn+0x2C00000)? pn + 0x2C00000 : 0;
+					s |= rehash(o2p->midstate, o2p->m7, o2p->ntime, o2p->nbits, pn+0x400000) ? pn + 0x400000 : 0;
 					if (s) {
-						results[results_num++] = bswap_32(s);
+						d->old_nonce = bswap_32(s);
+						found++;
+					}
+
+					s = 0;
+					pn = decnonce(newbuf[i]);
+					s |= rehash(p->midstate, p->m7, p->ntime, p->nbits, pn) ? pn : 0;
+					s |= rehash(p->midstate, p->m7, p->ntime, p->nbits, pn-0x400000) ? pn - 0x400000 : 0;
+					s |= rehash(p->midstate, p->m7, p->ntime, p->nbits, pn-0x800000) ? pn - 0x800000 : 0;
+					s |= rehash(p->midstate, p->m7, p->ntime, p->nbits, pn+0x2800000)? pn + 0x2800000 : 0;
+					s |= rehash(p->midstate, p->m7, p->ntime, p->nbits, pn+0x2C00000)? pn + 0x2C00000 : 0;
+					s |= rehash(p->midstate, p->m7, p->ntime, p->nbits, pn+0x400000) ? pn + 0x400000 : 0;
+					if (s) {
+						d->future_nonce = bswap_32(s);
+						found++;
+					}
+					if (!found) {
+						printf("AAA Strange: %08x, chip_id: %d\n", pn, chip_id);
 					}
 				}
 			}
 			d->results_n = results_num;
 
-			memcpy(op, p, sizeof(struct bitfury_payload));
-			memcpy(oldbuf, newbuf, 17 * 4);
+			if (smart) {
+				d_time = t_diff(d->timer2, d->timer1);
+			} else {
+				d_time = t_diff(d->otimer1, d->timer1);
+			}
+			d->ocounter1 = d->counter1;
+			d->counter1 = get_counter(newbuf, oldbuf);
+			if (d->counter2 || !smart) {
+				int shift;
+				int cycles;
+				int req1_cycles;
+				long long unsigned int period;
+				double ns;
+				unsigned full_cycles, half_cycles;
+				double full_delay, half_delay;
+				long long unsigned delta;
+				struct timespec t_delta;
+				double mhz;
+				int ccase;
+
+				shift = 800000;
+				if (smart) {
+					cycles = d->counter1 < d->counter2 ? 0x00400000 - d->counter2 + d->counter1 : d->counter1 - d->counter2; // + 0x003FFFFF;
+				} else {
+					if (d->counter1 > (0x00400000 - shift * 2) && d->ocounter1 > (0x00400000 - shift)) {
+						cycles = 0x00400000 - d->ocounter1 + d->counter1; // + 0x003FFFFF;
+						ccase = 1;
+					} else {
+						cycles = d->counter1 - d->ocounter1;
+						ccase = 2;
+					}
+				}
+				req1_cycles = 0x003FFFFF - d->counter1;
+				period = (long long unsigned int)d_time.tv_sec * 1000000000ULL + (long long unsigned int)d_time.tv_nsec;
+				ns = (double)period / (double)(cycles);
+				mhz = 1.0 / ns * 65.0 * 1000.0;
+
+				if (d->counter1 > 0 && d->counter1 < 0x001FFFFF)
+					printf("AAA chip_id %2d: %llu ms, req1_cycles: %08u,  counter1: %08d, ocounter1: %08d, counter2: %08d, cycles: %08d, ns: %.2f, mhz: %.2f \n", chip_id, period / 1000000ULL, req1_cycles, d->counter1, d->ocounter1, d->counter2, cycles, ns, mhz);
+				if (ns > 2000.0 || ns < 20) {
+					printf("AAA %d!Stupid ns chip_id %2d: %llu ms, req1_cycles: %08u,  counter1: %08d, ocounter1: %08d, counter2: %08d, cycles: %08d, ns: %.2f, mhz: %.2f \n", ccase, chip_id, period / 1000000ULL, req1_cycles, d->counter1, d->ocounter1, d->counter2, cycles, ns, mhz);
+					ns = 200.0;
+				} else {
+					d->ns = ns;
+					d->mhz = mhz;
+				}
+
+				if (smart) {
+					half_cycles = req1_cycles + shift;
+					full_cycles = 0x003FFFFF - 2 * shift;
+				} else {
+					half_cycles = 0;
+					full_cycles = req1_cycles > shift ? req1_cycles - shift : req1_cycles + 0x00400000 - shift;
+				}
+				half_delay = (double)half_cycles * ns * (1 +0.92);
+				full_delay = (double)full_cycles * ns;
+				delta = (long long unsigned)(full_delay + half_delay);
+				t_delta.tv_sec = delta / 1000000000ULL;
+				t_delta.tv_nsec = delta - t_delta.tv_sec * 1000000000ULL;
+				d->predict1 = t_add(time, t_delta);
+
+				if (smart) {
+					half_cycles = req1_cycles + shift;
+					full_cycles = 0;
+				} else {
+					full_cycles = req1_cycles + shift;
+				}
+				half_delay = (double)half_cycles * ns * (1 + 0.92);
+				full_delay = (double)full_cycles * ns;
+				delta = (long long unsigned)(full_delay + half_delay);
+
+				t_delta.tv_sec = delta / 1000000000ULL;
+				t_delta.tv_nsec = delta - t_delta.tv_sec * 1000000000ULL;
+				d->predict2 = t_add(time, t_delta);
+				d->req2_done = 0; d->req1_done = 0;
+			}
+
+			if (d->job_switched) {
+				memcpy(o2p, op, sizeof(struct bitfury_payload));
+				memcpy(op, p, sizeof(struct bitfury_payload));
+				memcpy(oldbuf, newbuf, 17 * 4);
+			}
 		}
 
-		cgsleep_ms(BITFURY_REFRESH_DELAY);
+		clock_gettime(CLOCK_REALTIME, &(time));
+		d_time = t_diff(time, d->predict2);
+		if (d_time.tv_sec < 0 && !d->req2_done) {
+			if(smart) {
+				d->otimer2 = d->timer2;
+				d->timer2 = time;
+				spi_clear_buf();
+				spi_emit_break();
+				spi_emit_fasync(chip);
+				spi_emit_data(0x3000, (void*)&atrvec[0], 19*4);
+				if (smart) {
+					config_reg(3,1);
+				}
+				tm_i2c_set_oe(slot);
+				spi_txrx(spi_gettxbuf(), spi_getrxbuf(), spi_getbufsz());
+				tm_i2c_clear_oe(slot);
+				memcpy(newbuf, spi_getrxbuf()+4 + chip, 17*4);
+				d->counter2 = get_counter(newbuf, oldbuf);
+
+				d->req2_done = 1;
+			} else {
+				d->req2_done = 1;
+			}
+		}
 	}
 	second_run = 1;
 

+ 27 - 2
libbitfury.h

@@ -29,7 +29,7 @@
 
 #include "miner.h"
 
-extern int libbitfury_detectChips(void);
+#define BITFURY_STAT_N 1024
 
 struct bitfury_payload {
 	unsigned char midstate[32];
@@ -41,20 +41,45 @@ struct bitfury_payload {
 };
 
 struct bitfury_device {
-	unsigned char osc[8];
+	unsigned char osc6_bits;
 	unsigned newbuf[17];
 	unsigned oldbuf[17];
 	struct work * work;
 	struct work * owork;
+	struct work * o2work;
 	int job_switched;
 	struct bitfury_payload payload;
 	struct bitfury_payload opayload;
+	struct bitfury_payload o2payload;
 	unsigned int results[16];
 	int results_n;
+	time_t stat_ts[BITFURY_STAT_N];
+	unsigned int stat_counter;
+	unsigned int future_nonce;
+	unsigned int old_nonce;
+	struct timespec timer1;
+	struct timespec timer2;
+	struct timespec otimer1;
+	struct timespec otimer2;
+	struct timespec predict1;
+	struct timespec predict2;
+	unsigned int counter1, counter2;
+	unsigned int ocounter1, ocounter2;
+	int rate; //per msec
+	int osc_slow;
+	int osc_fast;
+	int req1_done, req2_done;
+	double mhz;
+	double ns;
+	unsigned slot;
+	unsigned fasync;
 };
 
 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);
+struct timespec t_diff(struct timespec start, struct timespec end);
+int libbitfury_detectChips(struct bitfury_device *devices);
+int libbitfury_shutdownChips(struct bitfury_device *devices, int chip_n);
 
 #endif /* __LIBBITFURY_H__ */

+ 1 - 3
miner.h

@@ -457,9 +457,6 @@ struct cgpu_info {
 #ifdef USE_ZTEX
 		struct libztex_device *device_ztex;
 #endif
-/*#ifdef USE_BITFURY
-		struct libbitfury_device *device_bitfury;
-#endif */
 		int device_fd;
 #ifdef USE_X6500
 		struct ft232r_device_handle *device_ft232r;
@@ -488,6 +485,7 @@ struct cgpu_info {
 
 #ifdef USE_BITFURY
 	int chip_n;
+	struct bitfury_device devices[200]; // TODO Move somewhere to appropriate place
 #endif
 
 	enum dev_enable deven;

+ 17 - 24
spidevc.c

@@ -58,35 +58,20 @@ void spi_init(void)
 // Bit-banging reset, to reset more chips in chain - toggle for longer period... Each 3 reset cycles reset first chip in chain
 void spi_reset(void)
 {
-	int i;
+	int i,j;
+	int a = 1234, len = 2;
 	INP_GPIO(10); OUT_GPIO(10);
 	INP_GPIO(11); OUT_GPIO(11);
 	GPIO_SET = 1 << 11; // Set SCK
 	for (i = 0; i < 16; i++) { // On standard settings this unoptimized code produces 1 Mhz freq.
 		GPIO_SET = 1 << 10;
-		GPIO_SET = 1 << 10;
-		GPIO_SET = 1 << 10;
-		GPIO_SET = 1 << 10;
-		GPIO_SET = 1 << 10;
-		GPIO_SET = 1 << 10;
-		GPIO_SET = 1 << 10;
-		GPIO_SET = 1 << 10;
-		GPIO_SET = 1 << 10;
-		GPIO_SET = 1 << 10;
-		GPIO_SET = 1 << 10;
-		GPIO_SET = 1 << 10;
-		GPIO_CLR = 1 << 10;
-		GPIO_CLR = 1 << 10;
-		GPIO_CLR = 1 << 10;
-		GPIO_CLR = 1 << 10;
-		GPIO_CLR = 1 << 10;
-		GPIO_CLR = 1 << 10;
-		GPIO_CLR = 1 << 10;
-		GPIO_CLR = 1 << 10;
-		GPIO_CLR = 1 << 10;
-		GPIO_CLR = 1 << 10;
-		GPIO_CLR = 1 << 10;
+		for (j = 0; j < len; j++) {
+			a *= a;
+		}
 		GPIO_CLR = 1 << 10;
+		for (j = 0; j < len; j++) {
+			a *= a;
+		}
 	}
 	GPIO_CLR = 1 << 10;
 	GPIO_CLR = 1 << 11;
@@ -106,7 +91,7 @@ int spi_txrx(const char *wrbuf, char *rdbuf, int bufsz)
 	struct spi_ioc_transfer tr[16];
 
 	memset(&tr,0,sizeof(tr));
-	mode = 0; bits = 8; speed = 200000;
+	mode = 0; bits = 8; speed = 2000000;
 
 	spi_reset();
 	fd = open("/dev/spidev0.0", O_RDWR);
@@ -146,6 +131,7 @@ int spi_txrx(const char *wrbuf, char *rdbuf, int bufsz)
         }
 
 	close(fd);
+	spi_reset();
 
 	return 0;
 }
@@ -191,6 +177,13 @@ void spi_emit_fasync(int n) {
 	}
 }
 
+void spi_emit_nop(int n) {
+	int i;
+	for (i = 0; i < n; n++) {
+		spi_emit_buf("\x0", 1);
+	}
+}
+
 void spi_emit_data(unsigned addr, const char *buf, unsigned len)
 {
 	unsigned char otmp[3];

+ 1 - 0
spidevc.h

@@ -37,6 +37,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_fsync(void); /* FEED-THROUGH TO NEXT CHIP SYNCHRONOUSLY (WITH FLIP-FLOP) */
 void spi_emit_fasync(int n); /* FEED-THROUGH TO NEXT CHIP ASYNCHRONOUSLY (WITHOUT FLIP-FLOP INTERMEDIATE) */
+void spi_emit_nop(int n);
 
 /* TRANSMIT PROGRAMMING SEQUENCE (AND ALSO READ-BACK) */
 /* addr is the destination address in bits (16-bit - 0 to 0xFFFF valid ones)

+ 106 - 0
tm_i2c.c

@@ -0,0 +1,106 @@
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include "tm_i2c.h"
+
+float tm_i2c_Data2Temp(unsigned int ans) {
+	float t = ans;
+	return (t / 1023.0 * 3.3 * 2-2.73) * 100.0;
+}
+
+float tm_i2c_Data2Core(unsigned int ans) {
+	float t = ans;
+	return t / 1023.0 * 3.3;
+}
+
+int tm_i2c_init() {
+	if ((tm_i2c_fd = open("/dev/i2c-1", O_RDWR)) < 0)
+		return 1;
+	else
+		return 0;
+}
+
+void tm_i2c_close() {
+	close(tm_i2c_fd);
+}
+
+unsigned int tm_i2c_req(int fd, unsigned char addr, unsigned char cmd, unsigned int data) {
+	int i;
+	unsigned char buf[16];
+	struct i2c_msg msg;
+	tm_struct *tm = (tm_struct *) buf;
+	struct i2c_rdwr_ioctl_data msg_rdwr;
+	unsigned int ret;
+
+	//printf("REQ from %02X cmd: %02X\n", addr, cmd);
+
+	tm->cmd = cmd;
+	tm->data_lsb = data & 0xFF;
+	tm->data_msb = (data & 0xFF00) >> 8;
+
+	/* Write CMD */
+	msg.addr = addr;
+	msg.flags = 0;
+	msg.len = 3;
+	msg.buf = buf;
+	msg_rdwr.msgs = &msg;
+	msg_rdwr.nmsgs = 1;
+	if ((i = ioctl(fd, I2C_RDWR, &msg_rdwr)) < 0) {
+//		perror("ioctl error");
+		return -1;
+	}
+
+	/* Read result */
+	msg.addr = addr;
+	msg.flags = I2C_M_RD;
+	msg.len = 3;
+	msg.buf = buf;
+	msg_rdwr.msgs = &msg;
+	msg_rdwr.nmsgs = 1;
+	if ((i = ioctl(fd, I2C_RDWR, &msg_rdwr)) < 0) {
+//		perror("ioctl error");
+		return -1;
+	}
+
+	//hexdump(buf, 10);
+	ret = (tm->data_msb << 8) + tm->data_lsb;
+	if (tm->cmd == cmd) return ret;
+	return 0;
+}
+
+int tm_i2c_detect(unsigned char slot) {
+	if (slot < 0 || slot > 31) return 0;
+	return tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slot, TM_GET_CORE0, 0);
+}
+
+float tm_i2c_getcore0(unsigned char slot) {
+	if (slot < 0 || slot > 31) return 0;
+	return tm_i2c_Data2Core(tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slot, TM_GET_CORE0, 0));
+}
+
+float tm_i2c_getcore1(unsigned char slot) {
+	if (slot < 0 || slot > 31) return 0;
+	return tm_i2c_Data2Core(tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slot, TM_GET_CORE1, 0));
+}
+
+float tm_i2c_gettemp(unsigned char slot) {
+	if (slot < 0 || slot > 31) return 0;
+	return tm_i2c_Data2Temp(tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slot, TM_GET_TEMP, 0));
+}
+
+void tm_i2c_set_oe(unsigned char slot) {
+	if (slot < 0 || slot > 31) return;
+	tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slot, TM_SET_OE, 0);
+}
+
+void tm_i2c_clear_oe(unsigned char slot) {
+	if (slot < 0 || slot > 31) return;
+	tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slot, TM_SET_OE, 1);
+}
+
+unsigned char tm_i2c_slot2addr(unsigned char slot) {
+	if (slot < 0 || slot > 31) return 0;
+	return ((TM_ADDR >> 1) + slot);
+}
+

+ 45 - 0
tm_i2c.h

@@ -0,0 +1,45 @@
+/* - Version 1.0 - */
+
+#define TM_ADDR         0xC0
+
+#define TM_GET_TEMP     0x10
+#define TM_GET_CORE0    0x11
+#define TM_GET_CORE1    0x12
+
+#define TM_SET_OE       0x20
+#define TM_SET_MODE     0x21
+#define TM_SET_RED      0x22
+#define TM_SET_GREEN    0x23
+
+#define TM_GET_PORTB    0x30
+#define TM_SET_PORTB    0x31
+#define TM_GET_PINB     0x32
+#define TM_GET_PORTD    0x33
+#define TM_SET_PORTD    0x34
+#define TM_GET_PIND     0x35
+#define TM_GET_ADC      0x36
+
+#define TM_MODE_AUTO    0
+#define TM_MODE_MANUAL  1
+
+static int tm_i2c_fd;
+
+typedef struct {
+	unsigned char cmd;
+	unsigned char data_lsb;
+	unsigned char data_msb;
+} tm_struct;
+
+int tm_i2c_init();
+void tm_i2c_close();
+unsigned int tm_i2c_req(int fd, unsigned char addr, unsigned char cmd, unsigned int data);
+float tm_i2c_Data2Temp(unsigned int ans);
+float tm_i2c_Data2Core(unsigned int ans);
+float tm_i2c_gettemp(unsigned char slot);
+float tm_i2c_getcore0(unsigned char slot);
+float tm_i2c_getcore1(unsigned char slot);
+void tm_i2c_set_oe(unsigned char slot);
+void tm_i2c_clear_oe(unsigned char slot);
+int tm_i2c_detect(unsigned char slot);
+unsigned char tm_i2c_slot2addr(unsigned char slot);
+