Merge pull request #148 from colognechip/colognechip/gatemate

Cologne Chip GateMate integration
This commit is contained in:
Gwenhael Goavec-Merou 2021-12-13 19:15:19 +01:00 committed by GitHub
commit 6ba0cb7f66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 709 additions and 31 deletions

View File

@ -103,6 +103,8 @@ set(OPENFPGALOADER_SOURCE
src/bitparser.cpp
src/xilinx.cpp
src/xilinxMapParser.cpp
src/colognechip.cpp
src/colognechipCfgParser.cpp
)
set(OPENFPGALOADER_HEADERS
@ -150,6 +152,8 @@ set(OPENFPGALOADER_HEADERS
src/latticeBitParser.hpp
src/xilinx.hpp
src/xilinxMapParser.hpp
src/colognechip.hpp
src/colognechipCfgParser.hpp
)
add_executable(openFPGALoader

View File

@ -12,7 +12,7 @@
<strong><a href="https://trabucayre.github.io/openFPGALoader/guide/first-steps.html">First steps</a><a href="https://trabucayre.github.io/openFPGALoader/guide/install.html">Install</a><a href="https://trabucayre.github.io/openFPGALoader/guide/troubleshooting.html">Troubleshooting</a></strong><a href="https://trabucayre.github.io/openFPGALoader/guide/advanced.html">Advanced usage</a>
</p>
Universal utility for programming FPGAs. Compatible with many boards, cables and FPGA from major manufacturers (Xilinx, Altera/Intel, Lattice, Gowin, Efinix, Anlogic). openFPGALoader works on Linux, Windows and macOS.
Universal utility for programming FPGAs. Compatible with many boards, cables and FPGA from major manufacturers (Xilinx, Altera/Intel, Lattice, Gowin, Efinix, Anlogic, Cologne Chip). openFPGALoader works on Linux, Windows and macOS.
Not sure if your hardware is supported? Check the hardware compatibility lists:
@ -22,6 +22,7 @@ Not sure if your hardware is supported? Check the hardware compatibility lists:
Also checkout the vendor-specific documentation:
[Anlogic](https://trabucayre.github.io/openFPGALoader/vendors/anlogic.html),
[Cologne Chip](https://trabucayre.github.io/openFPGALoader/vendors/colognechip.html),
[Efinix](https://trabucayre.github.io/openFPGALoader/vendors/efinix.html),
[Gowin](https://trabucayre.github.io/openFPGALoader/vendors/gowin.html),
[Intel/Altera](https://trabucayre.github.io/openFPGALoader/vendors/intel.html),

View File

@ -21,6 +21,9 @@ Boards
arty `Digilent Analog Discovery 2 <https://reference.digilentinc.com/test-and-measurement/analog-discovery-2/start>`__ Spartan6 xc6slx25 OK NT
arty `Digilent Digital Discovery <https://reference.digilentinc.com/test-and-measurement/digital-discovery/start>`__ Spartan6 xc6slx25 OK NT
basys3 `Digilent Basys3 <https://reference.digilentinc.com/reference/programmable-logic/basys-3/start>`__ Artix xc7a35tcpg236 OK OK
gatemate_evb_jtag `Cologne Chip GateMate FPGA Evaluation Board (JTAG mode) <https://colognechip.com/programmable-logic/gatemate/>`__ Cologne Chip GateMate Series OK OK
gatemate_evb_spi `Cologne Chip GateMate FPGA Evaluation Board (SPI mode) <https://colognechip.com/programmable-logic/gatemate/>`__ Cologne Chip GateMate Series OK OK
gatemate_pgm_spi `Cologne Chip GateMate FPGA Programmer (SPI mode) <https://colognechip.com/programmable-logic/gatemate/>`__ Cologne Chip GateMate Series OK OK
colorlight `Colorlight 5A-75B (version 7) <https://fr.aliexpress.com/item/32281130824.html>`__ ECP5 LFE5U-25F-6BG256C OK OK
colorlight_i5 `Colorlight I5 <https://www.colorlight-led.com/product/colorlight-i5-led-display-receiver-card.html>`__ ECP5 LFE5U-25F-6BG381C OK OK
crosslinknx_evn `Lattice CrossLink-NX Evaluation Board <https://www.latticesemi.com/en/Products/DevelopmentBoardsAndKits/CrossLink-NXEvaluationBoard>`__ Nexus LIFCL-40 OK OK

View File

@ -20,3 +20,4 @@ Cables
* `Tang Nano 4k USB-JTAG interface <https://github.com/sipeed/RV-Debugger-BL702>`__: USB-JTAG/UART debugger based on BL702 microcontroler.
* `Tigard <https://www.crowdsupply.com/securinghw/tigard>`__: SWD/JTAG/UART/SPI programmer based on Ftdi FT2232HQ
* `honeycomb USB-JTAG interface <https://github.com/Disasm/f042-ftdi>`__: FT2232C clone based on STM32F042 microcontroler
* `Cologne Chip GateMate FPGA Programmer <https://colognechip.com/programmable-logic/gatemate/>`__: FT232H-based JTAG/SPI programmer cable

View File

@ -3,32 +3,33 @@
FPGAs
#####
======== =================================================================================================================================== ====== =====
Vendor Model Memory Flash
======== =================================================================================================================================== ====== =====
Anlogic `EG4S20 <http://www.anlogic.com/prod_view.aspx?TypeId=10&Id=168&FId=t3:10:3>`__ OK OK
Anlogic `EF2M45 <http://www.anlogic.com/prod_view.aspx?TypeId=12&Id=170&FId=t3:12:3>`__ OK OK
Efinix `Trion T8 <https://www.efinixinc.com/products-trion.html>`__ NA OK
Gowin `GW1N (GW1N-1, GW1N-4, GW1NR-9, GW1NS-2C, GW1NSR-4C) <https://www.gowinsemi.com/en/product/detail/2/>`__ OK IF
Intel Cyclone III `EP3C16 <https://www.intel.com/content/www/us/en/programmable/products/fpga/cyclone-series/cyclone-iii/support.html>`__ OK OK
Intel Cyclone IV CE `EP4CE22 <https://www.intel.com/content/www/us/en/products/programmable/fpga/cyclone-iv/features.html>`__ OK OK
Intel Cyclone V E `5CEA2, 5CEBA4 <https://www.intel.com/content/www/us/en/products/programmable/fpga/cyclone-v.html>`__ OK OK
Intel Cyclone 10 LP `10CL025 <https://www.intel.com/content/www/us/en/products/programmable/fpga/cyclone-10.html>`__ OK OK
Lattice `CrossLink-NX (LIFCL-40) <https://www.latticesemi.com/en/Products/FPGAandCPLD/CrossLink-NX>`__ OK OK
Lattice `ECP5 (25F, 5G 85F) <http://www.latticesemi.com/Products/FPGAandCPLD/ECP5>`__ OK OK
Lattice `iCE40 (HX1K, HX4K, HX8K, UP5K) <https://www.latticesemi.com/en/Products/FPGAandCPLD/iCE40>`__ NA AS
Lattice `MachXO2 <https://www.latticesemi.com/en/Products/FPGAandCPLD/MachXO2>`__ OK OK
Lattice `MachXO3D <http://www.latticesemi.com/en/Products/FPGAandCPLD/MachXO3D.aspx>`__ OK OK
Lattice `MachXO3LF <http://www.latticesemi.com/en/Products/FPGAandCPLD/MachXO3.aspx>`__ OK OK
Xilinx Artix 7 `xc7a35ti, xc7a50t, xc7a75t, xc7a100t, xc7a200t <https://www.xilinx.com/products/silicon-devices/fpga/artix-7.html>`__ OK OK
Xilinx Kintex 7 `xc7k325t <https://www.xilinx.com/products/silicon-devices/fpga/kintex-7.html#productTable>`__ OK NT
Xilinx Spartan 3 `xc3s200 <https://www.xilinx.com/products/silicon-devices/fpga/spartan-3.html>`__ OK NA
Xilinx Spartan 6 `xc6slx9, xc6slx16, xc6slx25, xc6slx45 <https://www.xilinx.com/products/silicon-devices/fpga/spartan-6.html>`__ OK OK
Xilinx Spartan 7 `xc7s15, xc7s25, xc7s50 <https://www.xilinx.com/products/silicon-devices/fpga/spartan-7.html>`__ OK OK
Xilinx XC9500XL `xc9536xl, xc9572xl, xc95144xl, xc95188xl <https://www.xilinx.com/support/documentation/data_sheets/ds054.pdf>`__ NA OK
Xilinx XC2C (coolrunner II) `xc2c32a <https://www.xilinx.com/support/documentation/data_sheets/ds090.pdf>`__ TBD OK
Xilinx XCF `xcf01s, xcf02s, xcf04s <https://www.xilinx.com/products/silicon-devices/configuration-memory/platform-flash.html>`__ NA OK
======== =================================================================================================================================== ====== =====
============= =================================================================================================================================== ====== =====
Vendor Model Memory Flash
============= =================================================================================================================================== ====== =====
Anlogic `EG4S20 <http://www.anlogic.com/prod_view.aspx?TypeId=10&Id=168&FId=t3:10:3>`__ OK AS
Anlogic `EF2M45 <http://www.anlogic.com/prod_view.aspx?TypeId=12&Id=170&FId=t3:12:3>`__ OK OK
Cologne Chip `GateMate Series <https://colognechip.com/programmable-logic/gatemate/>`__ OK OK
Efinix `Trion T8 <https://www.efinixinc.com/products-trion.html>`__ NA OK
Gowin `GW1N (GW1N-1, GW1N-4, GW1NR-9, GW1NS-2C, GW1NSR-4C) <https://www.gowinsemi.com/en/product/detail/2/>`__ OK IF
Intel Cyclone III `EP3C16 <https://www.intel.com/content/www/us/en/programmable/products/fpga/cyclone-series/cyclone-iii/support.html>`__ OK OK
Intel Cyclone IV CE `EP4CE22 <https://www.intel.com/content/www/us/en/products/programmable/fpga/cyclone-iv/features.html>`__ OK OK
Intel Cyclone V E `5CEA2, 5CEBA4 <https://www.intel.com/content/www/us/en/products/programmable/fpga/cyclone-v.html>`__ OK OK
Intel Cyclone 10 LP `10CL025 <https://www.intel.com/content/www/us/en/products/programmable/fpga/cyclone-10.html>`__ OK OK
Lattice `CrossLink-NX (LIFCL-40) <https://www.latticesemi.com/en/Products/FPGAandCPLD/CrossLink-NX>`__ OK OK
Lattice `ECP5 (25F, 5G 85F) <http://www.latticesemi.com/Products/FPGAandCPLD/ECP5>`__ OK OK
Lattice `iCE40 (HX1K, HX4K, HX8K, UP5K) <https://www.latticesemi.com/en/Products/FPGAandCPLD/iCE40>`__ NA AS
Lattice `MachXO2 <https://www.latticesemi.com/en/Products/FPGAandCPLD/MachXO2>`__ OK OK
Lattice `MachXO3D <http://www.latticesemi.com/en/Products/FPGAandCPLD/MachXO3D.aspx>`__ OK OK
Lattice `MachXO3LF <http://www.latticesemi.com/en/Products/FPGAandCPLD/MachXO3.aspx>`__ OK OK
Xilinx Artix 7 `xc7a35ti, xc7a50t, xc7a75t, xc7a100t, xc7a200t <https://www.xilinx.com/products/silicon-devices/fpga/artix-7.html>`__ OK OK
Xilinx Kintex 7 `xc7k325t <https://www.xilinx.com/products/silicon-devices/fpga/kintex-7.html#productTable>`__ OK NT
Xilinx Spartan 3 `xc3s200 <https://www.xilinx.com/products/silicon-devices/fpga/spartan-3.html>`__ OK NA
Xilinx Spartan 6 `xc6slx9, xc6slx16, xc6slx25, xc6slx45 <https://www.xilinx.com/products/silicon-devices/fpga/spartan-6.html>`__ OK OK
Xilinx Spartan 7 `xc7s15, xc7s25, xc7s50 <https://www.xilinx.com/products/silicon-devices/fpga/spartan-7.html>`__ OK OK
Xilinx XC9500XL `xc9536xl, xc9572xl, xc95144xl, xc95188xl <https://www.xilinx.com/support/documentation/data_sheets/ds054.pdf>`__ NA OK
Xilinx XC2C (coolrunner II) `xc2c32a <https://www.xilinx.com/support/documentation/data_sheets/ds090.pdf>`__ TBD OK
Xilinx XCF `xcf01s, xcf02s, xcf04s <https://www.xilinx.com/products/silicon-devices/configuration-memory/platform-flash.html>`__ NA OK
============= =================================================================================================================================== ====== =====
* IF: Internal Flash
* AS: Active Serial flash mode

View File

@ -4,7 +4,7 @@ openFPGALoader: universal utility for programming FPGA
Welcome to the documentation of openFPGALoader!
openFPGALoader is a universal utility for programming FPGAs.
Compatible with many boards, cables and FPGA from major manufacturers (Xilinx, Altera/Intel, Lattice, Gowin, Efinix, Anlogic).
Compatible with many boards, cables and FPGA from major manufacturers (Xilinx, Altera/Intel, Lattice, Gowin, Efinix, Anlogic, Cologne Chip).
openFPGALoader works on Linux, Windows and macOS.
Not sure if your hardware is supported? Check the hardware compatibility lists:
@ -16,6 +16,7 @@ Not sure if your hardware is supported? Check the hardware compatibility lists:
Also checkout the vendor-specific documentation:
* `Anlogic <https://trabucayre.github.io/openFPGALoader/vendors/anlogic.html>`__
* `Cologne Chip <https://trabucayre.github.io/openFPGALoader/vendors/colognechip.html>`__
* `Efinix <https://trabucayre.github.io/openFPGALoader/vendors/efinix.html>`__
* `Gowin <https://trabucayre.github.io/openFPGALoader/vendors/gowin.html>`__
* `Intel/Altera <https://trabucayre.github.io/openFPGALoader/vendors/intel.html>`__
@ -44,6 +45,7 @@ Also checkout the vendor-specific documentation:
:hidden:
vendors/anlogic
vendors/colognechip
vendors/efinix
vendors/gowin
vendors/intel

95
doc/vendors/colognechip.rst vendored Normal file
View File

@ -0,0 +1,95 @@
.. _colognechip:
Cologne Chip notes
##################
Supported Boards/Cables
=======================
* GateMate Evaluation Board using board parameters ``-b gatemate_evb_jtag`` or ``-b gatemate_evb_spi``
* GateMate Programmer using cable parameter ``-c gatemate_pgm``
Programming Modes
=================
Supported configuration files are bitfiles ``*.bit`` and it's ASCII equivalents ``*.cfg``.
JTAG Configuration
------------------
Performs an active hardware reset and writes the configuration into the FPGA latches via JTAG. The configuration mode pins ``CFG_MD[3:0]`` must be set to 0xF0 (JTAG).
1. Program using Evaluation Board:
.. code-block:: bash
openFPGALoader -b gatemate_evb_jtag <bitfile>.cfg.bit
2. Program using Programmer Cable:
.. code-block:: bash
openFPGALoader -c gatemate_pgm <bitfile>.cfg.bit
SPI Configuration
-----------------
Performs an active hardware reset and writes the configuration into the FPGA latches via SPI. The configuration mode pins ``CFG_MD[3:0]`` must be set to 0x40 (SPI passive).
1. Program using Evaluation Board:
.. code-block:: bash
openFPGALoader -b gatemate_evb_spi <bitfile>.cfg.bit
2. Program using Programmer Cable:
.. code-block:: bash
openFPGALoader -b gatemate_pgm_spi <bitfile>.cfg.bit
JTAG Flash Access
-----------------
It is possible to access external flashes via the internal JTAG-SPI-bypass. The configuration mode pins ``CFG_MD[3:0]`` must be set to 0xF0 (JTAG). Note that the FPGA will not start automatically.
1. Write to flash using Evaluation Board:
.. code-block:: bash
openFPGALoader -b gatemate_evb_jtag <bitfile>.cfg.bit
2. Write to flash using Programmer Cable:
.. code-block:: bash
openFPGALoader -c gatemate_pgm -f <bitfile>.cfg.bit
The `offset` parameter can be used to store data at any point in the flash, e.g.:
.. code-block:: bash
openFPGALoader -b gatemate_evb_jtag -o <offset> <bitfile>.cfg.bit
SPI Flash Access
----------------
If the programming device and FPGA share the same SPI signals, it is possible to hold the FPGA in reset and write data to the flash. The configuration mode can be set as desired. If the FPGA should start from the external memory after reset, the configuration mode pins ``CFG_MD[3:0]`` set to 0x00 (SPI active).
1. Write to flash using Evaluation Board:
.. code-block:: bash
openFPGALoader -b gatemate_evb_spi -f <bitfile>.cfg.bit
2. Write to flash using Programmer Cable:
.. code-block:: bash
openFPGALoader -b gatemate_pgm_spi -f <bitfile>.cfg.bit
The `offset` parameter can be used to store data at any point in the flash, e.g.:
.. code-block:: bash
openFPGALoader -b gatemate_evb_spi -o <offset> <bitfile>.cfg.bit

View File

@ -120,6 +120,11 @@ static std::map <std::string, target_board_t> board_list = {
SPI_BOARD("fireant", "efinix", "ft232",
DBUS4, DBUS5, 0, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0, CABLE_DEFAULT),
DFU_BOARD("fomu", "", "dfu", 0x1209, 0x5bf0, 0),
SPI_BOARD("gatemate_pgm_spi", "colognechip", "gatemate_pgm",
DBUS4, DBUS5, CBUS0, DBUS3, DBUS0, DBUS1, DBUS2, 0, 0, CABLE_DEFAULT),
JTAG_BOARD("gatemate_evb_jtag", "", "gatemate_evb_jtag", 0, 0, CABLE_DEFAULT),
SPI_BOARD("gatemate_evb_spi", "colognechip", "gatemate_evb_spi",
DBUS4, DBUS5, CBUS0, DBUS3, DBUS0, DBUS1, DBUS2, 0, 0, CABLE_DEFAULT),
/* most ice40 boards uses the same pinout */
SPI_BOARD("ice40_generic", "lattice", "ft2232",
DBUS7, DBUS6, 0,

View File

@ -38,6 +38,9 @@ static std::map <std::string, cable_t> cable_list = {
{"bus_blaster_b", {MODE_FTDI_SERIAL, {0x0403, 0x6010, INTERFACE_B, 0x08, 0x0B, 0x08, 0x0B}}},
{"ch552_jtag", {MODE_FTDI_SERIAL, {0x0403, 0x6010, INTERFACE_A, 0x08, 0x0B, 0x08, 0x0B}}},
{"cmsisdap", {MODE_CMSISDAP, {0x0d28, 0x0204, 0, 0, 0, 0, 0 }}},
{"gatemate_pgm", {MODE_FTDI_SERIAL, {0x0403, 0x6014, INTERFACE_A, 0x10, 0x9B, 0x14, 0x17}}},
{"gatemate_evb_jtag", {MODE_FTDI_SERIAL, {0x0403, 0x6010, INTERFACE_A, 0x10, 0x1B, 0x00, 0x01}}},
{"gatemate_evb_spi", {MODE_FTDI_SERIAL, {0x0403, 0x6010, INTERFACE_B, 0x00, 0x1B, 0x00, 0x01}}},
{"dfu", {MODE_DFU, {}}},
{"digilent", {MODE_FTDI_SERIAL, {0x0403, 0x6010, INTERFACE_A, 0xe8, 0xeb, 0x00, 0x60}}},
{"digilent_b", {MODE_FTDI_SERIAL, {0x0403, 0x6010, INTERFACE_B, 0xe8, 0xeb, 0x00, 0x60}}},

419
src/colognechip.cpp Normal file
View File

@ -0,0 +1,419 @@
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright (C) 2021 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
* Copyright (C) 2021 Cologne Chip AG <support@colognechip.com>
*/
#include "colognechip.hpp"
#define JTAG_CONFIGURE 0x06
#define JTAG_SPI_BYPASS 0x05
#define SLEEP_US 500
CologneChip::CologneChip(FtdiSpi *spi, const std::string &filename,
const std::string &file_type, Device::prog_type_t prg_type,
uint16_t rstn_pin, uint16_t done_pin, uint16_t failn_pin, uint16_t oen_pin,
bool verify, int8_t verbose) :
Device(NULL, filename, file_type, verify, verbose), _rstn_pin(rstn_pin),
_done_pin(done_pin), _failn_pin(failn_pin), _oen_pin(oen_pin)
{
_spi = spi;
_spi->gpio_set_input(_done_pin | _failn_pin);
_spi->gpio_set_output(_rstn_pin | _oen_pin);
if (prg_type == Device::WR_SRAM) {
_mode = Device::MEM_MODE;
} else {
_mode = Device::FLASH_MODE;
}
}
CologneChip::CologneChip(Jtag* jtag, const std::string &filename,
const std::string &file_type, Device::prog_type_t prg_type,
const std::string &board_name, const std::string &cable_name,
bool verify, int8_t verbose) :
Device(jtag, filename, file_type, verify, verbose)
{
/* check which cable/board we're using in order to select pin definitions */
std::string spi_board_name;
if (board_name != "-") {
spi_board_name = std::regex_replace(board_name, std::regex("jtag"), "spi");
} else if (cable_name == "gatemate_pgm") {
spi_board_name = "gatemate_pgm_spi";
}
target_board_t *spi_board = &(board_list[spi_board_name]);
cable_t *spi_cable = &(cable_list[spi_board->cable_name]);
/* pin configurations valid for both evaluation board and programer */
_rstn_pin = spi_board->reset_pin;
_done_pin = spi_board->done_pin;
_failn_pin = DBUS6;
_oen_pin = spi_board->oe_pin;
/* cast _jtag->_jtag from JtagInterface to FtdiJtagMPSSE to access GPIO */
_ftdi_jtag = reinterpret_cast<FtdiJtagMPSSE *>(_jtag->_jtag);
_ftdi_jtag->gpio_set_input(_done_pin | _failn_pin);
_ftdi_jtag->gpio_set_output(_rstn_pin | _oen_pin);
if (prg_type == Device::WR_SRAM) {
_mode = Device::MEM_MODE;
} else {
_mode = Device::FLASH_MODE;
}
}
/**
* Enable outputs and hold FPGA in active hardware reset for SLEEP_US.
*/
void CologneChip::reset()
{
if (_spi) {
_spi->gpio_clear(_rstn_pin | _oen_pin);
usleep(SLEEP_US);
_spi->gpio_set(_rstn_pin);
} else if (_ftdi_jtag) {
_ftdi_jtag->gpio_clear(_rstn_pin | _oen_pin);
usleep(SLEEP_US);
_ftdi_jtag->gpio_set(_rstn_pin);
}
}
/**
* Obtain CFG_DONE and ~CFG_FAILED signals. Configuration is successfull iff
* CFG_DONE=true and ~CFG_FAILED=false.
*/
bool CologneChip::cfgDone()
{
uint16_t status = 0;
if (_spi) {
status = _spi->gpio_get(true);
} else if (_ftdi_jtag) {
status = _ftdi_jtag->gpio_get(true);
}
bool done = (status & _done_pin) > 0;
bool fail = (status & _failn_pin) == 0;
return (done && !fail);
}
/**
* Prints information if configuration was successfull.
*/
void CologneChip::waitCfgDone()
{
uint32_t timeout = 1000;
printInfo("Wait for CFG_DONE ", false);
do {
timeout--;
usleep(SLEEP_US);
} while (!cfgDone() && timeout > 0);
if (timeout == 0) {
printError("FAIL");
} else {
printSuccess("DONE");
}
}
/**
* Dump flash contents to file. Works in both SPI and JTAG-SPI-bypass mode.
*/
bool CologneChip::dumpFlash(const std::string &filename, uint32_t base_addr,
uint32_t len)
{
if (_spi) {
/* enable output and hold reset */
_spi->gpio_clear(_rstn_pin | _oen_pin);
} else if (_ftdi_jtag) {
/* enable output and disable reset */
_ftdi_jtag->gpio_clear(_oen_pin);
_ftdi_jtag->gpio_set(_rstn_pin);
}
/* prepare SPI access */
printInfo("Read Flash ", false);
try {
SPIFlash *flash;
if (_spi) {
flash = new SPIFlash(reinterpret_cast<SPIInterface *>(_spi), _verbose);
} else if (_ftdi_jtag) {
flash = new SPIFlash(this, _verbose);
}
flash->reset();
flash->power_up();
flash->dump(filename, base_addr, len);
} catch (std::exception &e) {
printError("Fail");
printError(std::string(e.what()));
return false;
}
if (_spi) {
/* disable output and release reset */
_spi->gpio_set(_rstn_pin | _oen_pin);
} else if (_ftdi_jtag) {
/* disable output */
_ftdi_jtag->gpio_set(_oen_pin);
}
usleep(SLEEP_US);
return true;
}
/**
* Parse bitstream from *.bit or *.cfg and program FPGA in SPI or JTAG mode
* or write configuration to external flash via SPI or JTAG-SPI-bypass.
*/
void CologneChip::program(unsigned int offset)
{
ConfigBitstreamParser *cfg;
if (_file_extension == "cfg") {
cfg = new CologneChipCfgParser(_filename);
} else if (_file_extension == "bit") {
cfg = new RawParser(_filename, false);
} else { /* unknown type: */
if (_mode == Device::FLASH_MODE) {
cfg = new RawParser(_filename, false);
} else {
throw std::runtime_error("incompatible file format");
}
}
cfg->parse();
uint8_t *data = cfg->getData();
int length = cfg->getLength() / 8;
switch (_mode) {
case Device::FLASH_MODE:
if (_jtag != NULL) {
programJTAG_flash(offset, data, length);
} else if (_jtag == NULL) {
programSPI_flash(offset, data, length);
}
break;
case Device::MEM_MODE:
if (_jtag != NULL) {
programJTAG_sram(data, length);
} else if (_jtag == NULL) {
programSPI_sram(data, length);
}
break;
}
}
/**
* Write configuration into FPGA latches via SPI after active reset.
* CFG_MD[3:0] must be set to 0x40 (SPI passive).
*/
void CologneChip::programSPI_sram(uint8_t *data, int length)
{
/* hold device in reset for a moment */
reset();
uint8_t *recv = new uint8_t[length];
_spi->gpio_set(_rstn_pin);
_spi->spi_put(data, recv, length); // TODO _spi->spi_put(data, null, length) does not work?
waitCfgDone();
_spi->gpio_set(_oen_pin);
delete [] recv;
}
/**
* Write configuration to flash via SPI while FPGA is in active reset. When
* done, release reset to start FPGA in active SPI mode (load from flash).
* CFG_MD[3:0] must be set to 0x00 (SPI active).
*/
void CologneChip::programSPI_flash(unsigned int offset, uint8_t *data, int length)
{
/* hold device in reset during flash write access */
_spi->gpio_clear(_rstn_pin | _oen_pin);
usleep(SLEEP_US);
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), _verbose);
flash.reset();
flash.power_up();
printf("%02x\n", flash.read_status_reg());
flash.read_id();
flash.erase_and_prog(offset, data, length);
/* verify write if required */
if (_verify)
flash.verify(offset, data, length);
_spi->gpio_set(_rstn_pin);
usleep(SLEEP_US);
waitCfgDone();
_spi->gpio_set(_oen_pin);
}
/**
* Write configuration into FPGA latches via JTAG after active reset.
* CFG_MD[3:0] must be set to 0xF0 (JTAG).
*/
void CologneChip::programJTAG_sram(uint8_t *data, int length)
{
/* hold device in reset for a moment */
reset();
_jtag->set_state(Jtag::RUN_TEST_IDLE);
uint8_t tmp[1024];
int size = 1024;
_jtag->shiftIR(JTAG_CONFIGURE, 6, Jtag::SELECT_DR_SCAN);
ProgressBar progress("Load SRAM via JTAG", length, 50, _quiet);
for (int i = 0; i < length; i += size) {
if (length < i + size)
size = length-i;
for (int ii = 0; ii < size; ii++)
tmp[ii] = data[i+ii];
_jtag->shiftDR(tmp, NULL, size*8, Jtag::SHIFT_DR);
progress.display(i);
}
progress.done();
_jtag->set_state(Jtag::RUN_TEST_IDLE);
waitCfgDone();
_ftdi_jtag->gpio_set(_oen_pin);
}
/**
* Write configuration to flash via JTAG-SPI-bypass. The FPGA will not start
* as it is in JTAG mode with CFG_MD[3:0] set to 0xF0 (JTAG).
*/
void CologneChip::programJTAG_flash(unsigned int offset, uint8_t *data, int length)
{
/* hold device in reset for a moment */
reset();
SPIFlash flash(this, _verbose);
flash.reset();
flash.power_up();
printf("%02x\n", flash.read_status_reg());
flash.read_id();
flash.erase_and_prog(offset, data, length);
/* verify write if required */
if (_verify)
flash.verify(offset, data, length);
_ftdi_jtag->gpio_set(_oen_pin);
}
/**
* Overrides spi_put() to access SPI components via JTAG-SPI-bypass.
*/
int CologneChip::spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, uint32_t len)
{
int xfer_len = len + 1;
uint8_t jtx[xfer_len+2];
uint8_t jrx[xfer_len+2];
jtx[0] = ConfigBitstreamParser::reverseByte(cmd);
if (tx != NULL) {
for (uint32_t i=0; i < len; i++)
jtx[i+1] = ConfigBitstreamParser::reverseByte(tx[i]);
}
_jtag->shiftIR(JTAG_SPI_BYPASS, 6, Jtag::SELECT_DR_SCAN);
int test = (rx == NULL) ? 8*xfer_len+1 : 8*xfer_len+2;
_jtag->shiftDR(jtx, (rx == NULL)? NULL: jrx, test, Jtag::SELECT_DR_SCAN);
if (rx != NULL) {
for (uint32_t i=0; i < len; i++) {
uint8_t b0 = ConfigBitstreamParser::reverseByte(jrx[i+1]);
uint8_t b1 = ConfigBitstreamParser::reverseByte(jrx[i+2]);
rx[i] = (b0 << 1) | ((b1 >> 7) & 0x01);
}
}
return 0;
}
/**
* Overrides spi_put() to access SPI components via JTAG-SPI-bypass.
*/
int CologneChip::spi_put(uint8_t *tx, uint8_t *rx, uint32_t len)
{
int xfer_len = len;
uint8_t jtx[xfer_len+2];
uint8_t jrx[xfer_len+2];
if (tx != NULL) {
for (uint32_t i=0; i < len; i++)
jtx[i] = ConfigBitstreamParser::reverseByte(tx[i]);
}
_jtag->shiftIR(JTAG_SPI_BYPASS, 6, Jtag::SELECT_DR_SCAN);
_jtag->shiftDR(jtx, (rx == NULL)? NULL: jrx, 8*xfer_len+1, Jtag::SELECT_DR_SCAN);
if (rx != NULL) {
for (uint32_t i=0; i < len; i++) {
uint8_t b0 = ConfigBitstreamParser::reverseByte(jrx[i]);
uint8_t b1 = ConfigBitstreamParser::reverseByte(jrx[i+1]);
rx[i] = (b0 << 1) | ((b1 >> 7) & 0x01);
}
}
return 0;
}
/**
* Overrides spi_put() to access SPI components via JTAG-SPI-bypass.
*/
int CologneChip::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
uint32_t timeout, bool verbose)
{
uint8_t rx[2];
uint8_t dummy[2];
uint8_t tmp;
uint8_t tx = ConfigBitstreamParser::reverseByte(cmd);
uint32_t count = 0;
_jtag->shiftIR(JTAG_SPI_BYPASS, 6, Jtag::SHIFT_DR);
_jtag->read_write(&tx, NULL, 8, 0);
do {
if (count == 0) {
_jtag->read_write(dummy, rx, 9, 0);
uint8_t b0 = ConfigBitstreamParser::reverseByte(rx[0]);
uint8_t b1 = ConfigBitstreamParser::reverseByte(rx[1]);
tmp = (b0 << 1) | ((b1 >> 7) & 0x01);
} else {
_jtag->read_write(dummy, rx, 8, 0);
tmp = ConfigBitstreamParser::reverseByte(rx[0]);
}
count++;
if (count == timeout) {
printf("timeout: %x %u\n", tmp, count);
break;
}
if (verbose) {
printf("%x %x %x %u\n", tmp, mask, cond, count);
}
} while ((tmp & mask) != cond);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
if (count == timeout) {
printf("%x\n", tmp);
std::cout << "wait: Error" << std::endl;
return -ETIME;
} else {
return 0;
}
}

64
src/colognechip.hpp Normal file
View File

@ -0,0 +1,64 @@
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright (C) 2021 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
* Copyright (C) 2021 Cologne Chip AG <support@colognechip.com>
*/
#ifndef SRC_COLOGNECHIP_HPP_
#define SRC_COLOGNECHIP_HPP_
#include <unistd.h>
#include <regex>
#include <string>
#include "device.hpp"
#include "jtag.hpp"
#include "ftdispi.hpp"
#include "ftdiJtagMPSSE.hpp"
#include "rawParser.hpp"
#include "colognechipCfgParser.hpp"
#include "spiFlash.hpp"
#include "progressBar.hpp"
class CologneChip: public Device, SPIInterface {
public:
CologneChip(FtdiSpi *spi, const std::string &filename,
const std::string &file_type, Device::prog_type_t prg_type,
uint16_t rstn_pin, uint16_t done_pin, uint16_t failn_pin, uint16_t oen_pin,
bool verify, int8_t verbose);
CologneChip(Jtag* jtag, const std::string &filename,
const std::string &file_type, Device::prog_type_t prg_type,
const std::string &board_name, const std::string &cable_name,
bool verify, int8_t verbose);
~CologneChip() {}
bool cfgDone();
void waitCfgDone();
bool dumpFlash(const std::string &filename, uint32_t base_addr, uint32_t len);
void program(unsigned int offset = 0) override;
int idCode() override {return 0;}
void reset() override;
private:
void programSPI_sram(uint8_t *data, int length);
void programSPI_flash(unsigned int offset, uint8_t *data, int length);
void programJTAG_sram(uint8_t *data, int length);
void programJTAG_flash(unsigned int offset, uint8_t *data, int length);
/* spi interface via jtag */
int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx,
uint32_t len) override;
int spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) override;
int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond, uint32_t timeout,
bool verbose=false) override;
FtdiSpi *_spi = NULL;
FtdiJtagMPSSE *_ftdi_jtag = NULL;
uint16_t _rstn_pin;
uint16_t _done_pin;
uint16_t _failn_pin;
uint16_t _oen_pin;
};
#endif // SRC_COLOGNECHIP_HPP_

View File

@ -0,0 +1,31 @@
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright (C) 2021 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
* Copyright (C) 2021 Cologne Chip AG <support@colognechip.com>
*/
#include <sstream>
#include "colognechipCfgParser.hpp"
CologneChipCfgParser::CologneChipCfgParser(const std::string &filename):
ConfigBitstreamParser(filename, ConfigBitstreamParser::ASCII_MODE,
false)
{}
int CologneChipCfgParser::parse()
{
std::string buffer;
std::istringstream lineStream(_raw_data);
while (std::getline(lineStream, buffer, '\n')) {
std::string val = buffer.substr(0, buffer.find("//"));
val.erase(std::remove_if(val.begin(), val.end(), ::isspace), val.end());
if (val != "") {
_bit_data += std::stol(val, nullptr, 16);
}
}
_bit_length = _bit_data.size() * 8;
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,22 @@
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright (C) 2021 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
* Copyright (C) 2021 Cologne Chip AG <support@colognechip.com>
*/
#ifndef SRC_COLOGNECHIPCFGPARSER_HPP_
#define SRC_COLOGNECHIPCFGPARSER_HPP_
#include <string>
#include <algorithm>
#include "configBitstreamParser.hpp"
class CologneChipCfgParser: public ConfigBitstreamParser {
public:
CologneChipCfgParser(const std::string &filename);
int parse() override;
};
#endif // SRC_COLOGNECHIPCFGPARSER_HPP_

View File

@ -20,7 +20,7 @@
* \author Gwenhael Goavec-Merou
*/
class FtdiJtagMPSSE : public JtagInterface, private FTDIpp_MPSSE {
class FtdiJtagMPSSE : public JtagInterface, public FTDIpp_MPSSE {
public:
FtdiJtagMPSSE(const FTDIpp_MPSSE::mpsse_bit_config &cable, std::string dev,
const std::string &serial, uint32_t clkHZ, uint8_t verbose = 0);

View File

@ -136,7 +136,13 @@ int Jtag::detectChain(int max_dev)
for (int ii=0; ii < 4; ii++)
tmp |= (rx_buff[ii] << (8*ii));
if (tmp != 0 && tmp != 0xffffffff) {
tmp &= 0x0fffffff;
/* ckeck highest nibble to prevent confusion between Cologne Chip
* GateMate and Efinix Trion T4/T8 devices
*/
if (tmp != 0x20000001)
tmp &= 0x0fffffff;
else
tmp &= 0xffffffff;
_devices_list.insert(_devices_list.begin(), tmp);
/* search for irlength in fpga_list or misc_dev_list */

View File

@ -92,6 +92,8 @@ class Jtag {
/* utilities */
void setVerbose(int8_t verbose){_verbose = verbose;}
JtagInterface *_jtag;
private:
void init_internal(cable_t &cable, const std::string &dev, const std::string &serial,
const jtag_pins_conf_t *pin_conf, uint32_t clkHZ,
@ -102,7 +104,6 @@ class Jtag {
int _num_tms;
unsigned char *_tms_buffer;
std::string _board_name;
JtagInterface *_jtag;
int device_index; /*!< index for targeted FPGA */
std::vector<int32_t> _devices_list; /*!< ordered list of devices idcode */

View File

@ -16,6 +16,7 @@
#include "anlogic.hpp"
#include "board.hpp"
#include "cable.hpp"
#include "colognechip.hpp"
#include "device.hpp"
#include "dfu.hpp"
#include "display.hpp"
@ -227,6 +228,19 @@ int main(int argc, char **argv)
} else {
target.program(args.offset);
}
} else if (board->manufacturer == "colognechip") {
CologneChip target(spi, args.bit_file, args.file_type, args.prg_type,
board->reset_pin, board->done_pin, DBUS6, board->oe_pin,
args.verify, args.verbose);
if (args.prg_type == Device::RD_FLASH) {
if (args.file_size == 0) {
printError("Error: 0 size for dump");
} else {
target.dumpFlash(args.bit_file, args.offset, args.file_size);
}
} else {
target.program(args.offset);
}
} else {
RawParser *bit = NULL;
if (board->reset_pin) {
@ -443,6 +457,9 @@ int main(int argc, char **argv)
} else if (fab == "lattice") {
fpga = new Lattice(jtag, args.bit_file, args.file_type,
args.prg_type, args.flash_sector, args.verify, args.verbose);
} else if (fab == "colognechip") {
fpga = new CologneChip(jtag, args.bit_file, args.file_type,
args.prg_type, args.board, args.cable, args.verify, args.verbose);
} else {
printError("Error: manufacturer " + fab + " not supported");
delete(jtag);

View File

@ -108,6 +108,9 @@ static std::map <int, fpga_model> fpga_list = {
{0x0100381B, {"Gowin", "GW1N", "GW1N-4", 8}},
{0x0300181b, {"Gowin", "GW1NS", "GW1NS-2C", 8}},
{0x0100981b, {"Gowin", "GW1NSR", "GW1NSR-4C", 8}},
/* keep highest nibble to prevent confusion with Efinix T4/T8 IDCODE */
{0x20000001, {"colognechip", "GateMate Series", "GM1Ax", 6}},
};
/* device potentially in JTAG chain but not handled */