Browse Source

x6500: Implement mining protocols (doesn't work yet)

Luke Dashjr 13 years ago
parent
commit
eac0c2a8e9
1 changed files with 171 additions and 3 deletions
  1. 171 3
      driver-x6500.c

+ 171 - 3
driver-x6500.c

@@ -26,6 +26,88 @@
 
 struct device_api x6500_api;
 
+#define fromlebytes(ca, j)  (ca[j] | (((uint16_t)ca[j+1])<<8) | (((uint32_t)ca[j+2])<<16) | (((uint32_t)ca[j+3])<<24))
+
+static
+void int2bits(uint32_t n, uint8_t *b, uint8_t bits)
+{
+	uint8_t i;
+	for (i = (bits + 7) / 8; i > 0; )
+		b[--i] = 0;
+	for (i = 0; i < bits; ++i) {
+		if (n & 1)
+			b[i/8] |= 0x80 >> (i % 8);
+		n >>= 1;
+	}
+}
+
+static
+uint32_t bits2int(uint8_t *b, uint8_t bits)
+{
+	uint32_t n, i;
+	n = 0;
+	for (i = 0; i < bits; ++i)
+		if (b[i/8] & (0x80 >> (i % 8)))
+			n |= 1<<i;
+	return n;
+}
+
+static
+void bitendianflip(void *n, size_t bits)
+{
+	size_t i;
+	uint8_t *b = n;
+	// NOTE: this doesn't work with non-byte boundaries
+	bits /= 8;
+	for (i = 0; i < bits; ++i)
+		b[i] = ((b[i] &    1) ? 0x80 : 0)
+		     | ((b[i] &    2) ? 0x40 : 0)
+		     | ((b[i] &    4) ? 0x20 : 0)
+		     | ((b[i] &    8) ? 0x10 : 0)
+		     | ((b[i] & 0x10) ?    8 : 0)
+		     | ((b[i] & 0x20) ?    4 : 0)
+		     | ((b[i] & 0x40) ?    2 : 0)
+		     | ((b[i] & 0x80) ?    1 : 0);
+}
+
+static
+void checksum(uint8_t *b, uint8_t bits)
+{
+	uint8_t i;
+	uint8_t checksum = 1;
+	for(i = 0; i < bits; ++i)
+		checksum ^= (b[i/8] & (0x80 >> (i % 8))) ? 1 : 0;
+	if (checksum)
+		b[i/8] |= 0x80 >> (i % 8);
+}
+
+static
+void x6500_set_register(struct jtag_port *jp, uint8_t addr, uint32_t nv)
+{
+	uint8_t buf[38];
+	jtag_write(jp, JTAG_REG_IR, "\x40", 6);
+	int2bits(nv, &buf[0], 32);
+	int2bits(addr, &buf[4], 4);
+	buf[4] |= 8;
+	checksum(buf, 37);
+	jtag_write(jp, JTAG_REG_DR, buf, 38);
+	jtag_run(jp);
+}
+
+static
+uint32_t x6500_get_register(struct jtag_port *jp, uint8_t addr)
+{
+	uint8_t buf[4];
+	jtag_write(jp, JTAG_REG_IR, "\x40", 6);
+	int2bits(addr, &buf[0], 4);
+	checksum(buf, 5);
+	jtag_write(jp, JTAG_REG_DR, buf, 6);
+	jtag_read (jp, JTAG_REG_DR, buf, 32);
+	jtag_reset(jp);
+	bitendianflip(buf, 32);
+	return bits2int(buf, 32);
+}
+
 static bool x6500_foundusb(libusb_device *dev, const char *product, const char *serial)
 {
 	struct cgpu_info *x6500;
@@ -65,7 +147,7 @@ static bool x6500_prepare(struct thr_info *thr)
 	struct cgpu_info *x6500 = thr->cgpu;
 	mutex_init(&x6500->device_mutex);
 	struct ft232r_device_handle *ftdi = ft232r_open(x6500->cgpu_data);
-	x6500->cgpu_data = NULL;
+	x6500->device_ft232r = NULL;
 	if (!ftdi)
 		return false;
 	if (!ft232r_set_bitmode(ftdi, 0xee, 4))
@@ -238,8 +320,12 @@ static bool x6500_fpga_init(struct thr_info *thr)
 		applog(LOG_DEBUG, "%s %u.%u: FPGA is already programmed :)",
 		       x6500->api->name, x6500->device_id, fpgaid);
 	
+	thr->cgpu_data = fpga;
+
+	x6500_set_register(jp, 0xD, 200);  // Set clock speed
+
 	mutex_unlock(&x6500->device_mutex);
-	return false;
+	return true;
 }
 
 static void
@@ -257,6 +343,88 @@ get_x6500_statline_before(char *buf, struct cgpu_info *x6500)
 	strcat(buf, "               | ");
 }
 
