Created
January 16, 2019 11:38
-
-
Save gregdavill/4f9f536757966171ef974f98348bbacb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import sys | |
import textwrap | |
# Very basic bitstream to SVF converter, tested with the ULX3S WiFi interface | |
flash_page_size = 256 | |
erase_block_size = 64*1024 | |
def bitreverse(x): | |
y = 0 | |
for i in range(8): | |
if (x >> (7 - i)) & 1 == 1: | |
y |= (1 << i) | |
return y | |
with open(sys.argv[1], '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) | |
address = 0 | |
last_page = -1 | |
with open(sys.argv[2], 'w') as svf: | |
print(""" | |
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 | |
SDR 8 TDI (D5); | |
RUNTEST 2.00E-0 SEC; | |
// CONFIRM FLASH ID | |
SDR 32 TDI (000000F9) | |
TDO (A8FFFFFF) | |
MASK (FF000000); | |
""", file=svf) | |
while True: | |
if((address // 0x10000) != last_page): | |
last_page = (address // 0x10000) | |
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; | |
""", file=svf) | |
chunk = bitf.read(flash_page_size) | |
if not chunk: | |
break | |
# Convert chunk to bit-reversed hex | |
br_chunk = [bitreverse(x) for x in bytes([0x20, 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; | |
""", file=svf) | |
print(""" | |
// BYPASS | |
SIR 8 TDI (FF); | |
STATE IDLE; | |
RUNTEST 32 TCK; | |
RUNTEST 2.00E-2 SEC; | |
STATE RESET; | |
""", file=svf) |
That's great! I don't own a ecp5_evn, so I've not tested on that yet. Good to know it works! :D
Hmmm didn't work for me with Winbond 25Q32JVSIQ flash on the Colorlight 5A-75B V8.0
First changed the ID check to
// CONFIRM FLASH ID
SDR 32 TDI (000000F9)
TDO (68FFFFFF)
MASK (FF000000);
No idea if 68 is correct, I can't make sense of what this table is trying to say. But it makes it past the check...
and then also used 0x02 as the page program command, which is the one I need as far as I can tell from the datasheet.
But yea, didn't write anything to flash as far as I can tell.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
ecpprog is awesome and works flawlessly on the ecp5_evn board. I can't believe I read your post about ecpprog on Twitter and then forgot about it. 🤦♂️