Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
63315d9a58 | |||
798a0f167e | |||
9506159380 | |||
89af26047e | |||
9876d92981 | |||
f4297532d0 | |||
4156a37d72 | |||
f2ae56a13e | |||
61151b4618 | |||
d6bff65d0b | |||
ea6c170023 | |||
d2b4ff089d | |||
fb21ad75e2 | |||
5e3ac61921 | |||
|
eb328612b2 |
|
@ -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.
|
||||
|
||||
|
|
915
fomu-flash.c
915
fomu-flash.c
File diff suppressed because it is too large
Load Diff
112
fpga.c
112
fpga.c
|
@ -11,11 +11,11 @@
|
|||
#include "fpga.h"
|
||||
|
||||
struct ff_fpga {
|
||||
struct {
|
||||
int reset;
|
||||
int done;
|
||||
int cs;
|
||||
} pins;
|
||||
struct {
|
||||
int reset;
|
||||
int done;
|
||||
int cs;
|
||||
} pins;
|
||||
};
|
||||
|
||||
int fpgaDone(struct ff_fpga *fpga) {
|
||||
|
@ -23,90 +23,90 @@ int fpgaDone(struct ff_fpga *fpga) {
|
|||
}
|
||||
|
||||
int fpgaResetSlave(struct ff_fpga *fpga) {
|
||||
// Put the FPGA into reset
|
||||
gpioSetMode(fpga->pins.reset, PI_OUTPUT);
|
||||
gpioWrite(fpga->pins.reset, 0);
|
||||
// Put the FPGA into reset
|
||||
gpioSetMode(fpga->pins.reset, PI_OUTPUT);
|
||||
gpioWrite(fpga->pins.reset, 0);
|
||||
|
||||
// Set the CS pin to a GPIO, which will let us control it
|
||||
gpioSetMode(fpga->pins.cs, PI_OUTPUT);
|
||||
// Set the CS pin to a GPIO, which will let us control it
|
||||
gpioSetMode(fpga->pins.cs, PI_OUTPUT);
|
||||
|
||||
// Set CS to 0, which will put the FPGA into slave mode
|
||||
gpioWrite(fpga->pins.cs, 0);
|
||||
// Set CS to 0, which will put the FPGA into slave mode
|
||||
gpioWrite(fpga->pins.cs, 0);
|
||||
|
||||
usleep(10000); // XXX figure out correct sleep length here
|
||||
usleep(10000); // XXX figure out correct sleep length here
|
||||
|
||||
// Bring the FPGA out of reset
|
||||
gpioWrite(fpga->pins.reset, 1);
|
||||
// Bring the FPGA out of reset
|
||||
gpioWrite(fpga->pins.reset, 1);
|
||||
|
||||
usleep(1200); // 13.2.SPI Slave Configuration Process
|
||||
usleep(1200); // 13.2.SPI Slave Configuration Process
|
||||
|
||||
// Release the CS pin
|
||||
gpioWrite(fpga->pins.cs, 1);
|
||||
// Release the CS pin
|
||||
gpioWrite(fpga->pins.cs, 1);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpgaResetMaster(struct ff_fpga *fpga) {
|
||||
|
||||
// Put the FPGA into reset
|
||||
gpioSetMode(fpga->pins.reset, PI_OUTPUT);
|
||||
gpioWrite(fpga->pins.reset, 0);
|
||||
// Put the FPGA into reset
|
||||
gpioSetMode(fpga->pins.reset, PI_OUTPUT);
|
||||
gpioWrite(fpga->pins.reset, 0);
|
||||
|
||||
// Set the CS pin to a GPIO, which will let us control it
|
||||
gpioSetMode(fpga->pins.cs, PI_OUTPUT);
|
||||
// Set the CS pin to a GPIO, which will let us control it
|
||||
gpioSetMode(fpga->pins.cs, PI_OUTPUT);
|
||||
|
||||
// Set CS to 1, which will put the FPGA into "self boot" mode
|
||||
gpioWrite(fpga->pins.cs, 1);
|
||||
// Set CS to 1, which will put the FPGA into "self boot" mode
|
||||
gpioWrite(fpga->pins.cs, 1);
|
||||
|
||||
usleep(10000); // XXX figure out correct sleep length here
|
||||
usleep(10000); // XXX figure out correct sleep length here
|
||||
|
||||
// Bring the FPGA out of reset
|
||||
gpioWrite(fpga->pins.reset, 1);
|
||||
// Bring the FPGA out of reset
|
||||
gpioWrite(fpga->pins.reset, 1);
|
||||
|
||||
usleep(1200); // 13.2.SPI Slave Configuration Process
|
||||
usleep(1200); // 13.2.SPI Slave Configuration Process
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpgaReset(struct ff_fpga *fpga) {
|
||||
// Put the FPGA into reset
|
||||
gpioSetMode(fpga->pins.reset, PI_OUTPUT);
|
||||
gpioWrite(fpga->pins.reset, 0);
|
||||
return 0;
|
||||
// Put the FPGA into reset
|
||||
gpioSetMode(fpga->pins.reset, PI_OUTPUT);
|
||||
gpioWrite(fpga->pins.reset, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpgaInit(struct ff_fpga *fpga) {
|
||||
// Put the FPGA into reset
|
||||
gpioSetMode(fpga->pins.reset, PI_OUTPUT);
|
||||
gpioWrite(fpga->pins.reset, 0);
|
||||
// Put the FPGA into reset
|
||||
gpioSetMode(fpga->pins.reset, PI_OUTPUT);
|
||||
gpioWrite(fpga->pins.reset, 0);
|
||||
|
||||
// Also monitor the C_DONE pin
|
||||
gpioSetMode(fpga->pins.done, PI_INPUT);
|
||||
// Also monitor the C_DONE pin
|
||||
gpioSetMode(fpga->pins.done, PI_INPUT);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ff_fpga *fpgaAlloc(void) {
|
||||
struct ff_fpga *fpga = (struct ff_fpga *)malloc(sizeof(struct ff_fpga));
|
||||
memset(fpga, 0, sizeof(*fpga));
|
||||
return fpga;
|
||||
struct ff_fpga *fpga = (struct ff_fpga *)malloc(sizeof(struct ff_fpga));
|
||||
memset(fpga, 0, sizeof(*fpga));
|
||||
return fpga;
|
||||
}
|
||||
|
||||
void fpgaSetPin(struct ff_fpga *fpga, enum fpga_pin pin, int val) {
|
||||
switch (pin) {
|
||||
case FP_RESET: fpga->pins.reset = val; break;
|
||||
case FP_DONE: fpga->pins.done = val; break;
|
||||
case FP_CS: fpga->pins.cs = val; break;
|
||||
default: fprintf(stderr, "unrecognized pin: %d\n", pin); break;
|
||||
}
|
||||
switch (pin) {
|
||||
case FP_RESET: fpga->pins.reset = val; break;
|
||||
case FP_DONE: fpga->pins.done = val; break;
|
||||
case FP_CS: fpga->pins.cs = val; break;
|
||||
default: fprintf(stderr, "unrecognized pin: %d\n", pin); break;
|
||||
}
|
||||
}
|
||||
|
||||
void fpgaFree(struct ff_fpga **fpga) {
|
||||
if (!fpga)
|
||||
return;
|
||||
if (!*fpga)
|
||||
return;
|
||||
if (!fpga)
|
||||
return;
|
||||
if (!*fpga)
|
||||
return;
|
||||
|
||||
free(*fpga);
|
||||
*fpga = NULL;
|
||||
free(*fpga);
|
||||
*fpga = NULL;
|
||||
}
|
||||
|
|
198
ice40.c
198
ice40.c
|
@ -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
|
||||
{
|
||||
|
@ -45,11 +79,11 @@ static uint32_t get_bit_offset(int x, int total_bits) {
|
|||
|
||||
uint32_t xorshift32(uint32_t x)
|
||||
{
|
||||
/* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */
|
||||
x = x ^ (x << 13);
|
||||
x = x ^ (x >> 17);
|
||||
x = x ^ (x << 5);
|
||||
return x;
|
||||
/* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */
|
||||
x = x ^ (x << 13);
|
||||
x = x ^ (x >> 17);
|
||||
x = x ^ (x << 5);
|
||||
return x;
|
||||
}
|
||||
|
||||
uint32_t get_rand(uint32_t x) {
|
||||
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user