Commit e067be421aa43558504c1b6198f4134d6bcb9e09

Kano 2012-08-01T22:50:30

ICA support 57600 baud rate, up to 8 FPGA and partial working FPGA boards

diff --git a/cgminer.c b/cgminer.c
index 0de93f0..e2976fd 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -142,6 +142,7 @@ bool opt_api_listen;
 bool opt_api_network;
 bool opt_delaynet;
 bool opt_disable_pool = true;
+char *opt_icarus_options = NULL;
 char *opt_icarus_timing = NULL;
 
 char *opt_kernel_path;
@@ -710,6 +711,13 @@ static char *set_api_description(const char *arg)
 }
 
 #ifdef USE_ICARUS
+static char *set_icarus_options(const char *arg)
+{
+	opt_set_charp(arg, &opt_icarus_options);
+
+	return NULL;
+}
+
 static char *set_icarus_timing(const char *arg)
 {
 	opt_set_charp(arg, &opt_icarus_timing);
@@ -873,6 +881,9 @@ static struct opt_table opt_config_table[] = {
 		     "Override sha256 kernel to use (diablo, poclbm, phatk or diakgcn) - one value or comma separated"),
 #endif
 #ifdef USE_ICARUS
+	OPT_WITH_ARG("--icarus-options",
+		     set_icarus_options, NULL, NULL,
+		     opt_hidden),
 	OPT_WITH_ARG("--icarus-timing",
 		     set_icarus_timing, NULL, NULL,
 		     opt_hidden),
@@ -3011,6 +3022,8 @@ void write_config(FILE *fcfg)
 		fprintf(fcfg, ",\n\"api-description\" : \"%s\"", opt_api_description);
 	if (opt_api_groups)
 		fprintf(fcfg, ",\n\"api-groups\" : \"%s\"", opt_api_groups);
+	if (opt_icarus_options)
+		fprintf(fcfg, ",\n\"icarus-options\" : \"%s\"", opt_icarus_options);
 	if (opt_icarus_timing)
 		fprintf(fcfg, ",\n\"icarus-timing\" : \"%s\"", opt_icarus_timing);
 	fputs("\n}", fcfg);
diff --git a/driver-icarus.c b/driver-icarus.c
index 5f2c78a..0b3aea7 100644
--- a/driver-icarus.c
+++ b/driver-icarus.c
@@ -65,7 +65,7 @@
 #define ASSERT1(condition) __maybe_unused static char sizeof_uint32_t_must_be_4[(condition)?1:-1]
 ASSERT1(sizeof(uint32_t) == 4);
 
-#define ICARUS_READ_TIME ((double)ICARUS_READ_SIZE * (double)8.0 / (double)ICARUS_IO_SPEED)
+#define ICARUS_READ_TIME(baud) ((double)ICARUS_READ_SIZE * (double)8.0 / (double)(baud))
 
 // Fraction of a second, USB timeout is measured in
 // i.e. 10 means 1/10 of a second
@@ -176,11 +176,36 @@ struct ICARUS_INFO {
 	// (which will only affect W)
 	uint64_t history_count;
 	struct timeval history_time;
+
+	// icarus-options
+	int baud;
+	int work_division;
+	int fpga_count;
+	uint32_t nonce_mask;
 };
 
+#define END_CONDITION 0x0000ffff
+
 // One for each possible device
 static struct ICARUS_INFO **icarus_info;
 
+// Looking for options in --icarus-timing and --icarus-options:
+//
+// Code increments this each time we start to look at a device
+// However, this means that if other devices are checked by
+// the Icarus code (e.g. BFL) they will count in the option offset
+//
+// This, however, is deterministic so that's OK
+//
+// If we were to increment after successfully finding an Icarus
+// that would be random since an Icarus may fail and thus we'd
+// not be able to predict the option order
+//
+// This also assumes that serial_detect() checks them sequentially
+// and in the order specified on the command line
+//
+static int option_offset = -1;
+
 struct device_api icarus_api;
 
 static void rev(unsigned char *s, size_t l)
@@ -195,8 +220,8 @@ static void rev(unsigned char *s, size_t l)
 	}
 }
 
-#define icarus_open2(devpath, purge)  serial_open(devpath, 115200, ICARUS_READ_FAULT_DECISECONDS, purge)
-#define icarus_open(devpath)  icarus_open2(devpath, false)
+#define icarus_open2(devpath, baud, purge)  serial_open(devpath, baud, ICARUS_READ_FAULT_DECISECONDS, purge)
+#define icarus_open(devpath, baud)  icarus_open2(devpath, baud, false)
 
 static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, struct thr_info *thr, int read_count)
 {
@@ -272,7 +297,7 @@ static const char *timing_mode_str(enum timing_mode timing_mode)
 	}
 }
 
