300 lines
9.0 KiB
C
300 lines
9.0 KiB
C
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#define MAX(x, y) (x) > (y) ? (x) : (y)
|
|
|
|
typedef struct irw_file
|
|
{
|
|
FILE *f;
|
|
uint16_t crc;
|
|
uint32_t offset;
|
|
} IRW_FILE;
|
|
|
|
int print_hex_offset(const void *block, int count, int offset, uint32_t start);
|
|
int print_hex(const void *block, int count, uint32_t start);
|
|
|
|
static void update_crc16(uint16_t *crc, uint8_t byte)
|
|
{
|
|
// CRC-16-CCITT, Initialize to 0xFFFF, No zero padding
|
|
for (int i = 7; i >= 0; i--)
|
|
{
|
|
uint16_t xor_value = ((*crc >> 15) ^ ((byte >> i) & 1)) ? 0x1021 : 0;
|
|
*crc = (*crc << 1) ^ xor_value;
|
|
}
|
|
}
|
|
|
|
static uint8_t reverse_u8(uint8_t b)
|
|
{
|
|
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
|
|
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
|
|
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
|
|
return b;
|
|
}
|
|
|
|
struct irw_file *irw_open(const char *filename, const char *mode)
|
|
{
|
|
struct irw_file *f = malloc(sizeof(*f));
|
|
memset(f, 0, sizeof(*f));
|
|
f->f = fopen(filename, mode);
|
|
return f;
|
|
}
|
|
|
|
int irw_readb(struct irw_file *f)
|
|
{
|
|
int val = fgetc(f->f);
|
|
if (val == EOF)
|
|
return EOF;
|
|
update_crc16(&f->crc, val);
|
|
return val;
|
|
}
|
|
|
|
struct Ice40Bitstream
|
|
{
|
|
uint32_t offset;
|
|
uint32_t current_bank;
|
|
uint32_t current_width;
|
|
uint32_t current_height;
|
|
uint32_t current_offset;
|
|
|
|
uint32_t cram_width;
|
|
uint32_t cram_height;
|
|
|
|
uint32_t bram_width;
|
|
uint32_t bram_height;
|
|
|
|
uint16_t crc_value;
|
|
|
|
uint8_t warmboot;
|
|
uint8_t nosleep;
|
|
|
|
uint8_t frequency_range;
|
|
|
|
uint8_t bram_banks[4][2560 * 2];
|
|
};
|
|
|
|
struct Ice40Bitstream bs;
|
|
|
|
int ice40_find_header(struct irw_file *f)
|
|
{
|
|
uint32_t preamble = 0;
|
|
uint8_t wakeup = 0;
|
|
|
|
memset(&bs, 0, sizeof(bs));
|
|
|
|
while (1)
|
|
{
|
|
int b = irw_readb(f);
|
|
if (b == EOF)
|
|
break;
|
|
|
|
preamble = (preamble << 8) | b;
|
|
if (preamble == 0x7eaa997e)
|
|
{
|
|
// printf("found preamble at %d\n", bs.offset);
|
|
break;
|
|
}
|
|
}
|
|
|
|
while (!wakeup)
|
|
{
|
|
int b = irw_readb(f);
|
|
if (b == EOF)
|
|
{
|
|
// printf("reached end of file\n");
|
|
break;
|
|
}
|
|
|
|
uint8_t cmd = b >> 4;
|
|
uint8_t payload_len = b & 0xf;
|
|
uint32_t payload = 0;
|
|
uint8_t last0, last1;
|
|
int i;
|
|
for (i = 0; i < payload_len; i++)
|
|
{
|
|
payload = (payload << 8) | (irw_readb(f) & 0xff);
|
|
}
|
|
|
|
// printf("cmd: %02x payload: %02x payload_len: %d\n", cmd, payload, payload_len);
|
|
switch (cmd)
|
|
{
|
|
case 0:
|
|
switch (payload)
|
|
{
|
|
case 1:
|
|
printf("CRAM data (bank %d): %d x %d @ 0x%08x; %d bits = %d bytes\n",
|
|
bs.current_bank,
|
|
bs.current_width,
|
|
bs.current_height,
|
|
bs.current_offset,
|
|
bs.current_width * bs.current_height,
|
|
(bs.current_width * bs.current_height) / 8);
|
|
bs.cram_width = MAX(bs.cram_width, bs.current_width);
|
|
bs.cram_height = MAX(bs.cram_height, bs.current_height);
|
|
for (i = 0; i < ((bs.current_width * bs.current_height) / 8); i++)
|
|
{
|
|
(void)irw_readb(f);
|
|
}
|
|
last0 = irw_readb(f);
|
|
last1 = irw_readb(f);
|
|
if (last0 || last1)
|
|
{
|
|
printf("expected 0x0000 after CRAM data, got %02x %02x\n", last0, last1);
|
|
}
|
|
break;
|
|
case 3:
|
|
{
|
|
printf("BRAM data (bank %d): %d x %d @ 0x%08x; %d bits = %d bytes\n",
|
|
bs.current_bank,
|
|
bs.current_width,
|
|
bs.current_height,
|
|
bs.current_offset,
|
|
bs.current_width * bs.current_height,
|
|
(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);
|
|
uint8_t try_1[(bs.current_height * bs.current_width) / 8];
|
|
uint8_t try_2[(bs.current_height * bs.current_width) / 8];
|
|
uint8_t try_3[(bs.current_height * bs.current_width) / 8];
|
|
uint8_t try_4[(bs.current_height * bs.current_width) / 8];
|
|
memset(try_1, 0, sizeof(try_1));
|
|
memset(try_2, 0, sizeof(try_2));
|
|
memset(try_3, 0, sizeof(try_3));
|
|
memset(try_4, 0, sizeof(try_4));
|
|
for (i = 0; i < ((bs.current_width * bs.current_height) / 8); i++)
|
|
{
|
|
uint8_t byte = irw_readb(f);
|
|
// int j;
|
|
// for (j = 0; j < 8; j++)
|
|
// {
|
|
// int x = (i * 8 + j) % bs.current_width;
|
|
// int y = (i * 8 + j) / bs.current_width;// + bs.current_offset;
|
|
// printf("x: %d y: %d\n", x, y);
|
|
// try_2[(x * bs.current_width + y) / 8] |= (1 << j);
|
|
// }
|
|
try_1[i] = byte;
|
|
// try_3[i] = reverse_u8(byte);
|
|
// try_4[i] = byte;
|
|
}
|
|
// for (i = 0; i < sizeof(try_4); i += 2)
|
|
// {
|
|
// uint8_t t = try_4[i];
|
|
// try_4[i] = try_4[i + 1];
|
|
// try_4[i + 1] = t;
|
|
// }
|
|
printf("try 1:\n");
|
|
print_hex(try_1, sizeof(try_1), 0);
|
|
// printf("try 2:\n");
|
|
// print_hex(try_2, sizeof(try_2), 0);
|
|
// printf("try 3:\n");
|
|
// print_hex(try_3, sizeof(try_3), 0);
|
|
// printf("try 4:\n");
|
|
// print_hex(try_4, sizeof(try_4), 0);
|
|
last0 = irw_readb(f);
|
|
last1 = irw_readb(f);
|
|
if (last0 || last1)
|
|
{
|
|
printf("expected 0x0000 after BRAM data, got %02x %02x\n", last0, last1);
|
|
}
|
|
break;
|
|
}
|
|
case 5:
|
|
// printf("resetting crc\n");
|
|
f->crc = 0xffff;
|
|
break;
|
|
|
|
case 6:
|
|
// printf("wakeup\n");
|
|
wakeup = 1;
|
|
break;
|
|
|
|
default:
|
|
printf("unrecognized command 0x%02x 0x%02x\n", cmd, payload);
|
|
break;
|
|
}
|
|
break;
|
|
case 1:
|
|
bs.current_bank = payload;
|
|
// printf("setting bank number to %d\n", bs.current_bank);
|
|
break;
|
|
case 2:
|
|
printf("crc check (%04x == %04x)\n", f->crc, 0);
|
|
break;
|
|
case 5:
|
|
switch (payload)
|
|
{
|
|
case 0:
|
|
bs.frequency_range = 0;
|
|
break;
|
|
case 1:
|
|
bs.frequency_range = 1;
|
|
break;
|
|
case 2:
|
|
bs.frequency_range = 2;
|
|
break;
|
|
default:
|
|
printf("unknown frequency range payload: %02x\n", payload);
|
|
break;
|
|
}
|
|
break;
|
|
case 6:
|
|
bs.current_width = payload + 1;
|
|
// printf("setting bank width to %d\n", bs.current_width);
|
|
break;
|
|
case 7:
|
|
bs.current_height = payload;
|
|
// printf("setting bank height to %d\n", bs.current_height);
|
|
break;
|
|
case 8:
|
|
bs.current_offset = payload;
|
|
// printf("setting bank offset to %d\n", bs.current_offset);
|
|
break;
|
|
case 9:
|
|
switch (payload)
|
|
{
|
|
case 0:
|
|
bs.warmboot = 0;
|
|
bs.nosleep = 0;
|
|
break;
|
|
case 1:
|
|
bs.warmboot = 0;
|
|
bs.nosleep = 1;
|
|
break;
|
|
case 32:
|
|
bs.warmboot = 1;
|
|
bs.nosleep = 0;
|
|
break;
|
|
case 33:
|
|
bs.warmboot = 1;
|
|
bs.nosleep = 1;
|
|
break;
|
|
default:
|
|
printf("unrecognized feature flags: %02x\n", payload);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
printf("unrecognized command: %02x\n", cmd);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// printf("read %d bytes\n", bs.offset);
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
struct irw_file *f = irw_open("memtest/memtest.bin", "r");
|
|
if (!f)
|
|
{
|
|
perror("couldn't open top.bin");
|
|
return 1;
|
|
}
|
|
ice40_find_header(f);
|
|
return 0;
|
|
} |