Browse Source

Merge commit 'legko/master^^' into littlefury

Conflicts:
	Makefile.am
	configure.ac
	miner.c
	miner.h
Luke Dashjr 12 years ago
parent
commit
031a7a86f3
9 changed files with 709 additions and 0 deletions
  1. 4 0
      Makefile.am
  2. 18 0
      configure.ac
  3. 128 0
      driver-bitfury.c
  4. 306 0
      libbitfury.c
  5. 29 0
      libbitfury.h
  6. 8 0
      miner.c
  7. 7 0
      miner.h
  8. 179 0
      spidevc.c
  9. 30 0
      spidevc.h

+ 4 - 0
Makefile.am

@@ -210,6 +210,10 @@ if HAS_ZTEX
 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
+endif
+
 bin_PROGRAMS += bfgminer-rpc
 bfgminer_rpc_SOURCES = api-example.c
 bfgminer_rpc_LDADD = @WS2_LIBS@

+ 18 - 0
configure.ac

@@ -430,6 +430,18 @@ fi
 AM_CONDITIONAL([HAS_ZTEX], [test x$ztex = xyes])
 
 
+bitfury="no"
+
+AC_ARG_ENABLE([bitfury],
+	[AC_HELP_STRING([--enable-bitfury],[Compile support for Bitfury (default disabled)])],
+	[bitfury=$enableval]
+	)
+if test "x$bitfury" = xyes; then
+	AC_DEFINE([USE_BITFURY], [1], [Defined to 1 if Bitfury support is wanted])
+fi
+AM_CONDITIONAL([HAS_BITFURY], [test x$bitfury = xyes])
+
+
 if test "x$x6500$ztex" = "xnono"; then
 	libusb=no
 	LIBUSB_LIBS=''
@@ -1070,6 +1082,12 @@ else
 	echo "  CPU Mining...........: Disabled"
 fi
 
+if test "x$bitfury" = xyes; then
+	echo "  Bitfury.ASICs........: Enabled"
+else
+	echo "  Bitfury.ASICs........: Disabled"
+fi
+
 echo
 echo "Compilation............: make (or gmake)"
 echo "  CPPFLAGS.............:" $CPPFLAGS $NCURSES_CPPFLAGS $PTHREAD_FLAGS

+ 128 - 0
driver-bitfury.c

@@ -0,0 +1,128 @@
+/**
+ *   bitfury.c - cgminer worker for bitfury chip/board
+ *
+ *   Copyright (c) 2013 bitfury
+ *   Copyright (c) 2013 legkodymov
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2 as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, see http://www.gnu.org/licenses/.
+**/
+
+#include "miner.h"
+#include <unistd.h>
+#include <sha2.h>
+#include "libbitfury.h"
+#include "util.h"
+
+#define GOLDEN_BACKLOG 5
+
+struct device_drv bitfury_drv;
+
+// Forward declarations
+static void bitfury_disable(struct thr_info* thr);
+static bool bitfury_prepare(struct thr_info *thr);
+
+static void bitfury_detect(void)
+{
+	struct cgpu_info *bitfury_info;
+	applog(LOG_INFO, "INFO: bitfury_detect");
+	libbitfury_detectChips();
+
+	bitfury_info = calloc(1, sizeof(struct cgpu_info));
+	bitfury_info->drv = &bitfury_drv;
+	bitfury_info->threads = 1;
+	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)
+{
+	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;
+	}
+
+	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]));
+		}
+	}
+
+	if (owork)
+		work_completed(thr->cgpu, owork);
+
+	owork = work;
+	return 0xffffffffull * i;
+}
+
+static bool bitfury_prepare(struct thr_info *thr)
+{
+	struct cgpu_info *cgpu = thr->cgpu;
+
+	get_now_datestamp(cgpu->init, sizeof(cgpu->init));
+
+	applog(LOG_INFO, "INFO bitfury_prepare");
+	return true;
+}
+
+static void bitfury_shutdown(struct thr_info *thr)
+{
+	applog(LOG_INFO, "INFO bitfury_shutdown");
+}
+
+static void bitfury_disable(struct thr_info *thr)
+{
+	applog(LOG_INFO, "INFO bitfury_disable");
+}
+
+struct device_drv bitfury_drv = {
+	.dname = "bitfury",
+	.name = "BITFURY",
+	.drv_detect = bitfury_detect,
+	.thread_prepare = bitfury_prepare,
+	.scanwork = bitfury_scanHash,
+	.thread_shutdown = bitfury_shutdown,
+	.minerloop = hash_queued_work,
+};
+

+ 306 - 0
libbitfury.c