+static
+bool x6500_start_work(struct thr_info *thr, struct work *work)
+{
+	struct cgpu_info *x6500 = thr->cgpu;
+	struct x6500_fpga_data *fpga = thr->cgpu_data;
+	char fpgaid = thr->device_thread;
+
+	mutex_lock(&x6500->device_mutex);
+
+	for (int i = 1, j = 0; i < 9; ++i, j += 4)
+		x6500_set_register(&fpga->jtag, i, fromlebytes(work->midstate, j));
+
+	for (int i = 9, j = 64; i < 12; ++i, j += 4)
+		x6500_set_register(&fpga->jtag, i, fromlebytes(work->data, j));
+
+	//gettimeofday(&fpga->tv_workstart, NULL);
+	mutex_unlock(&x6500->device_mutex);
+
+	if (opt_debug) {
+		char *xdata = bin2hex(work->data, 80);
+		applog(LOG_DEBUG, "%s %u.%u: Started work: %s",
+		       x6500->api->name, x6500->device_id, fpgaid, xdata);
+		free(xdata);
+	}
+
+	return true;
+}
+
+static
+int64_t x6500_process_results(struct thr_info *thr, struct work *work)
+{
+	struct cgpu_info *x6500 = thr->cgpu;
+	struct x6500_fpga_data *fpga = thr->cgpu_data;
+	struct jtag_port *jtag = &fpga->jtag;
+	char fpgaid = thr->device_thread;
+
+	uint32_t nonce;
+	long iter;
+	bool bad;
+
+	iter = 200;
+	while (1) {
+		mutex_lock(&x6500->device_mutex);
+		nonce = x6500_get_register(jtag, 0xE);
+		mutex_unlock(&x6500->device_mutex);
+		if (nonce != 0xffffffff) {
+			bad = !test_nonce(work, nonce, false);
+			if (!bad) {
+				submit_nonce(thr, work, nonce);
+				applog(LOG_DEBUG, "%s %u.%u: Nonce for current  work: %08lx",
+				       x6500->api->name, x6500->device_id, fpgaid,
+				       (unsigned long)nonce);
+			} else {
+				applog(LOG_DEBUG, "%s %u.%u: Nonce with H not zero  : %08lx",
+				       x6500->api->name, x6500->device_id, fpgaid,
+				       (unsigned long)nonce);
+				++hw_errors;
+				++x6500->hw_errors;
+			}
+		}
+		if (thr->work_restart || !--iter)
+			break;
+		usleep(1000);
+		if (thr->work_restart)
+			break;
+	}
+
+	return 10000000;
+}
+
+static int64_t
+x6500_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce)
+{
+	if (!x6500_start_work(thr, work))
+		return -1;
+
+	int64_t hashes = x6500_process_results(thr, work);
+	if (hashes > 0)
+		work->blk.nonce += hashes;
+	return hashes;
+}
+
 struct device_api x6500_api = {
 	.dname = "x6500",
 	.name = "XBS",
@@ -264,6 +432,6 @@ struct device_api x6500_api = {
 	.thread_prepare = x6500_prepare,
 	.thread_init = x6500_fpga_init,
 	.get_statline_before = get_x6500_statline_before,
-// 	.scanhash = x6500_fpga_scanhash,
+	.scanhash = x6500_scanhash,
 // 	.thread_shutdown = x6500_fpga_shutdown,
 };