| #!/usr/bin/env python3 | |
| import sys | |
| import textwrap | |
| # Very basic bitstream to SVF converter, tested with the ULX3S WiFi interface | |
| max_row_size = 8000 # needed for ULX3S Wifi | |
| 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) | |
| with open(sys.argv[2], 'w') as svf: | |
| print(""" | |
| 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); | |
| SIR 8 TDI (C6); | |
| SDR 8 TDI (00); | |
| RUNTEST IDLE 2 TCK 1.00E-02 SEC; | |
| SIR 8 TDI (3C); | |
| SDR 32 TDI (00000000) | |
| TDO (00000000) | |
| MASK (0000B000); | |
| SIR 8 TDI (46); | |
| SDR 8 TDI (01); | |
| RUNTEST IDLE 2 TCK 1.00E-02 SEC; | |
| SIR 8 TDI (7A); | |
| RUNTEST IDLE 2 TCK 1.00E-02 SEC; | |
| """, file=svf) | |
| while True: | |
| chunk = bitf.read(max_row_size//8) | |
| if not chunk: | |
| break | |
| # Convert chunk to bit-reversed hex | |
| br_chunk = [bitreverse(x) for x in chunk] | |
| hex_chunk = ["{:02X}".format(x) for x in reversed(br_chunk)] | |
| print("\n".join(textwrap.wrap("SDR {} TDI ({});".format(8*len(chunk), "".join(hex_chunk)), 100)), file=svf) | |
| print(""" | |
| SIR 8 TDI (FF); | |
| RUNTEST IDLE 100 TCK 1.00E-02 SEC; | |
| SIR 8 TDI (C0); | |
| RUNTEST IDLE 2 TCK 1.00E-03 SEC; | |
| SDR 32 TDI (00000000) | |
| TDO (00000000) | |
| MASK (FFFFFFFF); | |
| ! Shift in ISC DISABLE(0x26) instruction | |
| SIR 8 TDI (26); | |
| RUNTEST IDLE 2 TCK 2.00E-01 SEC; | |
| ! Shift in BYPASS(0xFF) instruction | |
| SIR 8 TDI (FF); | |
| RUNTEST IDLE 2 TCK 1.00E-03 SEC; | |
| ! Shift in LSC_READ_STATUS(0x3C) instruction | |
| SIR 8 TDI (3C); | |
| SDR 32 TDI (00000000) | |
| TDO (00000100) | |
| MASK (00002100); | |
| """, file=svf) |