@@ -0,0 +1,306 @@
+/**
+ *   libbitfury.c - library for Bitfury chip/board
+ *
+ *   Copyright (c) 2013 bitfury
+ *   Copyright (c) 2013 legkodymov
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2 as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, see http://www.gnu.org/licenses/.
+**/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "miner.h"
+#include "libbitfury.h"
+
+#include "spidevc.h"
+#include "sha2.h"
+
+#include <time.h>
+
+// 0 .... 31 bit
+// 1000 0011 0101 0110 1001 1010 1100 0111
+
+// 1100 0001 0110 1010 0101 1001 1110 0011
+// C16A59E3
+
+unsigned results[16];
+unsigned results_num = 0;
+
+unsigned char enaconf[4] = { 0xc1, 0x6a, 0x59, 0xe3 };
+unsigned char disconf[4] = { 0, 0, 0, 0 };
+
+/* Configuration registers - control oscillators and such stuff. PROGRAMMED when magic number is matches, UNPROGRAMMED (default) otherwise */
+void config_reg(int cfgreg, int ena)
+{
+	if (ena) spi_emit_data(0x7000+cfgreg*32, (void*)enaconf, 4);
+	else     spi_emit_data(0x7000+cfgreg*32, (void*)disconf, 4);
+}
+
+#define FIRST_BASE 61
+#define SECOND_BASE 4
+char counters[16] = { 64, 64,
+	SECOND_BASE, SECOND_BASE+4, SECOND_BASE+2, SECOND_BASE+2+16, SECOND_BASE, SECOND_BASE+1,
+	(FIRST_BASE)%65,  (FIRST_BASE+1)%65,  (FIRST_BASE+3)%65, (FIRST_BASE+3+16)%65, (FIRST_BASE+4)%65, (FIRST_BASE+4+4)%65, (FIRST_BASE+3+3)%65, (FIRST_BASE+3+1+3)%65};
+
+//char counters[16] = { 64, 64,
+//	SECOND_BASE, SECOND_BASE+4, SECOND_BASE+2, SECOND_BASE+2+16, SECOND_BASE, SECOND_BASE+1,
+//	(FIRST_BASE)%65,  (FIRST_BASE+1)%65,  (FIRST_BASE+3)%65, (FIRST_BASE+3+16)%65, (FIRST_BASE+4)%65, (FIRST_BASE+4+4)%65, (FIRST_BASE+3+3)%65, (FIRST_BASE+3+1+3)%65};
+char *buf = "Hello, World!\x55\xaa";
+char outbuf[16];
+
+/* Oscillator setup variants (maybe more), values inside of chip ANDed to not allow by programming errors work it at higher speeds  */
+/* WARNING! no chip temperature control limits, etc. It may self-fry and make fried chips with great ease :-) So if trying to overclock */
+/* Do not place chip near flammable objects, provide adequate power protection and better wear eye protection ! */
+/* 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+/* Test vectors to calculate (using address-translated loads) */
+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 */
+
+0x9c4dfdc0, 0xf055c9e1, 0xe60f079d, 0xeeada6da, 0xd459883d, 0xd8049a9d, 0xd49f9a96, 0x15972fed, /* MIDSTATE */
+0,0,0,0,0,0,0,0,
+0x048b2528, 0x7acb2d4f, 0x0b290c1a, 0xbe00084a, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
+
+0x0317b3ea, 0x1d227d06, 0x3cca281e, 0xa6d0b9da, 0x1a359fe2, 0xa7287e27, 0x8b79c296, 0xc4d88274, /* MIDSTATE */
+0,0,0,0,0,0,0,0,
+0x328bcd4f, 0x75462d4f, 0x0b290c1a, 0x002c6dbc, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
+
+0xac4e38b6, 0xba0e3b3b, 0x649ad6f8, 0xf72e4c02, 0x93be06fb, 0x366d1126, 0xf4aae554, 0x4ff19c5b, /* MIDSTATE */
+0,0,0,0,0,0,0,0,
+0x72698140, 0x3bd62b4f, 0x3fd40c1a, 0x801e43e9, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
+
+0x9dbf91c9, 0x12e5066c, 0xf4184b87, 0x8060bc4d, 0x18f9c115, 0xf589d551, 0x0f7f18ae, 0x885aca59, /* MIDSTATE */
+0,0,0,0,0,0,0,0,
+0x6f3806c3, 0x41f82a4f, 0x3fd40c1a, 0x00334b39, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
+
+};
+
+#define rotrFixed(x,y) (((x) >> (y)) | ((x) << (32-(y))))
+#define s0(x) (rotrFixed(x,7)^rotrFixed(x,18)^(x>>3))
+#define s1(x) (rotrFixed(x,17)^rotrFixed(x,19)^(x>>10))
+#define Ch(x,y,z) (z^(x&(y^z)))
+#define Maj(x,y,z) (y^((x^y)&(y^z)))
+#define S0(x) (rotrFixed(x,2)^rotrFixed(x,13)^rotrFixed(x,22))
+#define S1(x) (rotrFixed(x,6)^rotrFixed(x,11)^rotrFixed(x,25))
+
+/* SHA256 CONSTANTS */
+static const unsigned SHA_K[64] = {
+        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+        0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+void ms3_compute(unsigned *p)
+{
+	unsigned a,b,c,d,e,f,g,h, ne, na,  i;
+
+	a = p[0]; b = p[1]; c = p[2]; d = p[3]; e = p[4]; f = p[5]; g = p[6]; h = p[7];
+
+	for (i = 0; i < 3; i++) {
+		ne = p[i+16] + SHA_K[i] + h + Ch(e,f,g) + S1(e) + d;
+		na = p[i+16] + SHA_K[i] + h + Ch(e,f,g) + S1(e) + S0(a) + Maj(a,b,c);
+		d = c; c = b; b = a; a = na;
+		h = g; g = f; f = e; e = ne;
+	}
+
+	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) {
+	unsigned w[16];
+	int i;
+
+	ms3_compute(&atrvec[0]);
+	ms3_compute(&atrvec[20]);
+	ms3_compute(&atrvec[40]);
+	spi_init();
+
+	spi_clear_buf();
+
+	spi_emit_break(); /* First we want to break chain! Otherwise we'll get all of traffic bounced to output */
+	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);
+
+	spi_txrx(spi_gettxbuf(), spi_getrxbuf(), spi_getbufsz());
+
+	return 1;
+}
+
+unsigned decnonce(unsigned in)
+{
+	unsigned out;
+
+	/* First part load */
+	out = (in & 0xFF) << 24; in >>= 8;
+
+	/* Byte reversal */
+	in = (((in & 0xaaaaaaaa) >> 1) | ((in & 0x55555555) << 1));
+	in = (((in & 0xcccccccc) >> 2) | ((in & 0x33333333) << 2));
+	in = (((in & 0xf0f0f0f0) >> 4) | ((in & 0x0f0f0f0f) << 4));
+
+	out |= (in >> 2)&0x3FFFFF;
+
+	/* Extraction */
+	if (in & 1) out |= (1 << 23);
+	if (in & 2) out |= (1 << 22);
+
+	out -= 0x800004;
+	return out;
+}
+
+int rehash(unsigned char *midstate, unsigned m7,
+			unsigned ntime, unsigned nbits, unsigned nnonce) {
+	unsigned char in[16];
+	unsigned char hash1[32];
+	unsigned int *in32 = (unsigned int *)in;
+	unsigned char hex[65];
+	unsigned int *mid32 = (unsigned int *)midstate;
+	unsigned out32[8];
+	unsigned char *out = (unsigned char *) out32;
+	int i;
+	sha256_ctx ctx;
+
+	memset( &ctx, 0, sizeof( sha256_ctx ) );
+	memcpy(ctx.h, mid32, 8*4);
+	ctx.tot_len = 64;
+	ctx.len = 0;
+
+	nnonce = bswap_32(nnonce);
+	in32[0] = m7;
+	in32[1] = ntime;
+	in32[2] = nbits;
+	in32[3] = nnonce;
+
+	sha256_update(&ctx, in, 16);
+	sha256_final(&ctx, out);
+	sha256(out, 32, out);
+	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);
+		return 1;
+	}
+	return 0;
+}
+
+int libbitfury_sendHashData(unsigned char *midstate, unsigned m7,
+						 unsigned ntime, unsigned nbits,
+						 unsigned nnonce) {
+	int i;
+
+	/* 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]);
+
+	results_num = 0;
+	while(newbuf[16] == oldbuf[16]) {
+		spi_clear_buf(); spi_emit_break();
+		spi_emit_data(0x3000, (void*)&atrvec[0], 19*4);
+		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);
+			}
+		}
+	}
+
+	om7 = m7;
+	ontime = ntime;
+	onbits = nbits;
+	memcpy(om, midstate, 32);
+
+	memcpy(oldbuf, newbuf, sizeof(oldbuf));
+
+	return 0;
+}
+
+int libbitfury_readHashData(unsigned int *res) {
+	memcpy(res, results, 16*4);
+	return results_num;
+}
+

+ 29 - 0
libbitfury.h

@@ -0,0 +1,29 @@
+/**
+ *   libbitfury.h - headers for Bitfury chip/board library
+ *
+ *   Copyright (c) 2013 bitfury
+ *   Copyright (c) 2013 legkodymov
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2 as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, see http://www.gnu.org/licenses/.
+**/
+#ifndef __LIBBITFURY_H__
+#define __LIBBITFURY_H__
+
+extern int libbitfury_detectChips(void);
+int libbitfury_sendHashData(unsigned char *midstate, unsigned m7,
+						 unsigned ntime, unsigned nbits,
+						 unsigned nnonce);
+
+int libbitfury_readHashData(unsigned int *res);
+
+#endif /* __LIBBITFURY_H__ */

+ 8 - 0
miner.c

@@ -9382,6 +9382,9 @@ extern struct device_drv x6500_api;
 extern struct device_drv ztex_drv;
 #endif
 
+#ifdef USE_BITFURY
+extern struct device_drv bitfury_drv;
+#endif
 
 static int cgminer_id_count = 0;
 static int device_line_id_count;
@@ -9486,6 +9489,11 @@ void drv_detect_all()
 		ztex_drv.drv_detect();
 #endif
 
+#ifdef USE_BITFURY
+	if (!opt_scrypt)
+		bitfury_drv.drv_detect();
+#endif
+
 	/* Detect avalon last since it will try to claim the device regardless
 	 * as detection is unreliable. */
 #ifdef USE_AVALON

+ 7 - 0
miner.h

@@ -112,6 +112,10 @@ static inline int fsync (int fd)
   #include "libztex.h"
 #endif
 
+#ifdef USE_BITFURY
+  #include "libbitfury.h"
+#endif
+
 #ifdef HAVE_BYTESWAP_H
 #include <byteswap.h>
 #endif
@@ -453,6 +457,9 @@ 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;

+ 179 - 0
spidevc.c

@@ -0,0 +1,179 @@
+#include "spidevc.h"
+#include <sys/mman.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <linux/spi/spidev.h>
+#include <time.h>
+#include <unistd.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <sys/stat.h>
+
+static volatile unsigned *gpio;
+
+void spi_init(void)
+{
+	int fd;
+	fd = open("/dev/mem",O_RDWR|O_SYNC);
+	if (fd < 0) { perror("/dev/mem trouble"); exit(1); }
+	gpio = mmap(0,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0x20200000);
+	if (gpio == MAP_FAILED) { perror("gpio mmap trouble"); exit(1); }
+	close(fd);
+}
+
+#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
+#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
+#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
+
+#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
+#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
+
+// 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;
+	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;
+		GPIO_CLR = 1 << 10;
+	}
+	GPIO_CLR = 1 << 10;
+	GPIO_CLR = 1 << 11;
+	INP_GPIO(10);
+	SET_GPIO_ALT(10,0);
+	INP_GPIO(11);
+	SET_GPIO_ALT(11,0);
+	INP_GPIO(9);
+	SET_GPIO_ALT(9,0);
+}
+
+int spi_txrx(const char *wrbuf, char *rdbuf, int bufsz)
+{
+	int fd;
+	int mode, bits, speed, rv, i, j;
+	struct timespec tv;
+	struct spi_ioc_transfer tr[16];
+
+	memset(&tr,0,sizeof(tr));
+	mode = 0; bits = 8; speed = 2000000;
+
+	spi_reset();
+	fd = open("/dev/spidev0.0", O_RDWR);
+	if (fd < 0) { perror("Unable to open SPI device"); exit(1); }
+        if (ioctl(fd, SPI_IOC_WR_MODE, &mode) < 0) { perror("Unable to set WR MODE"); close(fd); return -1; }
+        if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) { perror("Unable to set RD MODE"); close(fd); return -1; }
+        if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0) { perror("Unable to set WR_BITS_PER_WORD"); close(fd); return -1; }
+        if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) { perror("Unable to set RD_BITS_PER_WORD"); close(fd); return -1; }
+        if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) { perror("Unable to set WR_MAX_SPEED_HZ"); close(fd); return -1; }
+        if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) { perror("Unable to set RD_MAX_SPEED_HZ"); close(fd); return -1; }
+
+	rv = 0;
+	while (bufsz >= 4096) {
+                tr[rv].tx_buf = (uintptr_t) wrbuf;
+                tr[rv].rx_buf = (uintptr_t) rdbuf;
+                tr[rv].len = 4096;
+                tr[rv].delay_usecs = 1;
+                tr[rv].speed_hz = speed;
+                tr[rv].bits_per_word = bits;
+                bufsz -= 4096;
+                wrbuf += 4096; rdbuf += 4096; rv ++;
+        }
+        if (bufsz > 0) {
+                tr[rv].tx_buf = (uintptr_t) wrbuf;
+                tr[rv].rx_buf = (uintptr_t) rdbuf;
+                tr[rv].len = (unsigned)bufsz;
+                tr[rv].delay_usecs = 1;
+                tr[rv].speed_hz = speed;
+                tr[rv].bits_per_word = bits;
+                rv ++;
+        }
+
+        i = rv;
+        for (j = 0; j < i; j++) {
+                rv = (int)ioctl(fd, SPI_IOC_MESSAGE(1), (intptr_t)&tr[j]);
+                if (rv < 0) { perror("WTF!"); close(fd); return -1; }
+        }
+
+	close(fd);
+
+	return 0;
+}
+
+#define SPIMAXSZ 256*1024
+static unsigned char spibuf[SPIMAXSZ], spibuf_rx[SPIMAXSZ];
+static unsigned spibufsz;
+
+void spi_clear_buf(void) { spibufsz = 0; }
+unsigned char *spi_getrxbuf(void) { return spibuf_rx; }
+unsigned char *spi_gettxbuf(void) { return spibuf; }
+unsigned spi_getbufsz(void) { return spibufsz; }
+
+void spi_emit_buf_reverse(const char *str, unsigned sz)
+{
+	unsigned i;
+	if (spibufsz + sz >= SPIMAXSZ) return;
+	for (i = 0; i < sz; i++) { // Reverse bit order in each byte!
+		unsigned char p = str[i];
+		p = ((p & 0xaa)>>1) | ((p & 0x55) << 1);
+		p = ((p & 0xcc)>>2) | ((p & 0x33) << 2);
+		p = ((p & 0xf0)>>4) | ((p & 0x0f) << 4);
+		spibuf[spibufsz+i] = p;
+	}
+	spibufsz += sz;
+}
+
+void spi_emit_buf(const char *str, unsigned sz)
+{
+	unsigned i;
+	if (spibufsz + sz >= SPIMAXSZ) return;
+	memcpy(&spibuf[spibufsz], str, sz); spibufsz += sz;
+}
+
+/* TODO: in production, emit just bit-sequences! Eliminate padding to byte! */
+void spi_emit_break(void) { spi_emit_buf("\x4", 1); }
+void spi_emit_fsync(void) { spi_emit_buf("\x6", 1); }
+void spi_emit_fasync(void) { spi_emit_buf("\x5", 1); }
+
+void spi_emit_data(unsigned addr, const char *buf, unsigned len)
+{
+	unsigned char otmp[3];
+	if (len < 4 || len > 128) return; /* This cannot be programmed in single frame! */
+	len /= 4; /* Strip */
+	otmp[0] = (len - 1) | 0xE0;
+	otmp[1] = (addr >> 8)&0xFF; otmp[2] = addr & 0xFF;
+	spi_emit_buf(otmp, 3);
+	spi_emit_buf_reverse(buf, len*4);
+}

