Browse Source

Merge pull request #123 from xiangfu/icarus

Add Icarus Support to Cgminer
nfactor-troky
Con Kolivas 12 years ago
parent
commit
882e4d85de
  1. 3
      Makefile.am
  2. 21
      README
  3. 19
      cgminer.c
  4. 21
      configure.ac
  5. 333
      icarus.c

3
Makefile.am

@ -70,3 +70,6 @@ if HAS_BITFORCE @@ -70,3 +70,6 @@ if HAS_BITFORCE
cgminer_SOURCES += bitforce.c
endif
if HAS_ICARUS
cgminer_SOURCES += icarus.c
endif

21
README

@ -50,6 +50,7 @@ CGMiner specific configuration options: @@ -50,6 +50,7 @@ CGMiner specific configuration options:
--disable-opencl Override detection and disable building with opencl
--disable-adl Override detection and disable building with adl
--enable-bitforce Compile support for BitForce FPGAs(default disabled)
--enable-icarus Compile support for Icarus Board(default disabled)
Basic *nix build instructions:
To build with GPU mining support:
@ -196,9 +197,9 @@ GPU only options: @@ -196,9 +197,9 @@ GPU only options:
--ndevs|-n Enumerate number of detected GPUs and exit
BitForce only options:
FPGA mining boards(BitForce, Icarus) only options:
--scan-serial|-S <arg> Serial port to probe for BitForce device
--scan-serial|-S <arg> Serial port to probe for FPGA mining device
CPU only options:
@ -317,14 +318,14 @@ The output line shows the following: @@ -317,14 +318,14 @@ The output line shows the following:
(5s):1713.6 (avg):1707.8 Mh/s | Q:301 A:729 R:8 HW:0 E:242% U:22.53/m
Each column is as follows:
A 5 second exponentially decaying average hash rate
An all time average hash rate
The number of requested (Queued) work items from the pools
The number of Accepted shares
The number of Rejected shares
The number of HardWare errors
The Efficiency defined as number of shares returned / work item
The Utility defined as the number of shares / minute
5s: A 5 second exponentially decaying average hash rate
avg: An all time average hash rate
Q: The number of requested (Queued) work items from the pools
A: The number of Accepted shares
R: The number of Rejected shares
HW: The number of HardWare errors
E: The Efficiency defined as number of shares returned / work item
U: The Utility defined as the number of shares / minute
GPU 1: 73.5C 2551RPM | 427.3/443.0Mh/s | A:8 R:0 HW:0 U:4.39/m

19
cgminer.c