-static void set_timing_mode(struct cgpu_info *icarus)
+static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus)
 {
 	struct ICARUS_INFO *info = icarus_info[icarus->device_id];
 	double Hs;
@@ -285,7 +310,7 @@ static void set_timing_mode(struct cgpu_info *icarus)
 		buf[0] = '\0';
 	else {
 		ptr = opt_icarus_timing;
-		for (i = 0; i < icarus->device_id; i++) {
+		for (i = 0; i < this_option_offset; i++) {
 			comma = strchr(ptr, ',');
 			if (comma == NULL)
 				break;
@@ -354,11 +379,122 @@ static void set_timing_mode(struct cgpu_info *icarus)
 
 	applog(LOG_DEBUG, "Icarus: Init: %d mode=%s read_count=%d Hs=%e",
 		icarus->device_id, timing_mode_str(info->timing_mode), info->read_count, info->Hs);
+}
+
+static uint32_t mask(int work_division)
+{
+	char err_buf[BUFSIZ+1];
+	uint32_t nonce_mask = 0x7fffffff;
+
+	// yes we can calculate these, but this way it's easy to see what they are
+	switch (work_division) {
+	case 1:
+		nonce_mask = 0xffffffff;
+		break;
+	case 2:
+		nonce_mask = 0x7fffffff;
+		break;
+	case 4:
+		nonce_mask = 0x3fffffff;
+		break;
+	case 8:
+		nonce_mask = 0x1fffffff;
+		break;
+	default:
+		sprintf(err_buf, "Invalid2 icarus-options for work_division (%d) must be 1, 2, 4 or 8", work_division);
+		quit(1, err_buf);
+	}
+
+	return nonce_mask;
+}
+
+static void get_options(int this_option_offset, int *baud, int *work_division, int *fpga_count)
+{
+	char err_buf[BUFSIZ+1];
+	char buf[BUFSIZ+1];
+	char *ptr, *comma, *colon, *colon2;
+	size_t max;
+	int i, tmp;
+
+	if (opt_icarus_options == NULL)
+		buf[0] = '\0';
+	else {
+		ptr = opt_icarus_options;
+		for (i = 0; i < this_option_offset; i++) {
+			comma = strchr(ptr, ',');
+			if (comma == NULL)
+				break;
+			ptr = comma + 1;
+		}
+
+		comma = strchr(ptr, ',');
+		if (comma == NULL)
+			max = strlen(ptr);
+		else
+			max = comma - ptr;
 
+		if (max > BUFSIZ)
+			max = BUFSIZ;
+		strncpy(buf, ptr, max);
+		buf[max] = '\0';
+	}
+
+	*baud = ICARUS_IO_SPEED;
+	*work_division = 2;
+	*fpga_count = 2;
+
+	if (*buf) {
+		colon = strchr(buf, ':');
+		if (colon)
+			*(colon++) = '\0';
+
+		if (*buf) {
+			tmp = atoi(buf);
+			switch (tmp) {
+			case 115200:
+				*baud = 115200;
+				break;
+			case 57600:
+				*baud = 57600;
+				break;
+			default:
+				sprintf(err_buf, "Invalid icarus-options for baud (%s) must be 115200 or 57600", buf);
+				quit(1, err_buf);
+			}
+		}
+
+		if (colon && *colon) {
+			colon2 = strchr(colon, ':');
+			if (colon2)
+				*(colon2++) = '\0';
+
+			if (*colon) {
+				tmp = atoi(colon);
+				if (tmp == 1 || tmp == 2 || tmp == 4 || tmp == 8)
+					*work_division = tmp;
+				else {
+					sprintf(err_buf, "Invalid icarus-options for work_division (%s) must be 1, 2, 4 or 8", colon);
+					quit(1, err_buf);
+				}
+			}
+
+			if (colon2 && *colon2) {
+				tmp = atoi(colon2);
+				if (tmp > 0 && tmp <= *work_division)
+					*fpga_count = tmp;
+				else {
+					sprintf(err_buf, "Invalid icarus-options for fpga_count (%s) must be >0 and <=work_division (%d)", colon2, *work_division);
+					quit(1, err_buf);
+				}
+			}
+		}
+	}
 }
 
 static bool icarus_detect_one(const char *devpath)
 {
+	int this_option_offset = ++option_offset;
+
 	struct ICARUS_INFO *info;
 	struct timeval tv_start, tv_finish;
 	int fd;
@@ -379,9 +515,13 @@ static bool icarus_detect_one(const char *devpath)
 	unsigned char ob_bin[64], nonce_bin[ICARUS_READ_SIZE];
 	char *nonce_hex;
 
+	int baud, work_division, fpga_count;
+
+	get_options(this_option_offset, &baud, &work_division, &fpga_count);
+
 	applog(LOG_DEBUG, "Icarus Detect: Attempting to open %s", devpath);
 
-	fd = icarus_open2(devpath, true);
+	fd = icarus_open2(devpath, baud, true);
 	if (unlikely(fd == -1)) {
 		applog(LOG_ERR, "Icarus Detect: Failed to open %s", devpath);
 		return false;
@@ -429,6 +569,9 @@ static bool icarus_detect_one(const char *devpath)
 	applog(LOG_INFO, "Found Icarus at %s, mark as %d",
 		devpath, icarus->device_id);
 
+	applog(LOG_DEBUG, "Icarus: Init: %d baud=%d work_division=%d fpga_count=%d",
+		icarus->device_id, baud, work_division, fpga_count);
+
 	// Since we are adding a new device on the end it needs to always be allocated
 	icarus_info[icarus->device_id] = (struct ICARUS_INFO *)malloc(sizeof(struct ICARUS_INFO));
 	if (unlikely(!(icarus_info[icarus->device_id])))
@@ -439,10 +582,15 @@ static bool icarus_detect_one(const char *devpath)
 	// Initialise everything to zero for a new device
 	memset(info, 0, sizeof(struct ICARUS_INFO));
 
-	info->golden_hashes = (golden_nonce_val & 0x7fffffff) << 1;
+	info->baud = baud;
+	info->work_division = work_division;
+	info->fpga_count = fpga_count;
+	info->nonce_mask = mask(work_division);
+
+	info->golden_hashes = (golden_nonce_val & info->nonce_mask) * fpga_count;
 	timersub(&tv_finish, &tv_start, &(info->golden_tv));
 
-	set_timing_mode(icarus);
+	set_timing_mode(this_option_offset, icarus);
 
 	return true;
 }
@@ -458,7 +606,7 @@ static bool icarus_prepare(struct thr_info *thr)
 
 	struct timeval now;
 
-	int fd = icarus_open(icarus->device_path);
+	int fd = icarus_open(icarus->device_path, icarus_info[icarus->device_id]->baud);
 	if (unlikely(-1 == fd)) {
 		applog(LOG_ERR, "Failed to open Icarus on %s",
 		       icarus->device_path);
@@ -565,11 +713,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 	submit_nonce(thr, work, nonce);
 
-	hash_count = (nonce & 0x7fffffff);
-	if (hash_count++ == 0x7fffffff)
-		hash_count = 0xffffffff;
-	else
-		hash_count <<= 1;
+	hash_count = (nonce & info->nonce_mask);
+	hash_count++;
+	hash_count *= info->fpga_count;
 
 	if (opt_debug || info->do_icarus_timing)
 		timersub(&tv_finish, &tv_start, &elapsed);
@@ -580,7 +726,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	}
 
 	// ignore possible end condition values
-	if (info->do_icarus_timing && (nonce & 0x7fffffff) > 0x000fffff && (nonce & 0x7fffffff) < 0x7ff00000) {
+	if (info->do_icarus_timing
+	&&  ((nonce & info->nonce_mask) > END_CONDITION)
+	&&  ((nonce & info->nonce_mask) < (info->nonce_mask & ~END_CONDITION))) {
 		gettimeofday(&tv_history_start, NULL);
 
 		history0 = &(info->history[0]);
@@ -590,7 +738,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 		Ti = (double)(elapsed.tv_sec)
 			+ ((double)(elapsed.tv_usec))/((double)1000000)
-			- ICARUS_READ_TIME;
+			- ((double)ICARUS_READ_TIME(info->baud));
 		Xi = (double)hash_count;
 		history0->sumXiTi += Xi * Ti;
 		history0->sumXi += Xi;
@@ -700,6 +848,9 @@ static struct api_data *icarus_api_stats(struct cgpu_info *cgpu)
 	root = api_add_uint(root, "timing_values", &(info->history[0].values), false);
 	root = api_add_const(root, "timing_mode", timing_mode_str(info->timing_mode), false);
 	root = api_add_bool(root, "is_timing", &(info->do_icarus_timing), false);
+	root = api_add_int(root, "baud", &(info->baud), false);
+	root = api_add_int(root, "work_division", &(info->work_division), false);
+	root = api_add_int(root, "fpga_count", &(info->fpga_count), false);
 
 	return root;
 }
diff --git a/miner.h b/miner.h
index 09cb503..44d0342 100644
--- a/miner.h
+++ b/miner.h
@@ -557,6 +557,7 @@ extern bool opt_api_listen;
 extern bool opt_api_network;
 extern bool opt_delaynet;
 extern bool opt_restart;
+extern char *opt_icarus_options;
 extern char *opt_icarus_timing;
 #ifdef USE_BITFORCE
 extern bool opt_bfl_noncerange;