CH552/project/JTAG/usbjtag.py
2021-05-17 11:27:15 +08:00

140 lines
5.3 KiB
Python

#!/usr/bin/env python3
# Copyright (c) 2020, Bo Gao <7zlaser@gmail.com>
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
# of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the names of its contributors may be
# used to endorse or promote products derived from this software without specific
# prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
# SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import sys, usb, time, binascii
class GowinJTAG:
dev=None
# Open USB device
def __init__(self):
self.dev=usb.core.find(idVendor=0x20a0, idProduct=0x4209)
if self.dev is None:
print("Error: device not found")
sys.exit(-1)
self.dev.reset()
self.dev.set_configuration()
# Close USB device
def __del__(self):
try:
usb.util.dispose_resources(self.dev)
except Exception: pass
# Write JTAG command
def WriteCmd(self, cmd):
self.dev.write(0x01, [0x10, 0x30, 0x80, 0x01, 0x00, cmd&0xff, 0x00])
# Reset FPGA
def ResetPwr(self):
self.dev.write(0x01, [0x00])
time.sleep(0.01)
self.dev.write(0x01, [0x01])
# Reset JTAG
def ResetTap(self):
self.dev.write(0x01, [0x10, 0xff, 0x00, 0x00, 0x00])
# Reset SRAM
def ResetRam(self):
self.WriteCmd(0x15) # Enter config mode
self.WriteCmd(0x05) # Clear SRAM
self.WriteCmd(0x02) # Nop
time.sleep(0.01) # Wait for finish
self.WriteCmd(0x3a) # Exit config mode
self.WriteCmd(0x02) # Nop
# Read JTAG ID
def ReadId(self):
self.WriteCmd(0x11) # Read JTAG ID command
self.dev.write(0x01, [0x11, 0x20, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
ret=self.dev.read(0x81, 64, 100)
ret.reverse()
return bytes(ret[1:5]).hex()
# Write SRAM
def WriteRam(self, filename):
flen=0
self.WriteCmd(0x15) # Enter config mode
self.WriteCmd(0x17) # Write SRAM
self.dev.write(0x01, [0x10, 0x20, 0x00]) # Shift DR
with open(filename, "rb") as f:
while True:
dat=f.read(63)
if not dat:
break
# SPI mode, MSB first
self.dev.write(0x01, [0x20]+list(dat))
flen=f.tell()
self.dev.write(0x01, [0x10, 0x03, 0x00]) # Idle
self.WriteCmd(0x3a) # Exit config mode
self.WriteCmd(0x02) # Nop
return flen
# Enter ISP mode
def EnterIsp(self):
try: # Connection WILL break
self.dev.write(0x01, [0xff])
except Exception: pass
# Entry point
if __name__ == "__main__":
import argparse
import os
parser=argparse.ArgumentParser(description="USB JTAG programmer for Gowin FPGAs")
parser.add_argument("-r", action="store_true", default=False, dest="reset_fpga", help="Reset FPGA")
parser.add_argument("-c", action="store_true", default=False, dest="clear_sram", help="Clear SRAM content")
parser.add_argument("-s", action="store_true", default=False, dest="prog_sram", help="Program SRAM")
parser.add_argument("-f", action="store", dest="prog_filename", help="Specify SRAM filename")
parser.add_argument("-i", action="store_true", default=False, dest="isp_mode", help="Enter adapter ISP mode")
parser.add_argument("-v", action="store_true", default=False, dest="verbose_mode", help="Verbose output")
args=parser.parse_args()
jtag=GowinJTAG()
if args.isp_mode:
jtag.EnterIsp()
time.sleep(0.5)
sys.exit(0)
if args.reset_fpga:
jtag.ResetPwr()
jtag.ResetTap()
if args.verbose_mode:
print("Device ID is 0x"+jtag.ReadId())
if args.clear_sram or args.prog_sram:
jtag.ResetRam()
if args.prog_sram:
if args.prog_filename is None:
print("Error: filename not specified")
sys.exit(-1)
if not os.path.exists(args.prog_filename):
print("Error: cannot open file")
sys.exit(-1)
tbegin=time.time()
flen=jtag.WriteRam(args.prog_filename)
tend=time.time()
if args.verbose_mode:
print("Programming done in {0:.2f}s at {1:.2f}kB/s.".format(tend-tbegin, flen/(tend-tbegin)/1000.0))
sys.exit(0)