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