Commit f15d2233fa57ef9f06f7ed60c67f31afca44e2c9

Kano 2012-05-22T09:42:43

Icarus: fix abort calculation/allow user specified abort

diff --git a/FPGA-README b/FPGA-README
index 203eaf2..7972514 100644
--- a/FPGA-README
+++ b/FPGA-README
@@ -7,10 +7,10 @@ Icarus
 There is a hidden option in cgminer when Icarus support is compiled in:
 
 --icarus-timing <arg> Set how the Icarus timing is calculated - one setting/value for all or comma separated
-           default       Use the default Icarus hash time (2.6316ns)
+           default[=N]   Use the default Icarus hash time (2.6316ns)
            short         Calculate the hash time and stop adjusting it at ~315 difficulty 1 shares (~1hr)
            long          Re-calculate the hash time continuously
-           value         Specify the hash time in nanoseconds (e.g. 2.6316)
+           value[=N]     Specify the hash time in nanoseconds (e.g. 2.6316) and abort time (e.g. 2.6316=80)
 
      Icarus timing is required for devices that do not exactly match a default Icarus Rev3 in
      processing speed
@@ -35,6 +35,8 @@ There is a hidden option in cgminer when Icarus support is compiled in:
 
      In 'default' or 'value' mode the 'constants' are calculated once at the start, based on the default
      value or the value specified
+     The optional additional =N specifies to set the default abort at N 1/10ths of a second, not the
+     calculated value, which is 112 for 2.6316ns
 
      To determine the hash time value for a non Icarus Rev3 device or an Icarus Rev3 with a different
      bitstream to the default one, use 'long' mode and give it at least a few hundred shares, or use
diff --git a/driver-icarus.c b/driver-icarus.c
index a4efc96..eb4d03a 100644
--- a/driver-icarus.c
+++ b/driver-icarus.c
@@ -82,7 +82,7 @@ ASSERT1(sizeof(uint32_t) == 4);
 // Since this rounds up a the last digit - it is a slight overestimate
 // Thus the hash rate will be a VERY slight underestimate
 // (by a lot less than the displayed accuracy)
-#define ICARUS_HASH_TIME 0.0000000026316
+#define ICARUS_REV3_HASH_TIME 0.0000000026316
 #define NANOSEC 1000000000.0
 
 // Icarus Rev3 doesn't send a completion message when it finishes
@@ -259,17 +259,22 @@ static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, in
 	ssize_t ret = 0;
 	int rc = 0;
 	int read_amount = ICARUS_READ_SIZE;
+	bool first = true;
 
+	// Read reply 1 byte at a time to get earliest tv_finish
 	while (true) {
-		ret = read(fd, buf, read_amount);
-		gettimeofday(tv_finish, NULL);
+		ret = read(fd, buf, 1);
+
+		if (first)
+			gettimeofday(tv_finish, NULL);
+
 		if (ret >= read_amount)
 			return 0;
 
-		// Allow a partial I/O
 		if (ret > 0) {
 			buf += ret;
 			read_amount -= ret;
+			first = false;
 			continue;
 		}
 			
@@ -328,7 +333,7 @@ static void set_timing_mode(struct cgpu_info *icarus)
 	struct ICARUS_INFO *info = icarus_info[icarus->device_id];
 	double Hs;
 	char buf[BUFSIZ+1];
-	char *ptr, *comma;
+	char *ptr, *comma, *eq;
 	size_t max;
 	int i;
 
@@ -355,14 +360,17 @@ static void set_timing_mode(struct cgpu_info *icarus)
 		buf[max] = '\0';
 	}
 
+	info->Hs = 0;
+	info->read_count = 0;
+
 	if (strcasecmp(buf, MODE_SHORT_STR) == 0) {
-		info->Hs = ICARUS_HASH_TIME;
+		info->Hs = ICARUS_REV3_HASH_TIME;
 		info->read_count = ICARUS_READ_COUNT_TIMING;
 
 		info->timing_mode = MODE_SHORT;
 		info->do_icarus_timing = true;
 	} else if (strcasecmp(buf, MODE_LONG_STR) == 0) {
-		info->Hs = ICARUS_HASH_TIME;
+		info->Hs = ICARUS_REV3_HASH_TIME;
 		info->read_count = ICARUS_READ_COUNT_TIMING;
 
 		info->timing_mode = MODE_LONG;
@@ -370,16 +378,29 @@ static void set_timing_mode(struct cgpu_info *icarus)
 	} else if ((Hs = atof(buf)) != 0) {
 		info->Hs = Hs / NANOSEC;
 		info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
-		info->read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
+
+		if ((eq = strchr(buf, '=')) != NULL)
+			info->read_count = atoi(eq+1);
+
+		if (info->read_count < 1)
+			info->read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
+
+		if (unlikely(info->read_count < 1))
+			info->read_count = 1;
 
 		info->timing_mode = MODE_VALUE;
 		info->do_icarus_timing = false;
 	} else {
 		// Anything else in buf just uses DEFAULT mode
 
-		info->Hs = ICARUS_HASH_TIME;
+		info->Hs = ICARUS_REV3_HASH_TIME;
 		info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
-		info->read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
+
+		if ((eq = strchr(buf, '=')) != NULL)
+			info->read_count = atoi(eq+1);
+
+		if (info->read_count < 1)
+			info->read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
 
 		info->timing_mode = MODE_DEFAULT;
 		info->do_icarus_timing = false;
@@ -562,10 +583,7 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	if (ret)
 		return 0;	/* This should never happen */
 
-	info = icarus_info[icarus->device_id];
-
-	if (opt_debug || info->do_icarus_timing)
-		gettimeofday(&tv_start, NULL);
+	gettimeofday(&tv_start, NULL);
 
 	if (opt_debug) {
 		ob_hex = bin2hex(ob_bin, sizeof(ob_bin));
@@ -578,6 +596,7 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 	/* Icarus will return 4 bytes (ICARUS_READ_SIZE) nonces or nothing */
 	memset(nonce_bin, 0, sizeof(nonce_bin));
+	info = icarus_info[icarus->device_id];
 	ret = icarus_gets(nonce_bin, fd, &tv_finish, thr_id, info->read_count);
 
 	work->blk.nonce = 0xffffffff;
@@ -654,7 +673,9 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 		if (history0->values >= info->min_data_count
 		&&  timercmp(&tv_start, &(history0->finish), >)) {
 			for (i = INFO_HISTORY; i > 0; i--)
-				memcpy(&(info->history[i]), &(info->history[i-1]), sizeof(struct ICARUS_HISTORY));
+				memcpy(&(info->history[i]),
+					&(info->history[i-1]),
+					sizeof(struct ICARUS_HISTORY));
 
 			// Initialise history0 to zero for summary calculation
 			memset(history0, 0, sizeof(struct ICARUS_HISTORY));