#include #include "miner.h" #include "bf16-bitfury16.h" #include "bf16-communication.h" #include "bf16-ctrldevice.h" #include "math.h" #include "sha2.h" #include "driver-bitfury16.h" //#define FLIP_BITS bf_cmd_description_t cmd_description[CHIP_CMD_NUM] = { { .cmd_code = CHIP_CMD_TASK_STATUS, .cmd_description = "CHIP_CMD_TASK_STATUS" }, { .cmd_code = CHIP_CMD_TASK_WRITE, .cmd_description = "CHIP_CMD_TASK_WRITE" }, { .cmd_code = CHIP_CMD_TASK_SWITCH, .cmd_description = "CHIP_CMD_TASK_SWITCH" }, { .cmd_code = CHIP_CMD_READ_NONCE, .cmd_description = "CHIP_CMD_READ_NONCE" }, { .cmd_code = CHIP_CMD_SET_CLOCK, .cmd_description = "CHIP_CMD_SET_CLOCK" }, { .cmd_code = CHIP_CMD_TOGGLE, .cmd_description = "CHIP_CMD_TOGGLE" }, { .cmd_code = CHIP_CMD_SET_MASK, .cmd_description = "CHIP_CMD_SET_MASK" }, { .cmd_code = CHIP_CMD_CREATE_CHANNEL, .cmd_description = "CHIP_CMD_CREATE_CHANNEL" } }; char* get_cmd_description(bf_cmd_code_t cmd_code) { uint8_t i; for (i = 0; i < CHIP_CMD_NUM; i++) if (cmd_description[i].cmd_code == cmd_code) return cmd_description[i].cmd_description; return NULL; } static void shift_bits(uint8_t* data, uint8_t size, uint8_t nbits) { uint8_t i; uint8_t bytes = nbits / 8; uint8_t bits = nbits % 8; for (i = 0; i < size; i++) { data[i] = (data[i + bytes] << bits); uint8_t minor = (data[i + bytes + 1] >> (8 - bits)); data[i] |= minor; } } static uint8_t extra_bytes(uint8_t depth) { return (depth * 3) / 8 + 1; } static uint8_t analyze_rx_data(bf_command_t* command, bf_cmd_status_t* cmd_status, uint32_t* nonces) { uint8_t i; uint8_t res = 0; if (command->cmd_code & CHIP_CMD_READ_NONCE) { shift_bits(command->rx, 49 + 2 + extra_bytes(command->depth), command->depth * 3); command->status = command->rx[0]; cmd_status->status = command->rx[0]; command->checksum = command->rx[1]; cmd_status->checksum_expected = command->checksum; if (nonces == NULL) return 1; uint32_t nonce = 0x00000000; /* fill nonces buffer */ for (i = 0; i <= 48; i++) { if ((i % 4 == 0) && (i != 0)) { if ((nonce & 0x0fffffff) != 0x0fffffff) nonce ^= 0xaaaaaaaa; nonces[i/4 - 1] = nonce; if (i == 48) break; nonce = 0x00000000; } nonce |= (command->rx[i + 2] << 8*(4 - (i%4) - 1)); } #if 0 char data[128]; memset(data, 0, sizeof(data)); for (i = 0; i < 49 + 2 + extra_bytes(command->depth); i++) sprintf(data, "%s%02x", data, command->rx[i]); applog(LOG_DEBUG, "BF16: RX <- [%s]", data); #endif for (i = 0; i < 48; i ++) command->nonce_checksum += command->rx[i + 2]; command->nonce_checksum += command->rx[1]; cmd_status->nonce_checksum_expected = command->nonce_checksum; if (command->checksum != command->rx[1]) { command->checksum_error = true; cmd_status->checksum_error = true; cmd_status->checksum_received = command->rx[50]; res = 1; #if 0 applog(LOG_ERR, "Checksum mismatch: received [%02x] expected [%02x]", command->rx[1], 0x04); #endif } else { command->checksum_error = false; cmd_status->checksum_error = false; } if ((command->nonce_checksum != command->rx[50]) && (command->nonce_checksum != command->rx[50] + 1)) { command->nonce_checksum_error = true; cmd_status->nonce_checksum_error = true; cmd_status->nonce_checksum_received = command->rx[50]; res += 2; #if 0 applog(LOG_ERR, "Nonce checksum mismatch: received [%02x] expected [%02x]", command->rx[50], checksum); #endif } else { command->nonce_checksum_error = false; cmd_status->nonce_checksum_error = false; } } else { shift_bits(command->rx, 2 + extra_bytes(command->depth), command->depth * 3); if (opt_bf16_test_chip != NULL) { char data[16]; memset(data, 0, sizeof(data)); for (i = 0; i < 2 + extra_bytes(command->depth); i++) sprintf(data, "%s%02x", data, command->rx[i]); applog(LOG_NOTICE, "BF16: RX <- [%s]", data); } command->status = command->rx[0]; cmd_status->status = command->rx[0]; uint8_t cmd_checksum = command->rx[1]; cmd_status->checksum_expected = command->checksum; #if 0 applog(LOG_DEBUG, "Command checksum: [%02x]", cmd_checksum); applog(LOG_DEBUG, "Command status: [%02x]", command->status); #endif if ((command->checksum != cmd_checksum) && (command->checksum != cmd_checksum + 1)) { command->checksum_error = true; cmd_status->checksum_error = true; cmd_status->checksum_received = cmd_checksum; res = 1; if (opt_bf16_test_chip != NULL) { applog(LOG_ERR, "BF16: checksum mismatch: received [%02x] expected [%02x]", cmd_checksum, command->checksum); } } else { command->checksum_error = false; cmd_status->checksum_error = false; } } return res; } /* SPI BTC250 primitives */ uint8_t create_channel(spi_channel_id_t spi_channel, uint8_t* channel_path, uint8_t channel_length) { int res = 0; uint8_t* channel_path_buff = cgcalloc(channel_length, sizeof(uint8_t)); cg_memcpy(channel_path_buff, channel_path, channel_length); res = device_spi_transfer(spi_channel, channel_path_buff, channel_length); free(channel_path_buff); return res; } uint8_t destroy_channel(spi_channel_id_t spi_channel, uint8_t depth) { bf_command_t chip_command; bf_chip_address_t chip_address = { 0x00, 0x00, 0x0f }; /* send command to 0x0f address */ spi_command_init(&chip_command, depth, chip_address, CHIP_CMD_TASK_SWITCH, 0, NULL); return spi_command_exec(spi_channel, &chip_command, NULL); } /* SPI BTC16 primitives */ void spi_emit_reset(spi_channel_id_t spi_channel) { device_ctrl_transfer(spi_channel, 1, F_RST); uint8_t data[2] = { 0x00, 0x00 }; device_spi_transfer(spi_channel, data, sizeof(data)); device_ctrl_transfer(spi_channel, 0, F_RST); } uint8_t send_toggle(spi_channel_id_t spi_channel, uint8_t depth, bf_chip_address_t chip_address) { bf_command_t chip_command; uint8_t toggle[4] = { 0xa5, 0x00, 0x00, 0x02 }; spi_command_init(&chip_command, depth, chip_address, CHIP_CMD_TOGGLE, 3, toggle); return spi_command_exec(spi_channel, &chip_command, NULL); } uint8_t set_clock(spi_channel_id_t spi_channel, uint8_t depth, bf_chip_address_t chip_address, uint8_t clock) { bf_command_t chip_command; uint8_t clock_buf[4]; memset(clock_buf, 0, 4); gen_clock_data(clock, 1, clock_buf); spi_command_init(&chip_command, depth, chip_address, CHIP_CMD_SET_CLOCK, 3, clock_buf); return spi_command_exec(spi_channel, &chip_command, NULL); } /* cmd buffer primitives */ int8_t cmd_buffer_init(bf_cmd_buffer_t* cmd_buffer) { if (cmd_buffer == NULL) return -1; cmd_buffer->cmd_list = cgmalloc(sizeof(bf_list_t)); cmd_buffer->cmd_list->head = NULL; cmd_buffer->cmd_list->tail = NULL; cmd_buffer->cmd_list->count = 0; cmd_buffer->tx_buffer = cgcalloc(CMD_BUFFER_LEN, sizeof(uint8_t)); cmd_buffer->rx_buffer = cgcalloc(CMD_BUFFER_LEN, sizeof(uint8_t)); memset(cmd_buffer->tx_buffer, 0, CMD_BUFFER_LEN); memset(cmd_buffer->rx_buffer, 0, CMD_BUFFER_LEN); cmd_buffer->free_bytes = CMD_BUFFER_LEN; cmd_buffer->tx_offset = 0; cmd_buffer->rx_offset = 0; cmd_buffer->status = EMPTY; return 0; } int8_t cmd_buffer_deinit(bf_cmd_buffer_t* cmd_buffer) { if (cmd_buffer == NULL) return -1; /* free cmd buffer */ while (cmd_buffer->cmd_list->head != NULL) { bf_data_t* cdata = cmd_buffer->cmd_list->head; LIST_POP_HEAD(cmd_buffer->cmd_list); free(cdata->data); free(cdata); } free(cmd_buffer->cmd_list); /* free RX/TX buffer */ free(cmd_buffer->tx_buffer); free(cmd_buffer->rx_buffer); cmd_buffer->free_bytes = CMD_BUFFER_LEN; cmd_buffer->tx_offset = 0; cmd_buffer->rx_offset = 0; cmd_buffer->status = EMPTY; return 0; } int8_t cmd_buffer_clear(bf_cmd_buffer_t* cmd_buffer) { if (cmd_buffer == NULL) return -1; /* release cmd buffer data memory */ while (cmd_buffer->cmd_list->head != NULL) { bf_data_t* cdata = cmd_buffer->cmd_list->head; LIST_POP_HEAD(cmd_buffer->cmd_list); free(cdata->data); free(cdata); } cmd_buffer->cmd_list->count = 0; /* clear RX/TX buffer */ memset(cmd_buffer->tx_buffer, 0, CMD_BUFFER_LEN); memset(cmd_buffer->rx_buffer, 0, CMD_BUFFER_LEN); cmd_buffer->free_bytes = CMD_BUFFER_LEN; cmd_buffer->tx_offset = 0; cmd_buffer->rx_offset = 0; cmd_buffer->status = EMPTY; return 0; } int8_t cmd_buffer_push(bf_cmd_buffer_t* cmd_buffer, const uint8_t depth, const bf_chip_address_t chip_address, const bf_chip_address_t src_address, const bf_works_t work, const uint32_t id, const bf_cmd_code_t cmd_code, const uint8_t data_length, const uint8_t* tx) { uint8_t res = 0; if (cmd_buffer == NULL) return -1; if (cmd_buffer->status == EXECUTED) return -2; bf_command_t command; memset(&command, 0, sizeof(bf_command_t)); uint8_t buff[192]; memset(buff, 0, sizeof(buff)); if (cmd_code != CHIP_CMD_CREATE_CHANNEL) { res = spi_command_init(&command, depth, chip_address, cmd_code, data_length, tx); if (res != 0) return res; } /* init structure */ bf_data_t* cdata = cgmalloc(sizeof(bf_data_t)); cdata->data = cgmalloc(sizeof(bf_cmd_t)); cdata->next = NULL; cdata->prev = NULL; cg_memcpy(&CMD(cdata)->chip_address, &chip_address, sizeof(bf_chip_address_t)); cg_memcpy(&CMD(cdata)->src_address, &src_address, sizeof(bf_chip_address_t)); cg_memcpy(&CMD(cdata)->work, &work, sizeof(bf_works_t)); CMD(cdata)->id = id; CMD(cdata)->depth = command.depth; CMD(cdata)->checksum = command.checksum; CMD(cdata)->cmd_code = cmd_code; if (CMD(cdata)->cmd_code & CHIP_CMD_READ_NONCE) CMD(cdata)->data_length = command.data_length + 49 + 2 + extra_bytes(command.depth); else if (CMD(cdata)->cmd_code == CHIP_CMD_CREATE_CHANNEL) CMD(cdata)->data_length = data_length; else CMD(cdata)->data_length = command.data_length + 2 + extra_bytes(command.depth); if (cmd_buffer->free_bytes < CMD(cdata)->data_length) { /* not enough TX/RX buffer space available */ free(cdata->data); free(cdata); return -3; } /* init send buffer */ if (cmd_code != CHIP_CMD_CREATE_CHANNEL) { cg_memcpy(buff, command.tx, command.data_length); cg_memcpy(cmd_buffer->tx_buffer + cmd_buffer->tx_offset, buff, CMD(cdata)->data_length); } else cg_memcpy(cmd_buffer->tx_buffer + cmd_buffer->tx_offset, tx, CMD(cdata)->data_length); #if 0 uint16_t i; char data[384]; memset(data, 0, sizeof(data)); for (i = 0; i < command.data_length; i++) sprintf(data, "%s%02x", data, command.tx[i]); applog(LOG_DEBUG, "BF16: TX -> [%s]", data); #endif cmd_buffer->tx_offset += CMD(cdata)->data_length; cmd_buffer->free_bytes -= CMD(cdata)->data_length; /* add cmd to buffer */ LIST_PUSH_TAIL(cmd_buffer->cmd_list, cdata); cmd_buffer->cmd_list->count++; return 0; } int8_t cmd_buffer_push_send_toggle(bf_cmd_buffer_t* cmd_buffer, const uint8_t depth, const bf_chip_address_t chip_address) { bf_works_t work; uint8_t toggle[4] = { 0xa5, 0x00, 0x00, 0x02 }; return cmd_buffer_push(cmd_buffer, depth, chip_address, chip_address, work, 0, CHIP_CMD_TOGGLE, 3, toggle); } int8_t cmd_buffer_push_set_clock(bf_cmd_buffer_t* cmd_buffer, const uint8_t depth, const bf_chip_address_t chip_address, uint8_t clock) { bf_works_t work; uint8_t clock_buf[4]; memset(clock_buf, 0, 4); gen_clock_data(clock, 1, clock_buf); return cmd_buffer_push(cmd_buffer, depth, chip_address, chip_address, work, 0, CHIP_CMD_SET_CLOCK, 3, clock_buf); } int8_t cmd_buffer_push_set_mask(bf_cmd_buffer_t* cmd_buffer, const uint8_t depth, const bf_chip_address_t chip_address, uint8_t mask) { uint8_t i; bf_works_t work; uint8_t noncemask[4]; for (i = 0; i < 4; i++) noncemask[i] = (mask >> (8*(4 - i - 1))) & 0xff; return cmd_buffer_push(cmd_buffer, depth, chip_address, chip_address, work, 0, CHIP_CMD_SET_MASK, 3, noncemask); } int8_t cmd_buffer_push_create_channel(bf_cmd_buffer_t* cmd_buffer, uint8_t* channel_path, uint8_t channel_length) { bf_works_t work; bf_chip_address_t chip_address = { 0x00, 0x00, 0x00 }; return cmd_buffer_push(cmd_buffer, 0, chip_address, chip_address, work, 0, CHIP_CMD_CREATE_CHANNEL, channel_length, channel_path); } int8_t cmd_buffer_push_destroy_channel(bf_cmd_buffer_t* cmd_buffer, const uint8_t depth) { bf_works_t work; bf_chip_address_t chip_address = { 0x00, 0x00, 0x0f }; return cmd_buffer_push(cmd_buffer, depth, chip_address, chip_address, work, 0, CHIP_CMD_TASK_SWITCH, 0, NULL); } bool match_nonce(uint32_t nonce, uint32_t mask, uint8_t nbits) { uint32_t fixed_mask = (uint32_t)(pow(2, nbits) - 1); return ((nonce & fixed_mask) == (mask & fixed_mask)); } uint8_t find_nonces(uint32_t* curr_nonces, uint32_t* prev_nonces, uint32_t* valid_nonces) { uint8_t i, j; uint8_t found = 0; uint8_t nonces = 0; uint8_t diff = 0; uint32_t found_nonces[12]; memset(found_nonces, 0, sizeof(found_nonces)); for (i = 0; i < 12; i++) { if (((curr_nonces[i] & 0x0fffffff) != 0x0fffffff) && (curr_nonces[i] != prev_nonces[i])) { found_nonces[found++] = curr_nonces[i]; } if (((curr_nonces[i] & 0x0fffffff) == 0x0fffffff) && (curr_nonces[i] != prev_nonces[i])) diff++; } for (i = 0; i < found; i++) { if (found_nonces[i] == 0x00000000) continue; for (j = i; j < found; j++) { if ((j != i) && (found_nonces[i] == found_nonces[j])) found_nonces[j] = 0x00000000; } valid_nonces[nonces++] = found_nonces[i]; } return nonces; } int8_t cmd_buffer_pop(bf_cmd_buffer_t* cmd_buffer, bf_cmd_status_t* cmd_status, uint32_t* nonces) { if (cmd_buffer == NULL) return -1; if (cmd_buffer->status != EXECUTED) return -2; if (cmd_buffer->cmd_list->head == NULL) return -3; uint8_t buff[192]; bf_command_t chip_command; memset(buff, 0, sizeof(buff)); memset(chip_command.rx, 0, sizeof(chip_command.rx)); /* extract command from list */ bf_data_t* cdata = cmd_buffer->cmd_list->head; chip_command.cmd_code = CMD(cdata)->cmd_code; chip_command.depth = CMD(cdata)->depth; chip_command.data_length = CMD(cdata)->data_length; chip_command.status = 0; chip_command.checksum = CMD(cdata)->checksum; chip_command.nonce_checksum = 0; chip_command.checksum_error = false; chip_command.nonce_checksum_error = false; /* extract chip return data */ cg_memcpy(buff, cmd_buffer->rx_buffer + cmd_buffer->rx_offset, CMD(cdata)->data_length); cmd_buffer->rx_offset += CMD(cdata)->data_length; if (CMD(cdata)->cmd_code & CHIP_CMD_READ_NONCE) { cg_memcpy(chip_command.rx, buff + CMD(cdata)->data_length - (49 + 2 + extra_bytes(chip_command.depth)), 49 + 2 + extra_bytes(chip_command.depth)); memset(nonces, 0, 12 * sizeof(uint32_t)); analyze_rx_data(&chip_command, cmd_status, nonces); } else if (CMD(cdata)->cmd_code == CHIP_CMD_CREATE_CHANNEL) { cg_memcpy(chip_command.rx, buff, CMD(cdata)->data_length); } else { cg_memcpy(chip_command.rx, buff + CMD(cdata)->data_length - (2 + extra_bytes(chip_command.depth)), 2 + extra_bytes(chip_command.depth)); analyze_rx_data(&chip_command, cmd_status, NULL); } /* prepare cmd_status */ cg_memcpy(&cmd_status->chip_address, &CMD(cdata)->chip_address, sizeof(bf_chip_address_t)); cg_memcpy(&cmd_status->src_address, &CMD(cdata)->src_address, sizeof(bf_chip_address_t)); cg_memcpy(&cmd_status->work, &CMD(cdata)->work, sizeof(bf_works_t)); cmd_status->id = CMD(cdata)->id; cmd_status->cmd_code = CMD(cdata)->cmd_code; /* push memory back to free cmd list */ LIST_POP_HEAD(cmd_buffer->cmd_list); cmd_buffer->cmd_list->count--; free(cdata->data); free(cdata); return 0; } int8_t cmd_buffer_exec(spi_channel_id_t spi_channel, bf_cmd_buffer_t* cmd_buffer) { if (cmd_buffer == NULL) return -1; if (cmd_buffer->status == TX_READY) { device_spi_txrx(spi_channel, cmd_buffer->tx_buffer, cmd_buffer->rx_buffer, cmd_buffer->tx_offset); cmd_buffer->status = EXECUTED; } else return -2; return 0; } /* BF16 command primitives */ uint8_t gen_clock_data(uint8_t clock, uint8_t prescaler, uint8_t data[4]) { uint8_t i; uint32_t data32 = 0x00000000; if (clock > 0x3f) return -1; if ((prescaler != 0) && (prescaler != 1)) return -1; uint32_t magic_const = 0x38; uint32_t prescaler1 = prescaler; uint32_t clock1 = clock; uint32_t prescaler2 = prescaler; uint32_t clock2 = clock; magic_const <<= 20; if (prescaler == 1) { prescaler1 <<= 19; prescaler2 <<= 12; } clock1 <<= 13; clock2 <<= 6; data32 = magic_const | prescaler1 | clock1 | prescaler2 | clock2; for (i = 0; i < 4; i++) data[i] = (data32 >> (8*(4 - i - 1))) & 0xff; return 0; } #ifdef FLIP_BITS static uint32_t flip_bits(uint32_t data, uint8_t nbits) { uint32_t ret = 0x00000000; uint8_t i; for (i = 0; i < nbits; i++) ret |= (((data >> i) & 0x1) << (nbits - (i + 1))); return ret; } #endif uint32_t gen_mask(uint32_t nonce, uint8_t nbits) { uint32_t mask = 0x00000000; uint32_t mask_code = (nbits << 16); /* highest 16 bits of nonce counter */ uint32_t nonce_code = (nonce & 0x0007ffff); #ifdef FLIP_BITS uint32_t nonce_cntr = flip_bits(nonce_code, 19); nonce_code = (flip_bits(nonce_cntr - 2, 19) ^ 0xaaaaaaaa); mask = (mask_code | (nonce_code & (uint32_t)(pow(2, nbits) - 1))); #else nonce_code = ((nonce_code ^ 0xaaaaaaaa) & (uint32_t)(pow(2, nbits) - 1)); mask = (mask_code | nonce_code); #endif return mask; } void ms3steps16(uint32_t* p, uint32_t* w, uint32_t* task) { uint32_t a, b, c, d, e, f, g, h, new_e, new_a; uint8_t i; a = p[0]; b = p[1]; c = p[2]; d = p[3]; e = p[4]; f = p[5]; g = p[6]; h = p[7]; for (i = 0; i < 3; i++) { new_e = w[i] + sha256_k[i] + h + CH(e,f,g) + SHA256_F2(e) + d; new_a = w[i] + sha256_k[i] + h + CH(e,f,g) + SHA256_F2(e) + SHA256_F1(a) + MAJ(a,b,c); d = c; c = b; b = a; a = new_a; h = g; g = f; f = e; e = new_e; } task[18] = ntohl(a ^ 0xaaaaaaaa); task[17] = ntohl(b ^ 0xaaaaaaaa); task[16] = ntohl(c ^ 0xaaaaaaaa); task[15] = ntohl(d ^ 0xaaaaaaaa); task[11] = ntohl(e ^ 0xaaaaaaaa); task[10] = ntohl(f ^ 0xaaaaaaaa); task[9] = ntohl(g ^ 0xaaaaaaaa); task[8] = ntohl(h ^ 0xaaaaaaaa); } uint8_t gen_task_data(uint32_t* midstate, uint32_t merkle, uint32_t ntime, uint32_t nbits, uint32_t mask, uint8_t* task) { uint8_t i; uint32_t tmp; uint32_t w[3]; w[0] = merkle; w[1] = ntime; w[2] = nbits; for (i = 0; i < 8; i++) { tmp = midstate[i]; tmp ^= 0xaaaaaaaa; tmp = ntohl(tmp); cg_memcpy(task + i*4, &tmp, sizeof(tmp)); } ms3steps16(midstate, w, (uint32_t*)task); for (i = 0; i < 3; i++) { tmp = w[i]; tmp ^= 0xaaaaaaaa; tmp = ntohl(tmp); cg_memcpy(task + (12 + i)*4, &tmp, sizeof(tmp)); } mask = ntohl(mask); cg_memcpy(task + 19*4, &mask, sizeof(mask)); return 0; } uint8_t spi_command_init(bf_command_t* command, const uint8_t depth, const bf_chip_address_t chip_address, const bf_cmd_code_t cmd_code, const uint8_t data_length, const uint8_t* tx) { uint8_t i; memset(command->tx, 0, sizeof(command->tx)); memset(command->rx, 0, sizeof(command->rx)); command->tx[0] = 0x01; command->data_length = 1; if ((chip_address.chip_id > 10) && (chip_address.chip_id != 0x0f)) return 1; else { cg_memcpy(&command->chip_address, &chip_address, sizeof(bf_chip_address_t)); command->tx[1] = (command->chip_address.chip_id << 4); command->data_length++; } command->depth = depth; command->cmd_code = cmd_code; command->tx[2] = command->cmd_code; command->data_length++; if (data_length <= 79) { command->tx[3] = data_length; command->data_length++; } else return 1; /* fill TX data */ if (data_length == 0) { command->tx[4] = 0x00; command->data_length++; } else if (tx != NULL) { cg_memcpy(command->tx + 4, tx, data_length + 1); command->data_length += (data_length + 1); } else return 1; /* calculate checksum */ command->checksum = 0; command->nonce_checksum = 0; for (i = 2; i < command->data_length; i++) command->checksum += command->tx[i]; command->checksum_error = false; command->nonce_checksum_error = false; return 0; } uint8_t spi_command_exec(spi_channel_id_t spi_channel, bf_command_t* command, uint32_t* nonces) { uint8_t buff[192]; uint8_t res = 0; bf_cmd_status_t cmd_status; if (command->cmd_code & CHIP_CMD_READ_NONCE) { memset(buff, 0x00, command->data_length + 49 + 2 + extra_bytes(command->depth)); cg_memcpy(buff, command->tx, command->data_length); device_spi_transfer(spi_channel, buff, command->data_length + 49 + 2 + extra_bytes(command->depth)); cg_memcpy(command->rx, buff + command->data_length, 49 + 2 + extra_bytes(command->depth)); #if 0 uint16_t i; char data[256]; memset(data, 0, sizeof(data)); for (i = 0; i < command->data_length; i++) sprintf(data, "%s%02x", data, command->tx[i]); applog(LOG_DEBUG, "BF16: TX -> [%s]", data); #endif return analyze_rx_data(command, &cmd_status, nonces); } else { memset(buff, 0x00, command->data_length + 2 + extra_bytes(command->depth)); cg_memcpy(buff, command->tx, command->data_length); device_spi_transfer(spi_channel, buff, command->data_length + 2 + extra_bytes(command->depth)); cg_memcpy(command->rx, buff + command->data_length, 2 + extra_bytes(command->depth)); if (opt_bf16_test_chip != NULL) { uint16_t i; char data[256]; memset(data, 0, sizeof(data)); for (i = 0; i < command->data_length; i++) sprintf(data, "%s%02x", data, command->tx[i]); applog(LOG_NOTICE, "BF16: TX -> [%s]", data); } return analyze_rx_data(command, &cmd_status, nonces); } return res; } /* dynamic work list primitives */ bf_list_t* workd_list_init(void) { bf_list_t* list = cgmalloc(sizeof(bf_list_t)); list->head = NULL; list->tail = NULL; list->count = 0; pthread_mutex_init(&list->lock, NULL); return list; } int8_t workd_list_deinit(bf_list_t* list, struct cgpu_info *bitfury) { if (list == NULL) return -1; /* free work list */ L_LOCK(list); while (list->head != NULL) { bf_data_t* wdata = list->head; LIST_POP_HEAD(list); if (WORKD(wdata)->rolled) free_work(WORKD(wdata)->work); else work_completed(bitfury, WORKD(wdata)->work); free(wdata); } L_UNLOCK(list); pthread_mutex_destroy(&list->lock); list->count = 0; free(list); return 0; } int8_t workd_list_push(bf_list_t* list, bf_workd_t* work) { if ((list == NULL) || (work == NULL)) return -1; bf_data_t* wdata = cgmalloc(sizeof(bf_data_t)); wdata->data = work; wdata->next = NULL; wdata->prev = NULL; LIST_PUSH_TAIL(list, wdata); list->count++; return 0; } int8_t workd_list_pop(bf_list_t* list, struct cgpu_info *bitfury) { if (list == NULL) return -1; bf_data_t* wdata = list->head; if (wdata != NULL) { LIST_POP_HEAD(list); if (WORKD(wdata)->rolled) free_work(WORKD(wdata)->work); else work_completed(bitfury, WORKD(wdata)->work); list->count--; free(wdata->data); free(wdata); } else return -1; return 0; } int8_t workd_list_remove(bf_list_t* list, bf_works_t* works) { if (list == NULL) return -1; bf_data_t* wdata = list->head; if (wdata != NULL) { LIST_POP_HEAD(list); cg_memcpy(&works->work, WORKD(wdata)->work, sizeof(struct work)); cg_memcpy(&works->payload, &WORKD(wdata)->payload, sizeof(bf_payload_t)); list->count--; free(wdata); } else return -1; return 0; } /* nonces list primitives */ bf_list_t* nonce_list_init(void) { bf_list_t* list = cgmalloc(sizeof(bf_list_t)); list->head = NULL; list->tail = NULL; list->count = 0; pthread_mutex_init(&list->lock, NULL); return list; } int8_t nonce_list_deinit(bf_list_t* list) { if (list == NULL) return -1; /* free nonce list */ L_LOCK(list); while (list->head != NULL) { bf_data_t* ndata = list->head; LIST_POP_HEAD(list); free(ndata->data); free(ndata); } L_UNLOCK(list); pthread_mutex_destroy(&list->lock); list->count = 0; free(list); return 0; } int8_t nonce_list_push(bf_list_t* list, uint32_t nonce) { if (list == NULL) return -1; /* find nonce duplicates */ bf_data_t* ndata = list->head; while (ndata != NULL) { if (NONCE(ndata)->nonce == nonce) return -1; ndata = ndata->next; } ndata = cgmalloc(sizeof(bf_data_t)); ndata->data = cgmalloc(sizeof(bf_nonce_t)); NONCE(ndata)->nonce = nonce; ndata->next = NULL; ndata->prev = NULL; LIST_PUSH_TAIL(list, ndata); list->count++; return 0; } uint32_t nonce_list_pop(bf_list_t* list) { uint32_t nonce = 0; bf_data_t* ndata = list->head; if (ndata != NULL) { nonce = NONCE(ndata)->nonce; LIST_POP_HEAD(list); list->count--; free(ndata->data); free(ndata); } else return -1; return nonce; } /* renoncework list primitives */ bf_list_t* renoncework_list_init(void) { bf_list_t* list = cgmalloc(sizeof(bf_list_t)); list->head = NULL; list->tail = NULL; list->count = 0; pthread_mutex_init(&list->lock, NULL); return list; } int8_t renoncework_list_deinit(bf_list_t* list) { if (list == NULL) return -1; /* free renoncework list */ L_LOCK(list); while (list->head != NULL) { bf_data_t* rnwdata = list->head; LIST_POP_HEAD(list); free(rnwdata->data); free(rnwdata); } L_UNLOCK(list); pthread_mutex_destroy(&list->lock); list->count = 0; free(list); return 0; } int8_t renoncework_list_push(bf_list_t* list, bf_chip_address_t src_address, uint32_t nonce) { if (list == NULL) return -1; bf_data_t* rnwdata = cgmalloc(sizeof(bf_data_t)); rnwdata->data = cgmalloc(sizeof(bf_renoncework_t)); rnwdata->next = NULL; rnwdata->prev = NULL; cg_memcpy(&RENONCEWORK(rnwdata)->src_address, &src_address, sizeof(bf_chip_address_t)); RENONCEWORK(rnwdata)->nonce = nonce; LIST_PUSH_TAIL(list, rnwdata); list->count++; return 0; } int8_t renoncework_list_pop(bf_list_t* list) { if (list == NULL) return -1; bf_data_t* rnwdata = list->head; if (rnwdata != NULL) { LIST_POP_HEAD(list); list->count--; free(rnwdata->data); free(rnwdata); } else return -1; return 0; } /* noncework list primitives */ bf_list_t* noncework_list_init(void) { bf_list_t* list = cgmalloc(sizeof(bf_list_t)); list->head = NULL; list->tail = NULL; list->count = 0; pthread_mutex_init(&list->lock, NULL); return list; } int8_t noncework_list_deinit(bf_list_t* list) { if (list == NULL) return -1; /* free noncework list */ L_LOCK(list); while (list->head != NULL) { bf_data_t* nwdata = list->head; LIST_POP_HEAD(list); free(nwdata->data); free(nwdata); } L_UNLOCK(list); pthread_mutex_destroy(&list->lock); list->count = 0; free(list); return 0; } int8_t noncework_list_push(bf_list_t* list, bf_chip_address_t chip_address, bf_chip_address_t src_address, bf_works_t cwork, bf_works_t owork, uint32_t nonce) { if (list == NULL) return -1; bf_data_t* nwdata = cgmalloc(sizeof(bf_data_t)); nwdata->data = cgmalloc(sizeof(bf_noncework_t)); nwdata->next = NULL; nwdata->prev = NULL; cg_memcpy(&NONCEWORK(nwdata)->cwork, &cwork, sizeof(bf_works_t)); cg_memcpy(&NONCEWORK(nwdata)->owork, &owork, sizeof(bf_works_t)); cg_memcpy(&NONCEWORK(nwdata)->chip_address, &chip_address, sizeof(bf_chip_address_t)); cg_memcpy(&NONCEWORK(nwdata)->src_address, &src_address, sizeof(bf_chip_address_t)); NONCEWORK(nwdata)->nonce = nonce; LIST_PUSH_TAIL(list, nwdata); list->count++; return 0; } int8_t noncework_list_pop(bf_list_t* list) { if (list == NULL) return -1; bf_data_t* nwdata = list->head; if (nwdata != NULL) { LIST_POP_HEAD(list); list->count--; free(nwdata->data); free(nwdata); } else return -1; return 0; } /* renonce list primitives */ bf_list_t* renonce_list_init(void) { bf_list_t* list = cgmalloc(sizeof(bf_list_t)); list->head = NULL; list->tail = NULL; list->count = 0; pthread_mutex_init(&list->lock, NULL); return list; } int8_t renonce_list_deinit(bf_list_t* list) { if (list == NULL) return -1; /* free renonce list */ L_LOCK(list); while (list->head != NULL) { bf_data_t* rdata = list->head; LIST_POP_HEAD(list); free(rdata->data); free(rdata); } L_UNLOCK(list); pthread_mutex_destroy(&list->lock); list->count = 0; free(list); return 0; } int8_t renonce_list_push(bf_list_t* list, uint32_t id, uint32_t nonce, bf_chip_address_t src_address, bf_works_t cwork, bf_works_t owork) { if (list == NULL) return -1; bf_data_t* rdata = cgmalloc(sizeof(bf_data_t)); rdata->data = cgmalloc(sizeof(bf_renonce_t)); rdata->next = NULL; rdata->prev = NULL; cg_memcpy(&RENONCE(rdata)->cwork, &cwork, sizeof(bf_works_t)); cg_memcpy(&RENONCE(rdata)->owork, &owork, sizeof(bf_works_t)); cg_memcpy(&RENONCE(rdata)->src_address, &src_address, sizeof(bf_chip_address_t)); RENONCE(rdata)->id = id; RENONCE(rdata)->nonce = nonce; RENONCE(rdata)->stage = RENONCE_STAGE0; RENONCE(rdata)->sent = false; RENONCE(rdata)->received = false; RENONCE(rdata)->match = false; LIST_PUSH_TAIL(list, rdata); list->count++; return 0; } int8_t renonce_list_pop(bf_list_t* list) { if (list == NULL) return -1; bf_data_t* rdata = list->head; if (rdata != NULL) { LIST_POP_HEAD(list); list->count--; free(rdata->data); free(rdata); } else return -1; return 0; } int8_t renonce_list_remove(bf_list_t* list, bf_data_t* rdata) { if (list == NULL) return -1; if (rdata != NULL) { LIST_REMOVE(list, rdata); list->count--; free(rdata->data); free(rdata); } else return -1; return 0; }