From 682f927f8e4e6c6216c6d0b259b3c24b9f3f6342 Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Fri, 24 Feb 2023 15:57:30 +0100 Subject: [PATCH] pld: add support for cologne chip gatemate fpgas Change-Id: I0bf5a52ee6a7f0287524619114eba0cfccf6ac81 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7565 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 6 + src/pld/Makefile.am | 1 + src/pld/gatemate.c | 241 ++++++++++++++++++++++++++++++++++++ src/pld/pld.c | 2 + tcl/board/gatemate_eval.cfg | 16 +++ tcl/fpga/gatemate.cfg | 16 +++ 6 files changed, 282 insertions(+) create mode 100644 src/pld/gatemate.c create mode 100644 tcl/board/gatemate_eval.cfg create mode 100644 tcl/fpga/gatemate.cfg diff --git a/doc/openocd.texi b/doc/openocd.texi index cea02bd542..f32ef34756 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8566,6 +8566,12 @@ The files @verb{|.fs|} and @verb{|.bin|} generated by Gowin FPGA Designer are su @end deffn +@deffn {FPGA Driver} {gatemate} +This driver can be used to load the bitstream into GateMate FPGAs form CologneChip. +The files @verb{|.bit|} and @verb{|.cfg|} both generated by p_r tool from CologneChip are supported. +@end deffn + + @node General Commands @chapter General Commands @cindex commands diff --git a/src/pld/Makefile.am b/src/pld/Makefile.am index 22ae9fd208..69e457c96a 100644 --- a/src/pld/Makefile.am +++ b/src/pld/Makefile.am @@ -6,6 +6,7 @@ noinst_LTLIBRARIES += %D%/libpld.la %D%/ecp2_3.c \ %D%/ecp5.c \ %D%/efinix.c \ + %D%/gatemate.c \ %D%/gowin.c \ %D%/intel.c \ %D%/lattice.c \ diff --git a/src/pld/gatemate.c b/src/pld/gatemate.c new file mode 100644 index 0000000000..afd27efca4 --- /dev/null +++ b/src/pld/gatemate.c @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "pld.h" +#include "raw_bit.h" + +#define JTAG_CONFIGURE 0x06 + +struct gatemate_pld_device { + struct jtag_tap *tap; +}; + +struct gatemate_bit_file { + struct raw_bit_file raw_file; + size_t capacity; +}; + +static int gatemate_add_byte_to_bitfile(struct gatemate_bit_file *bit_file, uint8_t byte) +{ + const size_t chunk_size = 8192; + if (bit_file->raw_file.length + 1 > bit_file->capacity) { + uint8_t *buffer; + if (bit_file->raw_file.data) + buffer = realloc(bit_file->raw_file.data, bit_file->capacity + chunk_size); + else + buffer = malloc(chunk_size); + if (!buffer) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + bit_file->raw_file.data = buffer; + bit_file->capacity += chunk_size; + } + + bit_file->raw_file.data[bit_file->raw_file.length++] = byte; + + return ERROR_OK; +} + +static int gatemate_read_cfg_line(struct gatemate_bit_file *bit_file, const char *line_buffer, size_t nread) +{ + for (size_t idx = 0; idx < nread; ++idx) { + if (line_buffer[idx] == ' ') { + continue; + } else if (line_buffer[idx] == 0) { + break; + } else if (idx + 1 < nread) { + if (isxdigit(line_buffer[idx]) && isxdigit(line_buffer[idx + 1])) { + uint8_t byte; + unhexify(&byte, line_buffer + idx, 2); + int retval = gatemate_add_byte_to_bitfile(bit_file, byte); + if (retval != ERROR_OK) + return retval; + } else if (line_buffer[idx] == '/' && line_buffer[idx + 1] == '/') { + break; + } + ++idx; + } else { + LOG_ERROR("parsing failed"); + return ERROR_FAIL; + } + } + return ERROR_OK; +} + +static int gatemate_getline(char **buffer, size_t *buf_size, FILE *input_file) +{ + const size_t chunk_size = 32; + if (!*buffer) + *buf_size = 0; + + size_t read = 0; + do { + if (read + 1 > *buf_size) { + char *new_buffer; + if (*buffer) + new_buffer = realloc(*buffer, *buf_size + chunk_size); + else + new_buffer = malloc(chunk_size); + if (!new_buffer) { + LOG_ERROR("Out of memory"); + return -1; + } + *buffer = new_buffer; + *buf_size += chunk_size; + } + + int c = fgetc(input_file); + if ((c == EOF && read) || (char)c == '\n') { + (*buffer)[read++] = 0; + return read; + } else if (c == EOF) { + return -1; + } + + (*buffer)[read++] = (char)c; + } while (1); + + return -1; +} + +static int gatemate_read_cfg_file(struct gatemate_bit_file *bit_file, const char *filename) +{ + FILE *input_file = fopen(filename, "r"); + + if (!input_file) { + LOG_ERROR("Couldn't open %s: %s", filename, strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + int retval = ERROR_OK; + char *line_buffer = NULL; + size_t buffer_length = 0; + int nread; + while (((nread = gatemate_getline(&line_buffer, &buffer_length, input_file)) != -1) && (retval == ERROR_OK)) + retval = gatemate_read_cfg_line(bit_file, line_buffer, (size_t)nread); + + if (line_buffer) + free(line_buffer); + + fclose(input_file); + if (retval != ERROR_OK) + free(bit_file->raw_file.data); + return retval; +} + +static int gatemate_read_file(struct gatemate_bit_file *bit_file, const char *filename) +{ + memset(bit_file, 0, sizeof(struct gatemate_bit_file)); + + if (!filename || !bit_file) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* check if binary .bit or ascii .cfg */ + const char *file_suffix_pos = strrchr(filename, '.'); + if (!file_suffix_pos) { + LOG_ERROR("Unable to detect filename suffix"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (strcasecmp(file_suffix_pos, ".bit") == 0) + return cpld_read_raw_bit_file(&bit_file->raw_file, filename); + else if (strcasecmp(file_suffix_pos, ".cfg") == 0) + return gatemate_read_cfg_file(bit_file, filename); + + LOG_ERROR("Filetype not supported, expecting .bit or .cfg file"); + return ERROR_PLD_FILE_LOAD_FAILED; +} + +static int gatemate_set_instr(struct jtag_tap *tap, uint8_t new_instr) +{ + struct scan_field field; + field.num_bits = tap->ir_length; + void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + field.out_value = t; + buf_set_u32(t, 0, field.num_bits, new_instr); + field.in_value = NULL; + jtag_add_ir_scan(tap, &field, TAP_IDLE); + jtag_add_runtest(3, TAP_IDLE); + free(t); + return ERROR_OK; +} + +static int gatemate_load(struct pld_device *pld_device, const char *filename) +{ + if (!pld_device) + return ERROR_FAIL; + + struct gatemate_pld_device *gatemate_info = pld_device->driver_priv; + + if (!gatemate_info || !gatemate_info->tap) + return ERROR_FAIL; + struct jtag_tap *tap = gatemate_info->tap; + + struct gatemate_bit_file bit_file; + int retval = gatemate_read_file(&bit_file, filename); + if (retval != ERROR_OK) + return retval; + + retval = gatemate_set_instr(tap, JTAG_CONFIGURE); + if (retval != ERROR_OK) + return retval; + + struct scan_field field; + field.num_bits = bit_file.raw_file.length * 8; + field.out_value = bit_file.raw_file.data; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + + retval = jtag_execute_queue(); + free(bit_file.raw_file.data); + + return retval; +} + +PLD_DEVICE_COMMAND_HANDLER(gatemate_pld_device_command) +{ + struct jtag_tap *tap; + + struct gatemate_pld_device *gatemate_info; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + tap = jtag_tap_by_string(CMD_ARGV[1]); + if (!tap) { + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]); + return ERROR_FAIL; + } + + gatemate_info = malloc(sizeof(struct gatemate_pld_device)); + if (!gatemate_info) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + gatemate_info->tap = tap; + + pld->driver_priv = gatemate_info; + + return ERROR_OK; +} + +struct pld_driver gatemate_pld = { + .name = "gatemate", + .pld_device_command = &gatemate_pld_device_command, + .load = &gatemate_load, +}; diff --git a/src/pld/pld.c b/src/pld/pld.c index d9e01f16cd..dd8f8263fe 100644 --- a/src/pld/pld.c +++ b/src/pld/pld.c @@ -19,6 +19,7 @@ /* pld drivers */ extern struct pld_driver efinix_pld; +extern struct pld_driver gatemate_pld; extern struct pld_driver gowin_pld; extern struct pld_driver intel_pld; extern struct pld_driver lattice_pld; @@ -26,6 +27,7 @@ extern struct pld_driver virtex2_pld; static struct pld_driver *pld_drivers[] = { &efinix_pld, + &gatemate_pld, &gowin_pld, &intel_pld, &lattice_pld, diff --git a/tcl/board/gatemate_eval.cfg b/tcl/board/gatemate_eval.cfg new file mode 100644 index 0000000000..cc078a0e30 --- /dev/null +++ b/tcl/board/gatemate_eval.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# GateMateTM FPGA Evaluation Board +# https://www.colognechip.com/programmable-logic/gatemate-evaluation-board/ +# + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 + +ftdi channel 0 +ftdi layout_init 0x0014 0x011b +reset_config none +transport select jtag +adapter speed 6000 + +source [find fpga/gatemate.cfg] diff --git a/tcl/fpga/gatemate.cfg b/tcl/fpga/gatemate.cfg new file mode 100644 index 0000000000..cc19fd4c20 --- /dev/null +++ b/tcl/fpga/gatemate.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# GateMateTM FPGA +# https://www.colognechip.com/programmable-logic/gatemate/ +# https://colognechip.com/docs/ds1001-gatemate1-datasheet-latest.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME gatemate +} + +jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ + -expected-id 0x20000001 + +pld device gatemate $_CHIPNAME.tap -- 2.30.2