// // Author: Wolfgang Spraul // // This is free and unencumbered software released into the public domain. // For details see the UNLICENSE file at the root of the source tree. // #include "helper.h" void printf_help() { printf("\n" "bit2txt %s - convert FPGA bitstream to text\n" "Public domain work by Wolfgang Spraul\n" "\n" "bit2txt [options] \n" " --help print help message\n" " --version print version number\n" " --info add extra info to output (marked #I)\n" " bitstream to print on stdout\n" " (proposing extension .b2t)\n" "\n", PROGRAM_REVISION); } const char* bitstr(uint32_t value, int digits) { static char str[2 /* "0b" */ + 32 + 1 /* '\0' */]; int i; str[0] = '0'; str[1] = 'b'; for (i = 0; i < digits; i++) str[digits-i+1] = (value & (1< 15) indent = 15; for (i = 0; i < indent; i++) indent_str[i] = ' '; indent_str[i] = 0; i = 0; if (len <= 0x100) fmt_str[5] = '2'; else if (len <= 0x10000) fmt_str[5] = '4'; else fmt_str[5] = '6'; while (i < len) { printf(fmt_str, indent_str, i, data[i]); for (j = 1; (j < 8) && (i + j < len); j++) { if (i + j >= len) break; printf(" %02x", data[i+j]); } printf("\n"); i += 8; } } uint16_t __swab16(uint16_t x) { return (((x & 0x00ffU) << 8) | \ ((x & 0xff00U) >> 8)); \ } uint32_t __swab32(uint32_t x) { return (((x & 0x000000ffUL) << 24) | \ ((x & 0x0000ff00UL) << 8) | \ ((x & 0x00ff0000UL) >> 8) | \ ((x & 0xff000000UL) >> 24)); \ } int atom_found(char* bits, const cfg_atom_t* atom) { int i; for (i = 0; atom->must_0[i] != -1; i++) if (bits[atom->must_0[i]]) break; if (atom->must_0[i] != -1) return 0; for (i = 0; atom->must_1[i] != -1; i++) if (!bits[atom->must_1[i]]) break; return atom->must_1[i] == -1; } void atom_remove(char* bits, const cfg_atom_t* atom) { int i; for (i = 0; atom->must_1[i] != -1; i++) { if (bits[atom->must_1[i]]) bits[atom->must_1[i]] = 0; } } int printf_header(uint8_t* d, int len, int inpos, int* outdelta) { int i, str_len; *outdelta = 0; if (inpos + 13 > len) { fprintf(stderr, "#E File size %i below minimum of 13 bytes.\n", len); return -1; } printf("hex"); for (i = 0; i < 13; i++) printf(" %.02x", d[inpos+*outdelta+i]); printf("\n"); *outdelta += 13; // 4 strings 'a' - 'd', 16-bit length for (i = 'a'; i <= 'd'; i++) { if (inpos + *outdelta + 3 > len) { fprintf(stderr, "#E Unexpected EOF at %i.\n", len); return -1; } if (d[inpos + *outdelta] != i) { fprintf(stderr, "#E Expected string code '%c', got " "'%c'.\n", i, d[inpos + *outdelta]); return -1; } str_len = __be16_to_cpu(*(uint16_t*)&d[inpos + *outdelta + 1]); if (inpos + *outdelta + 3 + str_len > len) { fprintf(stderr, "#E Unexpected EOF at %i.\n", len); return -1; } if (d[inpos + *outdelta + 3 + str_len - 1]) { fprintf(stderr, "#E z-terminated string ends with %0xh" ".\n", d[inpos + *outdelta + 3 + str_len - 1]); return -1; } printf("header_str_%c %s\n", i, &d[inpos + *outdelta + 3]); *outdelta += 3 + str_len; } return 0; } // for an equivalent schematic, see lut.svg const int lut_base_vars[6] = {0 /* A1 */, 1, 0 /* A3 - not used */, 0, 0, 1 /* A6 */}; int bool_nextlen(const char* expr, int len) { int i, depth; if (!len) return -1; i = 0; if (expr[i] == '~') { i++; if (i >= len) return -1; } if (expr[i] == '(') { if (i+2 >= len) return -1; i++; for (depth = 1; depth && i < len; i++) { if (expr[i] == '(') depth++; else if (expr[i] == ')') depth--; } if (depth) return -1; return i; } if (expr[i] == 'A') { i++; if (i >= len) return -1; if (expr[i] < '1' || expr[i] > '6') return -1; return i+1; } return -1; } // + or, * and, @ xor, ~ not // var must point to array of A1..A6 variables int bool_eval(const char* expr, int len, const int* var) { int i, negate, result, oplen; oplen = bool_nextlen(expr, len); if (oplen < 1) goto fail; i = 0; negate = 0; if (expr[i] == '~') { negate = 1; if (++i >= oplen) goto fail; } if (expr[i] == '(') { if (i+2 >= oplen) goto fail; result = bool_eval(&expr[i+1], oplen-i-2, var); if (result == -1) goto fail; } else if (expr[i] == 'A') { if (i+1 >= oplen) goto fail; if (expr[i+1] < '1' || expr[i+1] > '6') goto fail; result = var[expr[i+1]-'1']; if (oplen != i+2) goto fail; } else goto fail; if (negate) result = !result; i = oplen; while (i < len) { if (expr[i] == '+') { if (result) return 1; return bool_eval(&expr[i+1], len-i-1, var); } if (expr[i] == '@') { int right_side = bool_eval(&expr[i+1], len-i-1, var); if (right_side == -1) goto fail; return (result && !right_side) || (!result && right_side); } if (expr[i] != '*') goto fail; if (!result) break; if (++i >= len) goto fail; oplen = bool_nextlen(&expr[i], len-i); if (oplen < 1) goto fail; result = bool_eval(&expr[i], oplen, var); if (result == -1) goto fail; i += oplen; } return result; fail: return -1; } int parse_boolexpr(const char* expr, uint64_t* lut) { int i, j, result, vars[6]; *lut = 0; for (i = 0; i < 64; i++) { memcpy(vars, lut_base_vars, sizeof(vars)); for (j = 0; j < 6; j++) { if (j != 2 && (i & (1< empty string if (mt_size[0] == 0) { str[0] = 0; return str; } // go through five rounds of merging for (round = 1; round < 7; round++) { for (i = 0; i < mt_size[round-1]; i++) { for (j = i+1; j < mt_size[round-1]; j++) { only_diff_bit = -1; for (k = 0; k < 6; k++) { if (mt[round-1][i].a[k] != mt[round-1][j].a[k]) { if (only_diff_bit != -1) { only_diff_bit = -1; break; } only_diff_bit = k; } } if (only_diff_bit != -1) { char new_term[6]; for (k = 0; k < 6; k++) new_term[k] = (k == only_diff_bit) ? 2 : mt[round-1][i].a[k]; for (k = 0; k < mt_size[round]; k++) { if (new_term[0] == mt[round][k].a[0] && new_term[1] == mt[round][k].a[1] && new_term[2] == mt[round][k].a[2] && new_term[3] == mt[round][k].a[3] && new_term[4] == mt[round][k].a[4] && new_term[5] == mt[round][k].a[5]) break; } if (k >= mt_size[round]) { mt[round][mt_size[round]].a[0] = new_term[0]; mt[round][mt_size[round]].a[1] = new_term[1]; mt[round][mt_size[round]].a[2] = new_term[2]; mt[round][mt_size[round]].a[3] = new_term[3]; mt[round][mt_size[round]].a[4] = new_term[4]; mt[round][mt_size[round]].a[5] = new_term[5]; mt_size[round]++; } mt[round-1][i].merged = 1; mt[round-1][j].merged = 1; } } } } // special case: 222222 -> (A6+~A6) for (i = 0; i < mt_size[6]; i++) { if (mt[6][i].a[0] == 2 && mt[6][i].a[1] == 2 && mt[6][i].a[2] == 2 && mt[6][i].a[3] == 2 && mt[6][i].a[4] == 2 && mt[6][i].a[5] == 2) { strcpy(str, "A6+~A6"); return str; } } str_end = 0; for (round = 0; round < 7; round++) { for (i = 0; i < mt_size[round]; i++) { if (!mt[round][i].merged) { if (str_end) str[str_end++] = '+'; first_op = 1; for (j = 0; j < 6; j++) { if (mt[round][i].a[j] != 2) { if (!first_op) str[str_end++] = '*'; if (!mt[round][i].a[j]) str[str_end++] = '~'; str[str_end++] = 'A'; str[str_end++] = '1' + j; first_op = 0; } } } } } str[str_end] = 0; // TODO: This could be further simplified, see Petrick's method. // XOR don't simplify well, try A2@A3 return str; } int printf_iob(uint8_t* d, int len, int inpos, int num_entries) { int i, j, num_printed; num_printed = 0; for (i = 0; i < num_entries; i++) { if (*(uint32_t*)&d[inpos+i*8] || *(uint32_t*)&d[inpos+i*8+4]) { printf("iob i%i", i); for (j = 0; j < 8; j++) printf(" %02X", d[inpos+i*8+j]); printf("\n"); num_printed++; } } return num_printed; } void printf_ramb16_data(uint8_t* bits, int inpos) { int nonzero_head, nonzero_tail; uint8_t init_byte; char init_str[65]; int i, j, k, bit_off; // check head and tail nonzero_head = 0; for (i = 0; i < 18; i++) { if (bits[inpos + i]) { nonzero_head = 1; break; } } nonzero_tail = 0; for (i = 0; i < 18; i++) { if (bits[inpos + 18*130-18 + i]) { nonzero_tail = 1; break; } } if (nonzero_head || nonzero_tail) printf(" #W Unexpected data.\n"); if (nonzero_head) { printf(" head"); for (i = 0; i < 18; i++) printf(" %02X", bits[inpos + i]); printf("\n"); } if (nonzero_tail) { printf(" tail"); for (i = 0; i < 18; i++) printf(" %02X", bits[inpos + 18*130-18 + i]); printf("\n"); } // 8 parity configs for (i = 0; i < 8; i++) { // 32 bytes per config for (j = 0; j < 32; j++) { init_byte = 0; for (k = 0; k < 8; k++) { bit_off = (i*(2048+256)) + (31-j)*4*18; bit_off += 1+(k/2)*18-(k&1); if (bits[inpos+18+bit_off/8] & (1<<(7-(bit_off%8)))) init_byte |= 1<= 0) if (d[l]) return 0; return 1; } int count_bits(uint8_t* d, int l) { int bits = 0; while (--l >= 0) { if (d[l] & 0x01) bits++; if (d[l] & 0x02) bits++; if (d[l] & 0x04) bits++; if (d[l] & 0x08) bits++; if (d[l] & 0x10) bits++; if (d[l] & 0x20) bits++; if (d[l] & 0x40) bits++; if (d[l] & 0x80) bits++; } return bits; } int bit_set(uint8_t* frame_d, int bit) { return (frame_d[(bit/16)*2 + !((bit/8)%2)] & 1<<(7-(bit%8))) != 0; } int printf_frames(uint8_t* bits, int max_frames, int row, int major, int minor, int print_empty) { int i; char prefix[32]; if (row < 0) sprintf(prefix, "f%i ", abs(row)); else sprintf(prefix, "r%i ma%i extra mi%i ", row, major, minor); if (is_empty(bits, 130)) { for (i = 1; i < max_frames; i++) { if (!is_empty(&bits[i*130], 130)) break; } if (print_empty) { if (i > 1) printf("%s- *%i\n", prefix, i); else printf("%s-\n", prefix); } return i; } if (count_bits(bits, 130) <= 32) { printf_clock(bits, row, major, minor); for (i = 0; i < 1024; i++) { if (bit_set(bits, (i >= 512) ? i + 16 : i)) printf("%sbit %i\n", prefix, i); } return 1; } printf("%shex\n", prefix); printf("{\n"); hexdump(1, bits, 130); printf("}\n"); return 1; } void printf_clock(uint8_t* frame, int row, int major, int minor) { int i; for (i = 0; i < 16; i++) { if (bit_set(frame, 512 + i)) printf("r%i ma%i mi%i clock %i\n", row, major, minor, i); } } int clb_empty(uint8_t* maj_bits, int idx) { int byte_off, i, minor; byte_off = idx * 8; if (idx >= 8) byte_off += 2; for (i = 0; i < 16; i++) { for (minor = 20; minor < 31; minor++) { if (!is_empty(&maj_bits[minor*130 + byte_off], 8)) return 0; } } return 1; } void printf_extrabits(uint8_t* maj_bits, int start_minor, int num_minors, int start_bit, int num_bits, int row, int major) { int minor, bit; for (minor = start_minor; minor < start_minor + num_minors; minor++) { for (bit = start_bit; bit < start_bit + num_bits; bit++) { if (bit_set(&maj_bits[minor*130], bit)) printf("r%i ma%i extra mi%i bit %i\n", row, major, minor, bit); } } } uint64_t read_lut64(uint8_t* two_minors, int off_in_frame) { uint64_t lut64 = 0; int j; for (j = 0; j < 16; j++) { if (bit_set(two_minors, off_in_frame+j*2)) lut64 |= 1LL << (j*4); if (bit_set(two_minors, off_in_frame+(j*2)+1)) lut64 |= 1LL << (j*4+1); if (bit_set(&two_minors[130], off_in_frame+j*2)) lut64 |= 1LL << (j*4+2); if (bit_set(&two_minors[130], off_in_frame+(j*2)+1)) lut64 |= 1LL << (j*4+3); } return lut64; } int get_vm_mb() { FILE* statusf = fopen("/proc/self/status", "r"); char line[1024]; int vm_size = 0; while (fgets(line, sizeof(line), statusf)) { if (sscanf(line, "VmSize: %i kB", &vm_size) == 1) break; } fclose(statusf); if (!vm_size) return 0; return (vm_size+1023)/1024; }