You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
4.2 KiB
145 lines
4.2 KiB
#!/usr/bin/env python3 |
|
|
|
import sys |
|
import textwrap |
|
import datetime |
|
|
|
# Very basic bitstream to SVF converter, tested with the ULX3S WiFi interface |
|
|
|
def bitreverse(x): |
|
y = 0 |
|
for i in range(8): |
|
if (x >> (7 - i)) & 1 == 1: |
|
y |= (1 << i) |
|
return y |
|
|
|
def convertBitToFlashFile(bitFile, FlashFile, flash_page_size = 256, address = 0, erase_block_size = 64*1024): |
|
with open(bitFile, 'rb') as bitf: |
|
bs = bitf.read() |
|
# Autodetect IDCODE from bitstream |
|
idcode_cmd = bytes([0xE2, 0x00, 0x00, 0x00]) |
|
idcode = None |
|
for i in range(len(bs) - 4): |
|
if bs[i:i+4] == idcode_cmd: |
|
idcode = bs[i+4] << 24 |
|
idcode |= bs[i+5] << 16 |
|
idcode |= bs[i+6] << 8 |
|
idcode |= bs[i+7] |
|
break |
|
if idcode is None: |
|
print("Failed to find IDCODE in bitstream, check bitstream is valid") |
|
sys.exit(1) |
|
print("IDCODE in bitstream is 0x%08x" % idcode) |
|
bitf.seek(0) |
|
|
|
last_page = -1 |
|
|
|
with open(FlashFile, 'w') as svf: |
|
now = datetime.datetime.now() |
|
print(f"""// generated {now:%Y-%m-%d %H:%M} |
|
STATE RESET; |
|
HDR 0; |
|
HIR 0; |
|
TDR 0; |
|
TIR 0; |
|
ENDDR DRPAUSE; |
|
ENDIR IRPAUSE; |
|
STATE IDLE; |
|
""", file=svf) |
|
print(""" |
|
SIR 8 TDI (E0); |
|
SDR 32 TDI (00000000) |
|
TDO ({:08X}) |
|
MASK (FFFFFFFF); |
|
""".format(idcode), file=svf) |
|
print(""" |
|
SIR 8 TDI (1C); |
|
SDR 510 TDI (3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
|
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); |
|
|
|
// Enter Programming mode |
|
SIR 8 TDI (C6); |
|
SDR 8 TDI (00); |
|
RUNTEST IDLE 2 TCK 1.00E-02 SEC; |
|
|
|
// Erase |
|
SIR 8 TDI (0E); |
|
SDR 8 TDI (01); |
|
RUNTEST IDLE 2 TCK 2.0E-1 SEC; |
|
|
|
// Read STATUS |
|
SIR 8 TDI (3C); |
|
SDR 32 TDI (00000000) |
|
TDO (00000000) |
|
MASK (0000B000); |
|
|
|
// Exit Programming mode |
|
SIR 8 TDI (26); |
|
RUNTEST IDLE 2 TCK 1.00E-02 SEC; |
|
|
|
// BYPASS |
|
SIR 8 TDI (FF); |
|
STATE IDLE; |
|
RUNTEST 32 TCK; |
|
RUNTEST 2.00E-2 SEC; |
|
|
|
// Enter SPI mode |
|
SIR 8 TDI (3A); |
|
SDR 16 TDI (68FE); |
|
STATE IDLE; |
|
RUNTEST 32 TCK; |
|
RUNTEST 2.00E-2 SEC; |
|
|
|
// SPI IO (CMD 0xAB release Power Down???) |
|
SDR 8 TDI (D5); |
|
RUNTEST 2.00E-0 SEC; |
|
|
|
// CONFIRM FLASH ID (CMD 0x9f JEDEC Flash Id -> Size must be 0x16) |
|
SDR 32 TDI (000000F9) |
|
TDO (68FFFFFF) |
|
MASK (FF000000); |
|
|
|
// CMD 0x06 Write Enable + 0x01 Write 0x00 to Status Register |
|
SDR 8 TDI(60); |
|
SDR 16 TDI(0080); |
|
RUNTEST 1.00E-0 SEC; |
|
|
|
""", file=svf) |
|
while True: |
|
if((address // 0x10000) != last_page): |
|
last_page = (address // 0x10000) |
|
print(f"// CMD 0x06 Write Enable + 0xd8 Erase 64K at 0x{address:x}", file=svf) |
|
print("SDR 8 TDI (60);", file=svf) |
|
address_flipped = [bitreverse(x) for x in [0xd8,int(address // 0x10000),0x00,0x00]] |
|
hex_address= ["{:02X}".format(x) for x in reversed(address_flipped)] |
|
print("\n".join(textwrap.wrap("SDR {} TDI ({});".format(8*len(hex_address), "".join(hex_address)), 100)), file=svf) |
|
print("RUNTEST 3.00 SEC;\n", file=svf) |
|
|
|
chunk = bitf.read(flash_page_size) |
|
if not chunk: |
|
break |
|
# Convert chunk to bit-reversed hex |
|
print(f"// CMD 0x06 Write Enable + 0x02 Write Chunk to 0x{address:x}", file=svf) |
|
br_chunk = [bitreverse(x) for x in bytes([0x02, int(address / 0x10000 % 0x100),int(address / 0x100 % 0x100),int(address % 0x100)]) + chunk] |
|
address += len(chunk) |
|
hex_chunk = ["{:02X}".format(x) for x in reversed(br_chunk)] |
|
print("SDR 8 TDI (60);", file=svf) |
|
print("\n".join(textwrap.wrap("SDR {} TDI ({});".format(8*len(br_chunk), "".join(hex_chunk)), 100)), file=svf) |
|
print("RUNTEST 2.50E-2 SEC;\n", file=svf) |
|
|
|
print(""" |
|
// BYPASS |
|
SIR 8 TDI (FF); |
|
|
|
//REFRESH |
|
SIR 8 TDI(79); |
|
SDR 24 TDI(000000); |
|
|
|
STATE IDLE; |
|
RUNTEST 32 TCK; |
|
RUNTEST 2.00E-2 SEC; |
|
STATE RESET; |
|
""", file=svf) |
|
|
|
if __name__ == "__main__": |
|
convertBitToFlashFile(sys.argv[1], sys.argv[2]) |