pld: add support for cologne chip gatemate fpgas
Change-Id: I0bf5a52ee6a7f0287524619114eba0cfccf6ac81 Signed-off-by: Daniel Anselmi <danselmi@gmx.ch> Reviewed-on: https://review.openocd.org/c/openocd/+/7565 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
parent
4b56c73ef3
commit
682f927f8e
|
@ -8566,6 +8566,12 @@ The files @verb{|.fs|} and @verb{|.bin|} generated by Gowin FPGA Designer are su
|
||||||
@end deffn
|
@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
|
@node General Commands
|
||||||
@chapter General Commands
|
@chapter General Commands
|
||||||
@cindex commands
|
@cindex commands
|
||||||
|
|
|
@ -6,6 +6,7 @@ noinst_LTLIBRARIES += %D%/libpld.la
|
||||||
%D%/ecp2_3.c \
|
%D%/ecp2_3.c \
|
||||||
%D%/ecp5.c \
|
%D%/ecp5.c \
|
||||||
%D%/efinix.c \
|
%D%/efinix.c \
|
||||||
|
%D%/gatemate.c \
|
||||||
%D%/gowin.c \
|
%D%/gowin.c \
|
||||||
%D%/intel.c \
|
%D%/intel.c \
|
||||||
%D%/lattice.c \
|
%D%/lattice.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 <jtag/jtag.h>
|
||||||
|
#include <jtag/adapter.h>
|
||||||
|
#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,
|
||||||
|
};
|
|
@ -19,6 +19,7 @@
|
||||||
/* pld drivers
|
/* pld drivers
|
||||||
*/
|
*/
|
||||||
extern struct pld_driver efinix_pld;
|
extern struct pld_driver efinix_pld;
|
||||||
|
extern struct pld_driver gatemate_pld;
|
||||||
extern struct pld_driver gowin_pld;
|
extern struct pld_driver gowin_pld;
|
||||||
extern struct pld_driver intel_pld;
|
extern struct pld_driver intel_pld;
|
||||||
extern struct pld_driver lattice_pld;
|
extern struct pld_driver lattice_pld;
|
||||||
|
@ -26,6 +27,7 @@ extern struct pld_driver virtex2_pld;
|
||||||
|
|
||||||
static struct pld_driver *pld_drivers[] = {
|
static struct pld_driver *pld_drivers[] = {
|
||||||
&efinix_pld,
|
&efinix_pld,
|
||||||
|
&gatemate_pld,
|
||||||
&gowin_pld,
|
&gowin_pld,
|
||||||
&intel_pld,
|
&intel_pld,
|
||||||
&lattice_pld,
|
&lattice_pld,
|
||||||
|
|
|
@ -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]
|
|
@ -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
|
Loading…
Reference in New Issue