@ -399,7 +399,7 @@ static char *set_int_1_to_10(const char *arg, int *i) @@ -399,7 +399,7 @@ static char *set_int_1_to_10(const char *arg, int *i)
return set_int_range(arg, i, 1, 10);
}
#ifdef USE_BITFORCE
#if defined(USE_BITFORCE) || defined(USE_ICARUS)
static char *add_serial(char *arg)
{
string_elist_add(arg, &scan_devices);
@ -661,7 +661,7 @@ static struct opt_table opt_config_table[] = { @@ -661,7 +661,7 @@ static struct opt_table opt_config_table[] = {
OPT_WITHOUT_ARG("--disable-gpu|-G",
opt_set_bool, &opt_nogpu,
"Disable GPU mining even if suitable devices exist"),
#if defined(WANT_CPUMINE) && (defined(HAVE_OPENCL) || defined(USE_BITFORCE))
#if defined(WANT_CPUMINE) && (defined(HAVE_OPENCL) || defined(USE_BITFORCE) || defined(USE_ICARUS))
OPT_WITHOUT_ARG("--enable-cpu|-C",
opt_set_bool, &opt_usecpu,
"Enable CPU mining with other mining (default: no CPU mining if other devices exist)"),
@ -776,10 +776,10 @@ static struct opt_table opt_config_table[] = { @@ -776,10 +776,10 @@ static struct opt_table opt_config_table[] = {
OPT_WITHOUT_ARG("--round-robin",
set_rr, &pool_strategy,
"Change multipool strategy from failover to round robin on failure"),
#ifdef USE_BITFORCE
#if defined(USE_BITFORCE) || defined(USE_ICARUS)
OPT_WITH_ARG("--scan-serial|-S",
add_serial, NULL, NULL,
"Serial port to probe for BitForce device"),
"Serial port to probe for FPGA Mining device"),
#endif
OPT_WITH_ARG("--scan-time|-s",
set_int_0_to_9999, opt_show_intval, &opt_scantime,
@ -960,6 +960,9 @@ static char *opt_verusage_and_exit(const char *extra) @@ -960,6 +960,9 @@ static char *opt_verusage_and_exit(const char *extra)
#endif
#ifdef USE_BITFORCE
"bitforce "
#endif
#ifdef USE_ICARUS
"icarus "
#endif
"mining support.\n"
, packagename);
@ -4157,6 +4160,10 @@ struct device_api cpu_api = { @@ -4157,6 +4160,10 @@ struct device_api cpu_api = {
extern struct device_api bitforce_api;
#endif
#ifdef USE_ICARUS
extern struct device_api icarus_api;
#endif
static int cgminer_id_count = 0;
@ -4311,6 +4318,10 @@ int main (int argc, char *argv[]) @@ -4311,6 +4318,10 @@ int main (int argc, char *argv[])
bitforce_api.api_detect();
#endif
#ifdef USE_ICARUS
icarus_api.api_detect();
#endif
#ifdef WANT_CPUMINE
cpu_api.api_detect();
#endif

21
configure.ac

@ -196,6 +196,17 @@ if test "x$bitforce" = xyes; then @@ -196,6 +196,17 @@ if test "x$bitforce" = xyes; then
fi
AM_CONDITIONAL([HAS_BITFORCE], [test x$bitforce = xyes])
icarus="no"
AC_ARG_ENABLE([icarus],
[AC_HELP_STRING([--enable-icarus],[Compile support for Icarus (default disabled)])],
[icarus=$enableval]
)
if test "x$icarus" = xyes; then
AC_DEFINE([USE_ICARUS], [1], [Defined to 1 if Icarus support is wanted])
fi
AM_CONDITIONAL([HAS_ICARUS], [test x$icarus = xyes])
AC_SEARCH_LIBS(addstr, ncurses pdcurses, ,
AC_MSG_ERROR([Could not find curses library - please install libncurses-dev or pdcurses-dev]))
@ -338,13 +349,13 @@ if test "x$opencl" != xno; then @@ -338,13 +349,13 @@ if test "x$opencl" != xno; then
echo " OpenCL...............: FOUND. GPU mining support enabled"
else
echo " OpenCL...............: NOT FOUND. GPU mining support DISABLED"
if test "x$cpumining$bitforce" = xnono; then
if test "x$cpumining$bitforce$icarus" = xnonono; then
AC_MSG_ERROR([No mining configured in])
fi
fi
else
echo " OpenCL...............: Detection overrided. GPU mining support DISABLED"
if test "x$cpumining$bitforce" = xnono; then
if test "x$cpumining$bitforce$icarus" = xnonono; then
AC_MSG_ERROR([No mining configured in])
fi
fi
@ -366,6 +377,12 @@ else @@ -366,6 +377,12 @@ else
echo " BitForce.FPGAs.......: Disabled"
fi
if test "x$icarus" = xyes; then
echo " Icarus.FPGAs.........: Enabled"
else
echo " Icarus.FPGAs.........: Disabled"
fi
echo
if test "x$cpumining" = xyes; then
echo " CPU Mining...........: Enabled"

333
icarus.c

@ -0,0 +1,333 @@ @@ -0,0 +1,333 @@
/*
* Copyright 2012 Luke Dashjr
* Copyright 2012 Xiangfu <xiangfu@openmobilefree.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version. See COPYING for more details.
*/
/*
* Those code should be works fine with V2 and V3 bitstream of Icarus.
* Operation:
* No detection implement.
* Input: 64B = 32B midstate + 20B fill bytes + last 12 bytes of block head.
* Return: send back 32bits immediately when Icarus found a valid nonce.
* no query protocol implemented here, if no data send back in ~11.3
* seconds (full cover time on 32bit nonce range by 380MH/s speed)
* just send another work.
* Notice:
* 1. Icarus will start calculate when you push a work to them, even they
* are busy.
* 2. The 2 FPGAs on Icarus will distribute the job, one will calculate the
* 0 ~ 7FFFFFFF, another one will cover the 80000000 ~ FFFFFFFF.
* 3. It's possible for 2 FPGAs both find valid nonce in the meantime, the 2
* valid nonce will all be send back.
* 4. Icarus will stop work when: a valid nonce has been found or 32 bits
* nonce range is completely calculated.
*/
#include <limits.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#ifndef WIN32
#include <termios.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
#else
#include <windows.h>
#include <io.h>
#endif
#include "elist.h"
#include "miner.h"
#define ICARUS_READ_FAULT_COUNT (8)
static int icarus_read_count;
static int icarus_write_fault;
struct device_api icarus_api;
static void rev(unsigned char *s, size_t l)
{
size_t i, j;
unsigned char t;
for (i = 0, j = l - 1; i < j; i++, j--) {
t = s[i];
s[i] = s[j];
s[j] = t;
}
}
static int icarus_open(const char *devpath)
{
#ifndef WIN32
struct termios my_termios;
int serialfd = open(devpath, O_RDWR | O_CLOEXEC | O_NOCTTY);
if (serialfd == -1)
return -1;
tcgetattr(serialfd, &my_termios);
my_termios.c_cflag = B115200;
my_termios.c_cflag |= CS8;
my_termios.c_cflag |= CREAD;
my_termios.c_cflag |= CLOCAL;
my_termios.c_cflag &= ~(CSIZE | PARENB);
my_termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK |
ISTRIP | INLCR | IGNCR | ICRNL | IXON);
my_termios.c_oflag &= ~OPOST;
my_termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
my_termios.c_cc[VTIME] = 10; /* block 1 second */
my_termios.c_cc[VMIN] = 0;
tcsetattr(serialfd, TCSANOW, &my_termios);
tcflush(serialfd, TCOFLUSH);
tcflush(serialfd, TCIFLUSH);
return serialfd;
#else
HANDLE hSerial = CreateFile(devpath, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, 0, NULL);
if (unlikely(hSerial == INVALID_HANDLE_VALUE))
return -1;
/* TODO: Needs setup read block time. just like VTIME = 10 */
return _open_osfhandle((LONG)hSerial, 0);
#endif
}
static void icarus_gets(char *buf, size_t bufLen, int fd)
{
ssize_t ret = 0;
icarus_read_count = 0;
while (bufLen) {
ret = read(fd, buf, 1);
if (ret == 1) {
bufLen--;
buf++;
continue;
}
icarus_read_count++;
if (icarus_read_count == ICARUS_READ_FAULT_COUNT) {
applog(LOG_WARNING,
"Icarus Read: No data in %d seconds",
ICARUS_READ_FAULT_COUNT);
break;
}
}
}
static void icarus_write(int fd, const void *buf, size_t bufLen)
{
ssize_t ret;
ret = write(fd, buf, bufLen);
if (unlikely(ret != bufLen))
icarus_write_fault = 1;
}
#define icarus_close(fd) close(fd)
static bool icarus_detect_one(const char *devpath)
{
int fd;
const unsigned char golden_ob[] =
"2db907f9cb4eb938ded904f4832c4331"
"0380e3aeb54364057e7fec5157bfc533"
"00000000000000000000000080000000"
"00000000a58e091ac342724e7c3dc346";
const unsigned char golden_nonce[] = "063c5e01";
char ob_bin[64], nonce_bin[4];
char *nonce_hex;
if (total_devices == MAX_DEVICES)
return false;
fd = icarus_open(devpath);
if (unlikely(fd == -1)) {
applog(LOG_ERR, "Icarus Detect: Failed to open %s", devpath);
return false;
}
hex2bin(ob_bin, golden_ob, sizeof(ob_bin));
icarus_write(fd, ob_bin, sizeof(ob_bin));
memset(nonce_bin, 0, sizeof(nonce_bin));
icarus_gets(nonce_bin, sizeof(nonce_bin), fd);
icarus_close(fd);
nonce_hex = bin2hex(nonce_bin, sizeof(nonce_bin));
if (nonce_hex) {
if (strncmp(nonce_hex, golden_nonce, 8)) {
applog(LOG_ERR,
"Icarus Detect: "
"Test failed at %s : get %s, should: %s",
devpath, nonce_hex, golden_nonce);
free(nonce_hex);
return false;
}
free(nonce_hex);
} else
return false;
/* We have a real Icarus! */
struct cgpu_info *icarus;
icarus = calloc(1, sizeof(struct cgpu_info));
icarus->api = &icarus_api;
icarus->device_id = total_devices;
icarus->device_path = strdup(devpath);
icarus->threads = 1;
devices[total_devices++] = icarus;
icarus_write_fault = 0;
return true;
}
static void icarus_detect()
{
struct string_elist *iter, *tmp;
list_for_each_entry_safe(iter, tmp, &scan_devices, list) {
if (icarus_detect_one(iter->string))
string_elist_del(iter);
}
}
static bool icarus_prepare(struct thr_info *thr)
{
struct cgpu_info *icarus = thr->cgpu;
struct timeval now;
int fd = icarus_open(icarus->device_path);
if (unlikely(-1 == fd)) {
applog(LOG_ERR, "Failed to open Icarus on %s",
icarus->device_path);
return false;
}
icarus->device_fd = fd;
applog(LOG_INFO, "Opened Icarus on %s", icarus->device_path);
gettimeofday(&now, NULL);
get_datestamp(icarus->init, &now);
return true;
}
static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
uint64_t max_nonce)
{
struct cgpu_info *icarus;
int fd;
unsigned char ob_bin[64], nonce_bin[4];
unsigned char *ob_hex, *nonce_hex;
uint32_t nonce;
uint32_t hash_count;
time_t t;
icarus = thr->cgpu;
fd = icarus->device_fd;
memset(ob_bin, 0, sizeof(ob_bin));
memcpy(ob_bin, work->midstate, 32);
memcpy(ob_bin + 52, work->data + 64, 12);
rev(ob_bin, 32);
rev(ob_bin + 52, 12);
#ifndef WIN32
tcflush(fd, TCOFLUSH);
#endif
icarus_write(fd, ob_bin, sizeof(ob_bin));
if (icarus_write_fault)
return 0; /* This should never happen */
ob_hex = bin2hex(ob_bin, sizeof(ob_bin));
if (ob_hex) {
t = time(NULL);
applog(LOG_DEBUG, "Icarus send : %s", ob_hex);
free(ob_hex);
}
/* Icarus will return 8 bytes nonces or nothing */
memset(nonce_bin, 0, sizeof(nonce_bin));
icarus_gets(nonce_bin, sizeof(nonce_bin), fd);
nonce_hex = bin2hex(nonce_bin, sizeof(nonce_bin));
if (nonce_hex) {
t = time(NULL) - t;
applog(LOG_DEBUG, "Icarus return (elapse %d seconds): %s",
t, nonce_hex);
free(nonce_hex);
}
memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
if (nonce == 0 && icarus_read_count == ICARUS_READ_FAULT_COUNT)
return 0xffffffff;
#ifndef __BIG_ENDIAN__
nonce = swab32(nonce);
#endif
work->blk.nonce = 0xffffffff;
submit_nonce(thr, work, nonce);
hash_count = (nonce & 0x7fffffff);
if (hash_count == 0)
hash_count = 2;
else {
if (hash_count++ == 0x7fffffff)
hash_count = 0xffffffff;
else
hash_count <<= 1;
}
return hash_count;
}
static void icarus_shutdown(struct thr_info *thr)
{
struct cgpu_info *icarus;
int fd;
if (thr->cgpu) {
icarus = thr->cgpu;
if (icarus->device_path)
free(icarus->device_path);
close(icarus->device_fd);
devices[icarus->device_id] = NULL;
free(icarus);
thr->cgpu = NULL;
}
}
struct device_api icarus_api = {
.name = "Icarus",
.api_detect = icarus_detect,
.thread_prepare = icarus_prepare,
.scanhash = icarus_scanhash,
.thread_shutdown = icarus_shutdown,
};
Loading…
Cancel
Save