From f79a010a29774daf99212c50b26bb86f24f53fe6 Mon Sep 17 00:00:00 2001 From: Dave Marples <dave@marples.net> Date: Tue, 14 Apr 2020 14:37:56 +0100 Subject: [PATCH] Addition of flash for colorlight board --- litex_boards/targets/bit_to_flash.py | 149 ++++++++++++++++++++++ litex_boards/targets/colorlight_5a_75b.py | 17 ++- 2 files changed, 164 insertions(+), 2 deletions(-) create mode 100755 litex_boards/targets/bit_to_flash.py diff --git a/litex_boards/targets/bit_to_flash.py b/litex_boards/targets/bit_to_flash.py new file mode 100755 index 0000000..aeba5e6 --- /dev/null +++ b/litex_boards/targets/bit_to_flash.py @@ -0,0 +1,149 @@ +#!/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) + 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 (68FFFFFF) + MASK (FF000000); + +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("""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([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; + """, 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) diff --git a/litex_boards/targets/colorlight_5a_75b.py b/litex_boards/targets/colorlight_5a_75b.py index 64288c9..cafe99d 100755 --- a/litex_boards/targets/colorlight_5a_75b.py +++ b/litex_boards/targets/colorlight_5a_75b.py @@ -127,7 +127,7 @@ class BaseSoC(SoCCore): # Load --------------------------------------------------------------------------------------------- -def load(iface="ftdi"): +def openocd_run_svf(filename, iface="ftdi"): import os f = open("openocd.cfg", "w") if (iface == "ftdi"): @@ -153,9 +153,18 @@ jtag newtap lfe5u25 tap -irlen 8 -irmask 0xFF -ircapture 0x5 -expected-id 0x4111 exit() f.close() - os.system("openocd -f openocd.cfg -c \"transport select jtag; init; svf -tap lfe5u25.tap -quiet -progress soc_basesoc_colorlight_5a_75b/gateware/top.svf; exit\"") + os.system("openocd -d0 -f openocd.cfg -c \"transport select jtag; init; svf -tap lfe5u25.tap {} -quiet -progress; exit\"".format(filename)) + os.system("rm openocd.cfg") exit() +def load(iface="ftdi"): + openocd_run_svf("soc_basesoc_colorlight_5a_75b/gateware/top.svf",iface=iface) + +def flash(iface="ftdi"): + import os + os.system("./bit_to_flash.py soc_basesoc_colorlight_5a_75b/gateware/top.bit soc_basesoc_colorlight_5a_75b/gateware/top.svf.flash") + openocd_run_svf("soc_basesoc_colorlight_5a_75b/gateware/top.svf.flash",iface=iface) + # Build -------------------------------------------------------------------------------------------- def main(): @@ -168,6 +177,7 @@ def main(): parser.add_argument("--with-etherbone", action="store_true", help="enable Etherbone support") parser.add_argument("--eth-phy", default=0, type=int, help="Ethernet PHY 0 or 1 (default=0)") parser.add_argument("--load", action="store_true", help="load bitstream") + parser.add_argument("--flash", action="store_true", help="flash bitstream") parser.add_argument("--iface", default="ftdi", help="loading jtag interface") parser.add_argument("--sys-clk-freq", default=60e6, help="system clock frequency (default=60MHz)") @@ -177,6 +187,9 @@ def main(): if args.load: load(iface=args.iface) + if args.flash: + flash(iface=args.iface) + assert not (args.with_ethernet and args.with_etherbone) soc = BaseSoC(revision=args.revision, with_ethernet = args.with_ethernet, -- GitLab