Compare commits

...

15 Commits
v1.2 ... master

Author SHA1 Message Date
63315d9a58 fomu-flash: exit nonzero on write error
Signed-off-by: Sean Cross <sean@xobs.io>
2021-04-14 14:11:06 +08:00
798a0f167e ice40: hardcode ora_ptr
The previous approach of attempting to derive it didn't work.

It turns out that the ora_ptr is 16 * the current offset.

Signed-off-by: Sean Cross <sean@xobs.io>
2019-02-26 15:12:45 +08:00
9506159380 fomu-flash: disable ICE40_DEBUG_PATCH
Since we've got ice40 working, we don't need to debug it anymore.

Signed-off-by: Sean Cross <sean@xobs.io>
2019-02-26 14:49:11 +08:00
89af26047e ice40: rewrite matching heuristic to increase reliability
Instead of looping through a small window, figure out the various bit
positions and offsets.  Then, as we scan through, validate that we've
found the proper offsets.

This should get us to 100% reliability.

Signed-off-by: Sean Cross <sean@xobs.io>
2019-02-26 14:48:05 +08:00
9876d92981 fpga: convert tabs to spaces
Signed-off-by: Sean Cross <sean@xobs.io>
2019-02-26 13:10:19 +08:00
f4297532d0 fomu-flash: make DEBUG_ICE40_PATCH work better
Signed-off-by: Sean Cross <sean@xobs.io>
2019-02-26 13:08:13 +08:00
4156a37d72 fomu-flash: convert tabs to spaces
Signed-off-by: Sean Cross <sean@xobs.io>
2019-02-26 13:03:09 +08:00
f2ae56a13e ice40: convert tabs to spaces
Signed-off-by: Sean Cross <sean@xobs.io>
2019-02-26 13:02:41 +08:00
61151b4618 fomu-flash: add debug hack to fix ice40 stuff
This will write data to a file, rather than to SPI.

Signed-off-by: Sean Cross <sean@xobs.io>
2019-02-26 13:01:04 +08:00
d6bff65d0b Merge branch 'master' of github.com:im-tomu/fomu-flash 2019-02-25 22:17:38 +08:00
ea6c170023 ice40: lower fuzz size to improve patcher reliability
The fuzz size should be made smaller, because we're getting too many false positives.

Signed-off-by: Sean Cross <sean@xobs.io>
2019-02-25 22:16:31 +08:00
d2b4ff089d ice40: convert from dos to unix line endings
Signed-off-by: Sean Cross <sean@xobs.io>
2019-02-25 18:38:53 +08:00
fb21ad75e2
Merge pull request #3 from tari/hardware-spi
Document the requirement for hardware SPI
2019-02-25 17:11:10 +08:00
5e3ac61921
Merge branch 'master' into hardware-spi 2019-02-25 17:10:11 +08:00
Peter Marheine
eb328612b2 Document the requirement for hardware SPI
I spent a while fighting with my hardware before working this out- if
SPI is disabled in the kernel reads will return all 1s which is very
confusing and looks more like something is wired up wrong when it's
actually correct.
2019-02-25 14:56:02 +11:00
5 changed files with 1117 additions and 971 deletions

View File

@ -16,7 +16,10 @@ The EVT boards can be attached directly to the Raspberry Pi as a "hat". When bu
The only pins that are required are 5V, GND, CRESET, SPI_MOSI, SPI_MISO, SPI_CLK, and SPI_CS.
You can improve performance by attaching SPI_IO2 and SPI_IO3 and running `fomu-flash` in quad/qpi mode by specifying `-t 4` or `-t q`.
The Pi's hardware SPI interface must be enabled in the kernel- use
`raspi-config` or add `dtparam=spi=on` to `/boot/config.txt` and reboot before
using. You can improve performance by attaching SPI_IO2 and SPI_IO3 and running
`fomu-flash` in quad/qpi mode by specifying `-t 4` or `-t q`.
You can get serial interaction by connecting the UART pins, but they are not necessary for flashing.

