Commit 832146ac01c15ebc1081a611cecb90195971ade7

Con Kolivas 2014-02-21T11:52:19

Allow any arbitrary frequency to be specified for ANU devices and try to find the nearest frequency when initialising it, reporting if the frequency is not exactly as requested.

diff --git a/ASIC-README b/ASIC-README
index b86182b..0f97e2d 100644
--- a/ASIC-README
+++ b/ASIC-README
@@ -205,12 +205,13 @@ ANTMINER U1 DEVICES
 --anu-freq <arg>    Set AntminerU1 frequency in MHz, range 150-500 (default: 200)
 
 By default, Antminer U1 devices run at a clockspeed of 200. This command allows
-you to specify a chosen frequency to attempt to run all ANU devices at and the
-value must be in increments of 25. Note that cgminer reports hashrate ONLY
-FROM VALID HASHES so if you increase the frequency but your hashrate does not
-increase or it decreases and hardware errors start showing up, you have
-overclocked it too much. In the worst case scenario it will fail to start at
-too high a speed.
+you to specify a chosen frequency to attempt to run all ANU devices at. Cgminer
+will try to find the nearest frequency the device supports and will report if
+the frequency is not exactly as requested. Note that cgminer reports hashrate
+ONLY FROM VALID HASHES so if you increase the frequency but your hashrate does
+not increase or it decreases and hardware errors start showing up, you have
+overclocked it too much. In the worst case scenario it will fail to start at too
+high a speed. Most will run happily up to 250.
 
 
 AVALON AND BITBURNER DEVICES
diff --git a/cgminer.c b/cgminer.c
index a16cc1f..69a5acb 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -192,7 +192,7 @@ static bool no_work;
 #ifdef USE_ICARUS
 char *opt_icarus_options = NULL;
 char *opt_icarus_timing = NULL;
-int opt_anu_freq = 200;
+float opt_anu_freq = 200;
 #endif
 bool opt_worktime;
 #ifdef USE_AVALON
@@ -1078,17 +1078,13 @@ static char *set_icarus_timing(const char *arg)
 	return NULL;
 }
 
-static char *set_int_150_to_500(const char *arg, int *i)
+static char *set_float_125_to_500(const char *arg, float *i)
 {
-	char *err = set_int_range(arg, i, 150, 500);
-	int mult;
+	char *err = opt_set_floatval(arg, i);
+
+	if (*i < 125 || *i > 500)
+		return "Value out of range";
 
-	if (err)
-		return err;
-	mult = *i / 25;
-	mult *= 25;
-	if (mult != *i)
-		return "Frequency must be a multiple of 25";
 	return NULL;
 }
 #endif
@@ -1161,8 +1157,8 @@ static char *set_null(const char __maybe_unused *arg)
 static struct opt_table opt_config_table[] = {
 #ifdef USE_ICARUS
 	OPT_WITH_ARG("--anu-freq",
-		     set_int_150_to_500, &opt_show_intval, &opt_anu_freq,
-		     "Set AntminerU1 frequency in MHz, range 150-500"),
+		     set_float_125_to_500, &opt_show_intval, &opt_anu_freq,
+		     "Set AntminerU1 frequency in MHz, range 125-500"),
 #endif
 	OPT_WITH_ARG("--api-allow",
 		     set_api_allow, NULL, NULL,
diff --git a/driver-icarus.c b/driver-icarus.c
index 6e25452..a757cf4 100644
--- a/driver-icarus.c
+++ b/driver-icarus.c
@@ -38,6 +38,7 @@
 #include <strings.h>
 #include <sys/time.h>
 #include <unistd.h>
+#include <math.h>
 
 #include "config.h"
 
@@ -842,25 +843,45 @@ unsigned char crc5(unsigned char *ptr, unsigned char len)
 	return crc;
 }
 
-static unsigned char anu_freq_table[] = {
-	0x05,	// 150
-	0x06,
-	0x07,	// 200 == default
-	0x08,
-	0x09,
-	0x0a,
-	0x0b,	// 300
-	0x4c,
-	0x4d,
-	0x4e,
-	0x4f,	// 400
-	0x50,
-	0x51,
-	0x52,
-	0x53	// 500
-};
+static bool anu_freqfound = false;
+static uint16_t anu_freq_hex;
 
-#define ANU_FREQTODATA(freq) (anu_freq_table[(freq - 150) / 25])
+static void anu_find_freqhex(void)
+{
+	float fout, best_fout = opt_anu_freq;
+	int od, nf, nr, no, n, m, bs;
+	float best_diff = 1000;
+
+	anu_freqfound = true;
+
+	for (od = 0; od < 4; od++) {
+		no = 1 << od;
+		for (n = 0; n < 16; n++) {
+			nr = n + 1;
+			for (m = 0; m < 64; m++) {
+				nf = m + 1;
+				fout = 25 * (float)nf /((float)(nr) * (float)(no));
+				if (fabsf(fout - opt_anu_freq)  > best_diff)
+					continue;
+				if (500 <= (fout * no) && (fout * no) <= 1000)
+					bs = 1;
+				else
+					bs = 0;
+				best_diff = fabsf(fout - opt_anu_freq);
+				best_fout = fout;
+				anu_freq_hex = (bs << 14) | (m << 7) | (n << 2) | od;
+				if (fout == opt_anu_freq) {
+					applog(LOG_DEBUG, "ANU found exact frequency %.1f with hex %04x",
+					       opt_anu_freq, anu_freq_hex);
+					return;
+				}
+			}
+		}
+	}
+	opt_anu_freq = best_fout;
+	applog(LOG_NOTICE, "ANU found nearest frequency %.1f with hex %04x", opt_anu_freq,
+	       anu_freq_hex);
+}
 
 static bool set_anu_freq(struct cgpu_info *icarus, struct ICARUS_INFO *info)
 {
@@ -868,11 +889,13 @@ static bool set_anu_freq(struct cgpu_info *icarus, struct ICARUS_INFO *info)
 	int amount, err;
 	char buf[512];
 
+	if (!anu_freqfound)
+		anu_find_freqhex();
 	memset(cmd_buf, 0, 4);
 	memset(rdreg_buf, 0, 4);
 	cmd_buf[0] = 2 | 0x80;
-	cmd_buf[1] = ANU_FREQTODATA(opt_anu_freq);	//16-23
-	cmd_buf[2] = 0x81;	//8-15
+	cmd_buf[1] = (anu_freq_hex & 0xff00u) >> 8;
+	cmd_buf[2] = (anu_freq_hex & 0x00ffu);
 	cmd_buf[3] = crc5(cmd_buf, 27);
 
 	rdreg_buf[0] = 4 | 0x80;
diff --git a/miner.h b/miner.h
index cfcf754..88833ff 100644
--- a/miner.h
+++ b/miner.h
@@ -968,7 +968,7 @@ extern bool opt_restart;
 #ifdef USE_ICARUS
 extern char *opt_icarus_options;
 extern char *opt_icarus_timing;
-extern int opt_anu_freq;
+extern float opt_anu_freq;
 #endif
 extern bool opt_worktime;
 #ifdef USE_AVALON