+ 30 - 0
spidevc.h

@@ -0,0 +1,30 @@
+#ifndef SPIDEVC_H
+#define SPIDEVC_H
+
+/* Initialize SPI using this function */
+void spi_init(void);
+
+/* TX-RX single frame */
+int spi_txrx(const char *wrbuf, char *rdbuf, int bufsz);
+
+/* SPI BUFFER OPS */
+void spi_clear_buf(void);
+unsigned char *spi_getrxbuf(void);
+unsigned char *spi_gettxbuf(void);
+unsigned spi_getbufsz(void);
+
+void spi_emit_buf_reverse(const char *str, unsigned sz); /* INTERNAL USE: EMIT REVERSED BYTE SEQUENCE DIRECTLY TO STREAM */
+void spi_emit_buf(const char *str, unsigned sz); /* INTERNAL USE: EMIT BYTE SEQUENCE DIRECTLY TO STREAM */
+
+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(void); /* FEED-THROUGH TO NEXT CHIP ASYNCHRONOUSLY (WITHOUT FLIP-FLOP INTERMEDIATE) */
+
+/* TRANSMIT PROGRAMMING SEQUENCE (AND ALSO READ-BACK) */
+/* addr is the destination address in bits (16-bit - 0 to 0xFFFF valid ones)
+   buf is buffer to be transmitted, it will go at position spi_getbufsz()+3
+   len is length in _bytes_, should be 4 to 128 and be multiple of 4, as smallest
+   transmission quantum is 32 bits */
+void spi_emit_data(unsigned addr, const char *buf, unsigned len);
+
+#endif