rewrite-rom works, but maps things improperly sometimes
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								rewrite-rom
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								rewrite-rom
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										415
									
								
								rewrite-rom.c
									
									
									
									
									
								
							
							
						
						
									
										415
									
								
								rewrite-rom.c
									
									
									
									
									
								
							| @@ -5,6 +5,7 @@ | ||||
| #include <unistd.h> | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| #include <assert.h> | ||||
|  | ||||
| #define MAX(x, y) (x) > (y) ? (x) : (y) | ||||
|  | ||||
| @@ -28,14 +29,6 @@ static void update_crc16(uint16_t *crc, uint8_t byte) | ||||
|     } | ||||
| } | ||||
|  | ||||
| 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)); | ||||
| @@ -53,6 +46,11 @@ int irw_readb(struct irw_file *f) | ||||
|     return val; | ||||
| } | ||||
|  | ||||
| int irw_writeb(struct irw_file *f, int c) { | ||||
|     update_crc16(&f->crc, c); | ||||
|     return fputc(c, f->f); | ||||
| } | ||||
|  | ||||
| struct Ice40Bitstream | ||||
| { | ||||
|     uint32_t offset; | ||||
| @@ -73,16 +71,14 @@ struct Ice40Bitstream | ||||
|     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) | ||||
| int ice40_parse(struct irw_file *f) | ||||
| { | ||||
|     uint32_t preamble = 0; | ||||
|     uint8_t wakeup = 0; | ||||
|     struct Ice40Bitstream bs; | ||||
|  | ||||
|     memset(&bs, 0, sizeof(bs)); | ||||
|  | ||||
| @@ -186,8 +182,6 @@ int ice40_find_header(struct irw_file *f) | ||||
|                 //     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"); | ||||
| @@ -222,7 +216,7 @@ int ice40_find_header(struct irw_file *f) | ||||
|             // printf("setting bank number to %d\n", bs.current_bank); | ||||
|             break; | ||||
|         case 2: | ||||
|             printf("crc check (%04x == %04x)\n", f->crc, 0); | ||||
|             printf("crc check (%04x == %04x)\n", f->crc, payload); | ||||
|             break; | ||||
|         case 5: | ||||
|             switch (payload) | ||||
| @@ -287,14 +281,399 @@ int ice40_find_header(struct irw_file *f) | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| struct mapping { | ||||
|     uint32_t count; | ||||
|     uint32_t *mappings; | ||||
| }; | ||||
|  | ||||
| static void add_mapping(struct mapping *mapping, uint32_t src, uint32_t dest) { | ||||
|     mapping->mappings = realloc(mapping->mappings, (mapping->count+1) * 2 * sizeof(uint32_t)); | ||||
|     mapping->mappings[mapping->count * 2] = src; | ||||
|     mapping->mappings[mapping->count * 2 + 1] = dest; | ||||
|     printf("creating mapping %08x -> %08x\n", src, dest); | ||||
|     mapping->count++; | ||||
| } | ||||
|  | ||||
| static uint32_t get_mapping(const struct mapping *mapping, uint32_t val) { | ||||
|     int i; | ||||
|     for (i = 0; i < mapping->count; i++) { | ||||
|         if (mapping->mappings[i * 2] == val) { | ||||
|             printf("found mapping for %08x: %08x\n", val, mapping->mappings[i * 2 + 1]); | ||||
|             return mapping->mappings[i * 2 + 1]; | ||||
|         } | ||||
|     } | ||||
|     printf("couldn't find mapping for %08x\n", val); | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| uint8_t get_bit(uint32_t *field, uint32_t offset) | ||||
| { | ||||
|     // printf("offset&31: %d\n", offset & 31); | ||||
|     // printf("offset/sizeof(*field): %d\n", offset >> 5); | ||||
|     assert(offset < 65536); | ||||
|     return !!(field[offset >> 5] & (1 << (offset & 31))); | ||||
| } | ||||
|  | ||||
| void set_bit(uint32_t *field, uint32_t offset) | ||||
| { | ||||
|     assert(offset < 65536); | ||||
|     field[offset >> 5] |= (1 << (offset & 31)); | ||||
| } | ||||
|  | ||||
| void clear_bit(uint32_t *field, uint32_t offset) | ||||
| { | ||||
|     assert(offset < 65536); | ||||
|     field[offset >> 5] &= ~(1 << (offset & 31)); | ||||
| } | ||||
|  | ||||
| static uint32_t get_bit_offset(int x, int total_bits) { | ||||
|     // return (8192 * (x & 7)) + (x >> 3); | ||||
|     int bitshift = ffs(total_bits)-1; | ||||
|     return ((x * 8192) % total_bits) + ((x*8192) >> bitshift); | ||||
| } | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
| uint32_t get_rand(uint32_t x) { | ||||
|     uint32_t out = 0; | ||||
|     int i; | ||||
|     for (i = 0; i < 32; i++) { | ||||
|         x = xorshift32(x); | ||||
|         if ((x & 1) == 1) | ||||
|             out = out | (1 << i); | ||||
|     } | ||||
|     return out; | ||||
| } | ||||
|  | ||||
| static uint32_t fill_rand(uint32_t *bfr, int count) { | ||||
|     int i; | ||||
|     uint32_t last = 1; | ||||
|     for (i = 0; i < count / 4; i++) { | ||||
|         last = get_rand(last); | ||||
|         bfr[i] = last; | ||||
|     } | ||||
|     return i; | ||||
| } | ||||
|  | ||||
| uint32_t swap_u32(uint32_t word) { | ||||
|     return (((word >> 24) & 0x000000ff) | ||||
|              | ((word >> 8) & 0x0000ff00) | ||||
|              | ((word << 8) & 0x00ff0000) | ||||
|              | ((word << 24) & 0xff000000)); | ||||
| } | ||||
|  | ||||
| // 1. Read ROM file into `input` | ||||
| // 2. For each pair of bytes of input,  | ||||
| uint16_t mappings[65536]; | ||||
| int ice40_patch(struct irw_file *f, struct irw_file *rom, struct irw_file *o) | ||||
| { | ||||
|     uint32_t preamble = 0; | ||||
|     uint8_t wakeup = 0; | ||||
|     struct Ice40Bitstream bs; | ||||
|     uint32_t input_rom[2048]; | ||||
|     uint32_t input_rand[2048]; | ||||
|     uint32_t output_rand[2048]; | ||||
|     uint32_t output_rom[2048]; | ||||
|     uint8_t *i8 = (uint8_t *)input_rom; | ||||
|     uint16_t *ora16 = (uint16_t *)output_rand; | ||||
|     uint16_t *oro16 = (uint16_t *)output_rom; | ||||
|     int b; | ||||
|     struct mapping mapping; | ||||
|  | ||||
|     memset(&mapping, 0, sizeof(mapping)); | ||||
|     memset(&bs, 0, sizeof(bs)); | ||||
|  | ||||
|     int input_ptr; | ||||
|  | ||||
|     // Read the ROM into a source buffer | ||||
|     memset(input_rom, 0, sizeof(input_rom)); | ||||
|     input_ptr = 0; | ||||
|     while ((b = irw_readb(rom)) != EOF) | ||||
|         i8[input_ptr++] = b; | ||||
|     printf("read %d bytes from rom\n", input_ptr); | ||||
|  | ||||
|     // Generate our reference pattern | ||||
|     memset(input_rand, 0, sizeof(input_rand)); | ||||
|     fill_rand(input_rand, sizeof(input_rand)); | ||||
|  | ||||
|     for (input_ptr = 0; input_ptr < sizeof(input_rom)/4; input_ptr++) { | ||||
|         // input_rand[input_ptr] = swap_u32(input_rand[input_ptr]); | ||||
|         // input_rom[input_ptr] = swap_u32(input_rom[input_ptr]); | ||||
|     } | ||||
|  | ||||
|     // Spray the reference pattern and ROM like they would exist in the FPGA | ||||
|     for (input_ptr = 0; input_ptr < sizeof(input_rom) * 8; input_ptr++) { | ||||
|         int bit; | ||||
|         bit = get_bit(input_rand, get_bit_offset(input_ptr, sizeof(input_rand)*8)); | ||||
|         if (bit) | ||||
|             set_bit(output_rand, input_ptr); | ||||
|         else | ||||
|             clear_bit(output_rand, input_ptr); | ||||
|  | ||||
|         bit = get_bit(input_rom, get_bit_offset(input_ptr, sizeof(input_rom)*8)); | ||||
|         if (bit) | ||||
|             set_bit(output_rom, input_ptr); | ||||
|         else | ||||
|             clear_bit(output_rom, input_ptr); | ||||
|     } | ||||
|  | ||||
|     // Finally, build a mapping from the random data to the replacement rom data. | ||||
|     uint32_t collisions = 0; | ||||
|     for (input_ptr = 0; input_ptr < 4096; input_ptr += 1) { | ||||
|         // uint32_t ra1 = (output_rand[input_ptr + 0] & 0xffff0000) | ||||
|         //                | ((output_rand[input_ptr + 1] >> 16) & 0x0000ffff); | ||||
|         // uint32_t ra2 = (output_rand[input_ptr + 1] & 0xffff0000) | ||||
|         //                | ((output_rand[input_ptr + 0] >> 16) & 0x0000ffff); | ||||
|         // add_mapping(&mapping, ra1, output_rom[input_ptr + 0]); | ||||
|         // add_mapping(&mapping, ra2, output_rom[input_ptr + 1]); | ||||
|         if (mappings[ora16[input_ptr]]) { | ||||
|             collisions++; | ||||
|             printf("mapping position %d not empty\n", input_ptr); | ||||
|         } | ||||
|         mappings[ora16[input_ptr]] = oro16[input_ptr]; | ||||
|     } | ||||
|     if (collisions) | ||||
|         printf("had %d collisions\n", collisions); | ||||
|  | ||||
|     while (1) | ||||
|     { | ||||
|         b = irw_readb(f); | ||||
|         if (b == EOF) | ||||
|             break; | ||||
|         irw_writeb(o, b); | ||||
|  | ||||
|         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; | ||||
|         } | ||||
|         irw_writeb(o, b); | ||||
|  | ||||
|         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++) | ||||
|         { | ||||
|             b = irw_readb(f); | ||||
|             payload = (payload << 8) | (b & 0xff); | ||||
|  | ||||
|             // Don't write the CRC16 out, since we'll do that later on. | ||||
|             if (cmd != 2) | ||||
|                 irw_writeb(o, b); | ||||
|         } | ||||
|  | ||||
|         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++) | ||||
|                 { | ||||
|                     irw_writeb(o, 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); | ||||
|                 } | ||||
|                 irw_writeb(o, last0); | ||||
|                 irw_writeb(o, 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); | ||||
|                 for (i = 0; i < ((bs.current_width * bs.current_height) / 8); i += 2) | ||||
|                 { | ||||
|                     uint32_t word =  | ||||
|                         // ((irw_readb(f) << 24) & 0xff000000) | ||||
|                         // | | ||||
|                         // ((irw_readb(f) << 16) & 0x00ff0000) | ||||
|                         // | | ||||
|                         ((irw_readb(f) << 8) & 0x0000ff00) | ||||
|                         | | ||||
|                         ((irw_readb(f) << 0) & 0x000000ff) | ||||
|                         ; | ||||
|                     // printf("%04x -> %04x\n", word, mapping[word]); | ||||
|                     // word = get_mapping(&mapping, word); | ||||
|                     // irw_writeb(o, word >> 24); | ||||
|                     // irw_writeb(o, word >> 16); | ||||
|                     word = mappings[word]; | ||||
|                     irw_writeb(o, word >> 8); | ||||
|                     irw_writeb(o, word); | ||||
|                 } | ||||
|                 last0 = irw_readb(f); | ||||
|                 last1 = irw_readb(f); | ||||
|                 if (last0 || last1) | ||||
|                 { | ||||
|                     printf("expected 0x0000 after BRAM data, got %02x %02x\n", last0, last1); | ||||
|                 } | ||||
|                 irw_writeb(o, last0); | ||||
|                 irw_writeb(o, last1); | ||||
|                 break; | ||||
|  | ||||
|             // Reset CRC | ||||
|             case 5: | ||||
|                 f->crc = 0xffff; | ||||
|                 o->crc = 0xffff; | ||||
|                 break; | ||||
|  | ||||
|             // Wakeup | ||||
|             case 6: | ||||
|                 wakeup = 1; | ||||
|                 break; | ||||
|  | ||||
|             default: | ||||
|                 printf("unrecognized command 0x%02x 0x%02x\n", cmd, payload); | ||||
|                 break; | ||||
|             } | ||||
|             break; | ||||
|  | ||||
|         // Set current bank | ||||
|         case 1: | ||||
|             bs.current_bank = payload; | ||||
|             // printf("setting bank number to %d\n", bs.current_bank); | ||||
|             break; | ||||
|  | ||||
|         // Validate CRC16 | ||||
|         case 2: | ||||
|             printf("crc check (%04x == %04x)\n", f->crc, 0); | ||||
|             uint16_t crc16 = o->crc; | ||||
|             irw_writeb(o, crc16 >> 8); | ||||
|             irw_writeb(o, crc16); | ||||
|             break; | ||||
|  | ||||
|         // Set frequency range | ||||
|         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; | ||||
|  | ||||
|         // Set current width | ||||
|         case 6: | ||||
|             bs.current_width = payload + 1; | ||||
|             break; | ||||
|  | ||||
|         // Set current height | ||||
|         case 7: | ||||
|             bs.current_height = payload; | ||||
|             break; | ||||
|  | ||||
|         // Set current ofset | ||||
|         case 8: | ||||
|             bs.current_offset = payload; | ||||
|             break; | ||||
|  | ||||
|         // Set flags | ||||
|         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; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Padding | ||||
|     irw_writeb(o, 0); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
|     struct irw_file *f = irw_open("memtest/memtest.bin", "r"); | ||||
|     if (!f) | ||||
|  | ||||
|     struct irw_file *input = irw_open("top.bin", "r"); | ||||
|     struct irw_file *output = irw_open("new.bin", "w"); | ||||
|     struct irw_file *rom = irw_open("rom.bin", "r"); | ||||
|  | ||||
|     // int i; | ||||
|     // for (i = 0; i < 32; i++) { | ||||
|     //     printf("bit %d: %d\n", i, get_bit_offset(i, 8192*8)); | ||||
|     // } | ||||
|  | ||||
|     if (!input) | ||||
|     { | ||||
|         perror("couldn't open top.bin"); | ||||
|         return 1; | ||||
|     } | ||||
|     ice40_find_header(f); | ||||
|  | ||||
|     if (!output) { | ||||
|         perror("couldn't open new.bin"); | ||||
|         return 2; | ||||
|     } | ||||
|  | ||||
|     ice40_patch(input, rom, output); | ||||
|     return 0; | ||||
| } | ||||
| @@ -1,5 +1,8 @@ | ||||
| #include <stdio.h> | ||||
| #include <stdint.h> | ||||
| #include <fcntl.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/types.h> | ||||
|  | ||||
| uint32_t xorshift32(uint32_t x) | ||||
| { | ||||
| @@ -24,10 +27,12 @@ uint32_t get_rand(uint32_t x) { | ||||
| int main(int argc, char **argv) { | ||||
|     int i; | ||||
|  | ||||
|     int fd = open("rom.bin", O_WRONLY | O_CREAT | O_TRUNC, 0777); | ||||
|     uint32_t init = 1; | ||||
|     for (i = 0; i < 2048; i++) { | ||||
|         init = get_rand(init); | ||||
|         printf("%08x\n", init); | ||||
|         // printf("%08x\n", init); | ||||
|         write(fd, &init, sizeof(init)); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user