Browse Source

Merge pull request #123 from xiangfu/icarus

Add Icarus Support to Cgminer
nfactor-troky
Con Kolivas 13 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
cgminer_SOURCES += bitforce.c cgminer_SOURCES += bitforce.c
endif endif
if HAS_ICARUS
cgminer_SOURCES += icarus.c
endif

21
README

@ -50,6 +50,7 @@ CGMiner specific configuration options:
--disable-opencl Override detection and disable building with opencl --disable-opencl Override detection and disable building with opencl
--disable-adl Override detection and disable building with adl --disable-adl Override detection and disable building with adl
--enable-bitforce Compile support for BitForce FPGAs(default disabled) --enable-bitforce Compile support for BitForce FPGAs(default disabled)
--enable-icarus Compile support for Icarus Board(default disabled)
Basic *nix build instructions: Basic *nix build instructions:
To build with GPU mining support: To build with GPU mining support:
@ -196,9 +197,9 @@ GPU only options:
--ndevs|-n Enumerate number of detected GPUs and exit --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: CPU only options:
@ -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 (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: Each column is as follows:
A 5 second exponentially decaying average hash rate 5s: A 5 second exponentially decaying average hash rate
An all time average hash rate avg: An all time average hash rate
The number of requested (Queued) work items from the pools Q: The number of requested (Queued) work items from the pools
The number of Accepted shares A: The number of Accepted shares
The number of Rejected shares R: The number of Rejected shares
The number of HardWare errors HW: The number of HardWare errors
The Efficiency defined as number of shares returned / work item E: The Efficiency defined as number of shares returned / work item
The Utility defined as the number of shares / minute 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 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)
return set_int_range(arg, i, 1, 10); return set_int_range(arg, i, 1, 10);
} }
#ifdef USE_BITFORCE #if defined(USE_BITFORCE) || defined(USE_ICARUS)
static char *add_serial(char *arg) static char *add_serial(char *arg)
{ {
string_elist_add(arg, &scan_devices); string_elist_add(arg, &scan_devices);
@ -661,7 +661,7 @@ static struct opt_table opt_config_table[] = {
OPT_WITHOUT_ARG("--disable-gpu|-G", OPT_WITHOUT_ARG("--disable-gpu|-G",
opt_set_bool, &opt_nogpu, opt_set_bool, &opt_nogpu,
"Disable GPU mining even if suitable devices exist"), "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_WITHOUT_ARG("--enable-cpu|-C",
opt_set_bool, &opt_usecpu, opt_set_bool, &opt_usecpu,
"Enable CPU mining with other mining (default: no CPU mining if other devices exist)"), "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[] = {
OPT_WITHOUT_ARG("--round-robin", OPT_WITHOUT_ARG("--round-robin",
set_rr, &pool_strategy, set_rr, &pool_strategy,
"Change multipool strategy from failover to round robin on failure"), "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", OPT_WITH_ARG("--scan-serial|-S",
add_serial, NULL, NULL, add_serial, NULL, NULL,
"Serial port to probe for BitForce device"), "Serial port to probe for FPGA Mining device"),
#endif #endif
OPT_WITH_ARG("--scan-time|-s", OPT_WITH_ARG("--scan-time|-s",
set_int_0_to_9999, opt_show_intval, &opt_scantime, set_int_0_to_9999, opt_show_intval, &opt_scantime,
@ -960,6 +960,9 @@ static char *opt_verusage_and_exit(const char *extra)
#endif #endif
#ifdef USE_BITFORCE #ifdef USE_BITFORCE
"bitforce " "bitforce "
#endif
#ifdef USE_ICARUS
"icarus "
#endif #endif
"mining support.\n" "mining support.\n"
, packagename); , packagename);
@ -4157,6 +4160,10 @@ struct device_api cpu_api = {
extern struct device_api bitforce_api; extern struct device_api bitforce_api;
#endif #endif
#ifdef USE_ICARUS
extern struct device_api icarus_api;
#endif
static int cgminer_id_count = 0; static int cgminer_id_count = 0;
@ -4311,6 +4318,10 @@ int main (int argc, char *argv[])
bitforce_api.api_detect(); bitforce_api.api_detect();
#endif #endif
#ifdef USE_ICARUS
icarus_api.api_detect();
#endif
#ifdef WANT_CPUMINE #ifdef WANT_CPUMINE
cpu_api.api_detect(); cpu_api.api_detect();
#endif #endif

21
configure.ac

@ -196,6 +196,17 @@ if test "x$bitforce" = xyes; then
fi fi
AM_CONDITIONAL([HAS_BITFORCE], [test x$bitforce = xyes]) 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_SEARCH_LIBS(addstr, ncurses pdcurses, ,
AC_MSG_ERROR([Could not find curses library - please install libncurses-dev or pdcurses-dev])) 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
echo " OpenCL...............: FOUND. GPU mining support enabled" echo " OpenCL...............: FOUND. GPU mining support enabled"
else else
echo " OpenCL...............: NOT FOUND. GPU mining support DISABLED" 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]) AC_MSG_ERROR([No mining configured in])
fi fi
fi fi
else else
echo " OpenCL...............: Detection overrided. GPU mining support DISABLED" 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]) AC_MSG_ERROR([No mining configured in])
fi fi
fi fi
@ -366,6 +377,12 @@ else
echo " BitForce.FPGAs.......: Disabled" echo " BitForce.FPGAs.......: Disabled"
fi fi
if test "x$icarus" = xyes; then
echo " Icarus.FPGAs.........: Enabled"
else
echo " Icarus.FPGAs.........: Disabled"
fi
echo echo
if test "x$cpumining" = xyes; then if test "x$cpumining" = xyes; then
echo " CPU Mining...........: Enabled" echo " CPU Mining...........: Enabled"

333
icarus.c

@ -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