View File

@ -25,6 +25,8 @@
static unsigned int F_RESET = 27;
#define F_DONE 17
// #define DEBUG_ICE40_PATCH
static int spi_irw_readb(void *data) {
return spiRx(data);
}
@ -185,6 +187,7 @@ int main(int argc, char **argv) {
enum spi_type spi_type = ST_SINGLE;
struct irw_file *replacement_rom = NULL;
#ifndef DEBUG_ICE40_PATCH
if (gpioInitialise() < 0) {
fprintf(stderr, "Unable to initialize GPIO\n");
return 1;
@ -195,6 +198,7 @@ int main(int argc, char **argv) {
// original had it as BCM 21.
if ((gpioHardwareRevision() == 2) || (gpioHardwareRevision() == 3))
F_RESET = 21;
#endif
spi = spiAlloc();
fpga = fpgaAlloc();
@ -361,6 +365,7 @@ int main(int argc, char **argv) {
return 1;
}
#ifndef DEBUG_ICE40_PATCH
spiInit(spi);
fpgaInit(fpga);
@ -369,6 +374,16 @@ int main(int argc, char **argv) {
if (spi_flash_bytes != -1)
spiOverrideSize(spi, spi_flash_bytes);
#else
if (op != OP_FPGA_BOOT) {
printf("DEBUG_ICE40_PATCH requires you load a bitstream with '-f'\n");
return 9;
}
if (!replacement_rom) {
printf("DEBUG_ICE40_PATCH requires you load a replacement rom with '-l'\n");
return 10;
}
#endif
switch (op) {
case OP_SPI_ID: {
@ -453,7 +468,7 @@ int main(int argc, char **argv) {
break;
}
close(fd);
spiWrite(spi, 0, bfr, stat.st_size);
ret += spiWrite(spi, 0, bfr, stat.st_size);
break;
}
@ -502,21 +517,25 @@ offset, file_src[offset], spi_src[offset]);
case OP_FPGA_BOOT: {
int count;
#ifndef DEBUG_ICE40_PATCH
spiHold(spi);
spiSwapTxRx(spi);
fpgaResetSlave(fpga);
fprintf(stderr, "FPGA Done? %d\n", fpgaDone(fpga));
spiBegin(spi);
#endif
if (replacement_rom) {
IRW_FILE *bitstream = irw_open(op_filename, "r");
if (!bitstream) {
perror("unable to open fpga bitstream");
break;
}
#ifdef DEBUG_ICE40_PATCH
IRW_FILE *spidev = irw_open("foboot-patched.bin", "w");
return ice40_patch(bitstream, replacement_rom, spidev, 8192);
#else
IRW_FILE *spidev = irw_open_fake(spi, spi_irw_readb, spi_irw_writeb);
#endif
ice40_patch(bitstream, replacement_rom, spidev, 8192);
}
else {

188
ice40.c
View File

@ -3,7 +3,41 @@
#include "ice40.h"
#define MAX(x, y) (x) > (y) ? (x) : (y)
#define ARRAY_SIZE(x) ((sizeof(x) / sizeof(*x)))
#define DEBUG_PRINT(...)
// #define DEBUG_PRINT(...) printf(__VA_ARGS__)
// #define SCAN_DEBUG
// Make this a macro so line numbers work correctly
#define assert_words_equal(check_word, old_word) \
if (check_word != old_word) { \
int j; \
printf("mismatch in source stream!\n"); \
printf("old_word: %04x check_word: %04x\n", old_word, check_word); \
printf("rand:"); \
for (j = (offset + mapping) - 16; j < (offset + mapping) + 16; j++) { \
if (j == (offset + mapping)) \
printf(" [%04x]", ora16[j]); \
else \
printf(" %04x", ora16[j]); \
}\
printf("\n"); \
\
printf(" rom:");\
for (j = i - 16; j < i + 16; j++) {\
printf(" %04x", oro16[j]);\
}\
printf("\n");\
printf("if possible, please email the rom and bitstream to sean@xobs.io\n"); \
} \
assert(check_word == old_word)
#ifdef SCAN_DEBUG
#define SCAN_DEBUG_PRINT(...) printf(__VA_ARGS__)
#else
#define SCAN_DEBUG_PRINT(...)
#endif
struct Ice40Bitstream
{
@ -166,7 +200,6 @@ int ice40_patch(struct irw_file *f, struct irw_file *rom,
uint16_t *ora16 = (uint16_t *)output_rand;
uint16_t *oro16 = (uint16_t *)output_rom;
unsigned int ora_ptr = 0;
unsigned int ora_matches = 0;
unsigned int input_ptr;
int b;
int errors = 0;
@ -284,44 +317,136 @@ int ice40_patch(struct irw_file *f, struct irw_file *rom,
(bs.current_width * bs.current_height) / 8);
bs.bram_width = MAX(bs.bram_width, bs.current_width);
bs.bram_height = MAX(bs.bram_height, bs.current_height);
for (i = 0; i < ((bs.current_width * bs.current_height) / 8); i += 2)
{
uint16_t word =
((irw_readb(f) << 8) & 0x0000ff00)
|
((irw_readb(f) << 0) & 0x000000ff)
;
int i;
ora_ptr = 16 * bs.current_offset;
if (word) {
int found = 0;
int start = ora_ptr - 64;
int end = ora_ptr + 64;
if (start < 0)
start = 0;
if (end > 8192)
end = 8192;
for (i = start; i < end; i++) {
if (ora16[i] == word) {
found = 1;
word = oro16[i];
ora_matches++;
ora_ptr = i;
break;
// Step 1: Find a mapping by scanning through the first 128 words looking for patterns.
uint16_t scan_buffer[128];
assert(((bs.current_width * bs.current_height)/8)*2 > 128);
for (i = 0; i < ARRAY_SIZE(scan_buffer); i++) {
scan_buffer[i] = ((irw_readb(f) << 8) & 0xff00) | ((irw_readb(f) << 0) & 0x00ff);
}
#ifdef SCAN_DEBUG
SCAN_DEBUG_PRINT("scan:");
for (i = 0; i < ARRAY_SIZE(scan_buffer); i++) {
SCAN_DEBUG_PRINT(" %04x", scan_buffer[i]);
}
SCAN_DEBUG_PRINT("\n");
SCAN_DEBUG_PRINT("rand:");
for (i = 0; i < ARRAY_SIZE(scan_buffer); i++) {
SCAN_DEBUG_PRINT(" %04x", ora16[ora_ptr + i]);
}
SCAN_DEBUG_PRINT("\n");
SCAN_DEBUG_PRINT(" rom:");
for (i = 0; i < ARRAY_SIZE(scan_buffer); i++) {
SCAN_DEBUG_PRINT(" %04x", oro16[ora_ptr + i]);
}
SCAN_DEBUG_PRINT("\n");
#endif /* SCAN_DEBUG */
int outer_word = 0;
static struct {
int bitstream;
int random;
int stride;
} word_mappings[16];
int word_stride = -1;
for (outer_word = 0; outer_word < 16; outer_word++) {
int inner_word;
word_mappings[outer_word].bitstream = -1;
word_mappings[outer_word].random = -1;
word_mappings[outer_word].stride = -1;
for (inner_word = 0; inner_word < 16; inner_word++) {
// We have a candidate offset. Figure out what its stride is,
// and validate that we have multiple matches.
if (scan_buffer[outer_word] == ora16[ora_ptr + inner_word]) {
SCAN_DEBUG_PRINT("Candidate %04x @ %d/%d\n", scan_buffer[outer_word], outer_word, inner_word);
int scan_offset = 0;
for (scan_offset = 0; scan_offset < 30; scan_offset++) {
if ((scan_buffer[outer_word + scan_offset] == ora16[ora_ptr + inner_word + 16])
&& (scan_buffer[outer_word + (scan_offset*2)] == ora16[ora_ptr + inner_word + 32])) {
SCAN_DEBUG_PRINT("Scan offset: %d\n", scan_offset);
word_mappings[outer_word].bitstream = outer_word;
word_mappings[outer_word].random = inner_word;
word_mappings[outer_word].stride = scan_offset;
}
}
if (!found) {
printf("couldn't find word %04x (ora_ptr: %d matches: %d)\n", word, ora_ptr, ora_matches);
errors++;
}
}
}
for (i = 0; i < ARRAY_SIZE(word_mappings); i++) {
if (word_mappings[i].stride != -1) {
if (word_stride != -1) {
if (word_mappings[i].stride != word_stride) {
printf("This stride is different (%d vs expected %d)\n", word_mappings[i].stride, word_stride);
}
}
word_stride = word_mappings[i].stride;
}
}
#ifdef SCAN_DEBUG
for (outer_word = 0; outer_word < ARRAY_SIZE(word_mappings); outer_word++) {
SCAN_DEBUG_PRINT("word_mappings[%2d]: bitstream: %2d random: %2d stride: %2d\n",
outer_word, word_mappings[outer_word].bitstream,
word_mappings[outer_word].random, word_mappings[outer_word].stride);
}
#endif /* SCAN_DEBUG */
for (i = 0; i < ARRAY_SIZE(scan_buffer); i++) {
int offset = -1;
int mapping = -1;
if (word_stride != -1) {
offset = (i / word_stride) * 16;
mapping = word_mappings[i % word_stride].random;
}
uint16_t old_word = scan_buffer[i];
uint16_t check_word;
uint16_t new_word;
if (mapping == -1) {
new_word = check_word = old_word;
}
else {
ora_ptr++;
// DEBUG_PRINT("word is 0, ptr is %d\n", ora_ptr);
check_word = ora16[ora_ptr + offset + mapping];
new_word = oro16[ora_ptr + offset + mapping];
}
irw_writeb(o, word >> 8);
irw_writeb(o, word);
irw_writeb(o, new_word >> 8);
irw_writeb(o, new_word);
SCAN_DEBUG_PRINT("%4d %4d %2d %2d %04x <-> %04x -> %04x\n", i, sizeof(scan_buffer), offset, mapping, old_word, check_word, new_word);
assert_words_equal(check_word, old_word);
}
SCAN_DEBUG_PRINT("---\n");
// Finish reading the page
for (i = ARRAY_SIZE(scan_buffer); i < ((bs.current_width * bs.current_height) / 8)/2; i++) {
int offset = -1;
int mapping = -1;
if (word_stride != -1) {
offset = (i / word_stride) * 16;
mapping = word_mappings[i % word_stride].random;
}
uint16_t old_word =
((irw_readb(f) << 8) & 0xff00)
|
((irw_readb(f) << 0) & 0x00ff)
;
uint16_t check_word;
uint16_t new_word;
if (mapping == -1) {
new_word = check_word = old_word;
}
else {
check_word = ora16[ora_ptr + offset + mapping];
new_word = oro16[ora_ptr + offset + mapping];
}
irw_writeb(o, new_word >> 8);
irw_writeb(o, new_word);
SCAN_DEBUG_PRINT("%4d %4d %2d %2d %04x <-> %04x -> %04x\n", i, sizeof(scan_buffer), offset, mapping, old_word, check_word, new_word);
assert_words_equal(check_word, old_word);
}
last0 = irw_readb(f);
last1 = irw_readb(f);
if (last0 || last1)
@ -353,7 +478,6 @@ int ice40_patch(struct irw_file *f, struct irw_file *rom,
case 1:
bs.current_bank = payload;
ora_ptr = 0;
ora_matches = 0;
// printf("setting bank number to %d\n", bs.current_bank);
break;