Hello, this is a patch to add a bus driver for the AHBJTAG core in grlib/leon3 systems. It allows to make 32-bit single and burst accesses on the AHBÂ bus in a grlib SOC. I have been using it with FT2232 cables for about a year and it works well without any issues.
Jiri.
From b1cefaed561204d6caf7e656f541d4e76284a40c Mon Sep 17 00:00:00 2001 From: Jiri Gaisler <j...@gaisler.se> Date: Mon, 19 Mar 2018 16:01:38 +0100 Subject: [PATCH 1/1] Add bus driver for the GRLIB AHBJTAG debug interface. * Used mainly for LEON3/4 processors. * See www.gaisler.com for details. --- urjtag/ChangeLog | 3 + urjtag/MAINTAINERS | 5 + urjtag/configure.ac | 1 + urjtag/src/bus/Makefile.am | 4 + urjtag/src/bus/ahbjtag.c | 333 ++++++++++++++++++++++++++++++++++++ urjtag/src/bus/buses_list.h | 3 + 6 files changed, 349 insertions(+) create mode 100644 urjtag/src/bus/ahbjtag.c diff --git a/urjtag/ChangeLog b/urjtag/ChangeLog index 15fa4ecb..e34aabb6 100644 --- a/urjtag/ChangeLog +++ b/urjtag/ChangeLog @@ -1,3 +1,6 @@ +2019-12-03 Jiri Gaisler <j...@gaisler.se> + * src/bus/ahbjtag.c: New file. Implements bus driver for GRLIB AHBJTAG core. + 2019-11-25 Alexander Voropay <a...@sensi.org> * git log hash as version number diff --git a/urjtag/MAINTAINERS b/urjtag/MAINTAINERS index 7caa5157..58d80c1e 100644 --- a/urjtag/MAINTAINERS +++ b/urjtag/MAINTAINERS @@ -21,6 +21,11 @@ S: Status, one of the following: it has been replaced by a better system and you should be using that. +AHBJTAG FPGA JTAG MEMORY BUS DRIVER +M: Jiri Gaisler <j...@gaisler.se> +F: src/bus/ahbjtag.c +S: Maintained + ALTERA UP3 EDUCATION KIT BUS DRIVER F: src/bus/slsup3.c diff --git a/urjtag/configure.ac b/urjtag/configure.ac index 7f348bb1..e0a5085d 100644 --- a/urjtag/configure.ac +++ b/urjtag/configure.ac @@ -619,6 +619,7 @@ m4_ifnblank([$3], [ # Enable bus drivers URJ_DRIVER_SET([bus], [ + ahbjtag arm9tdmi au1500 avr32 diff --git a/urjtag/src/bus/Makefile.am b/urjtag/src/bus/Makefile.am index b16812e8..3a082439 100644 --- a/urjtag/src/bus/Makefile.am +++ b/urjtag/src/bus/Makefile.am @@ -35,6 +35,10 @@ libbus_la_SOURCES = \ readmem.c \ writemem.c +if ENABLE_BUS_AHBJTAG +libbus_la_SOURCES += ahbjtag.c +endif + if ENABLE_BUS_ARM9TDMI libbus_la_SOURCES += arm9tdmi.c endif diff --git a/urjtag/src/bus/ahbjtag.c b/urjtag/src/bus/ahbjtag.c new file mode 100644 index 00000000..5c19878d --- /dev/null +++ b/urjtag/src/bus/ahbjtag.c @@ -0,0 +1,333 @@ +/* + * $Id$ + * + * Bus driver for the GRLIB AHBJTAG core. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Jiri Gaisler <j...@gaisler.se>, 2018. + * Based on fjmem.c + * + */ + +#include <sysdep.h> + +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include <urjtag/log.h> +#include <urjtag/part.h> +#include <urjtag/bus.h> +#include <urjtag/chain.h> +#include <urjtag/cmd.h> +#include <urjtag/tap.h> +#include <urjtag/data_register.h> +#include <urjtag/tap_register.h> +#include <urjtag/part_instruction.h> + +#include "buses.h" +#include "generic_bus.h" + +#undef DEBUG + +#define AHBJTAG_ADDR_NAME "AINST" +#define AHBJTAG_AREG_NAME "ADDR" +#define AHBJTAG_DATA_NAME "DINST" +#define AHBJTAG_DREG_NAME "DATA" +#define AHBJTAG_MAX_REG_LEN 40 + +typedef struct +{ + urj_data_register_t *ahbjtag_areg; + urj_data_register_t *ahbjtag_dreg; +} bus_params_t; + +#define AHBJTAG_AREG ((bus_params_t *) bus->params)->ahbjtag_areg +#define AHBJTAG_DREG ((bus_params_t *) bus->params)->ahbjtag_dreg + +static uint32_t next_waddr = 0; +static uint32_t read_addr = 0; + +/** + * bus->driver->(*new_bus) + * + */ +static urj_bus_t * +ahbjtag_bus_new (urj_chain_t *chain, const urj_bus_driver_t *driver, + const urj_param_t *params[]) +{ + urj_bus_t *bus = NULL; + urj_part_t *part; + + bus = urj_bus_generic_new (chain, driver, sizeof (bus_params_t)); + if (bus == NULL) + return NULL; + part = bus->part; + + urj_part_instruction_length_set (part, chain->total_instr_len); + urj_part_data_register_define (part, "ADDR", 35); + urj_part_instruction_define (part, "AINST", "000010", "ADDR"); + urj_part_data_register_define (part, "DATA", 33); + urj_part_instruction_define (part, "DINST", "000011", "DATA"); + + AHBJTAG_AREG = urj_part_find_data_register (part, AHBJTAG_AREG_NAME); + AHBJTAG_DREG = urj_part_find_data_register (part, AHBJTAG_DREG_NAME); + + return bus; +} + + +/** + * bus->driver->(*free_bus) + * + */ +static void +ahbjtag_bus_free (urj_bus_t *bus) +{ + urj_data_register_t *dr = AHBJTAG_AREG; + + /* fill all fields with '0' + -> prepare idle instruction for next startup/detect */ + urj_part_set_instruction (bus->part, AHBJTAG_ADDR_NAME); + urj_tap_chain_shift_instructions (bus->chain); + + urj_tap_register_fill (dr->in, 0); + urj_tap_chain_shift_data_registers (bus->chain, 0); + + urj_bus_generic_free (bus); +} + +/** + * bus->driver->(*printinfo) + * + */ +static void +ahbjtag_bus_printinfo (urj_log_level_t ll, urj_bus_t *bus) +{ + int i; + + for (i = 0; i < bus->chain->parts->len; i++) + if (bus->part == bus->chain->parts->parts[i]) + break; + urj_log (ll, _("GRLIB AHB driver via USER registers (JTAG part No. %d)\n"), + i); +} + +/** + * bus->driver->(*prepare) + * + */ +static void +ahbjtag_bus_prepare (urj_bus_t *bus) +{ + if (!bus->initialized) + URJ_BUS_INIT (bus); + + /* ensure AHBJTAG_ADDR is active */ + urj_part_set_instruction (bus->part, AHBJTAG_ADDR_NAME); + urj_tap_chain_shift_instructions (bus->chain); +} + +static int +block_bus_area (urj_bus_t *bus, uint32_t adr, urj_bus_area_t *area) +{ + area->description = NULL; + area->start = 0; + area->length = 0xfffffffc; + area->width = 32; + return URJ_STATUS_OK; +} + +/** + * bus->driver->(*area) + * + */ +static int +ahbjtag_bus_area (urj_bus_t *bus, uint32_t adr, urj_bus_area_t *area) +{ + + return block_bus_area (bus, adr, area); +} + +static void +setup_address_data (urj_bus_t *bus, uint32_t ad, urj_data_register_t *dr) +{ + int idx; + + /* set address/data */ + for (idx = 0; idx < 32; idx++) + { + dr->in->data[idx] = ad & 1; + ad >>= 1; + } +} + +/** + * bus->driver->(*read_start) + * + */ +static int +ahbjtag_bus_read_start (urj_bus_t *bus, uint32_t adr) +{ + urj_chain_t *chain = bus->chain; + urj_data_register_t *dr = AHBJTAG_AREG; + + urj_part_set_instruction (bus->part, AHBJTAG_ADDR_NAME); + urj_tap_chain_shift_instructions (bus->chain); + setup_address_data (bus, adr, dr); + /* select read instruction */ + dr->in->data[32] = 0; + dr->in->data[33] = 1; + dr->in->data[34] = 0; + + urj_tap_chain_shift_data_registers (chain, 0); + next_waddr = 0; + read_addr = adr; + + return URJ_STATUS_OK; +} + +/** + * bus->driver->(*read_next) + * + */ +static uint32_t +ahbjtag_bus_read_next (urj_bus_t *bus, uint32_t adr) +{ + urj_chain_t *chain = bus->chain; + urj_data_register_t *dr = AHBJTAG_DREG; + uint32_t d; + int idx; + + urj_part_set_instruction (bus->part, AHBJTAG_DATA_NAME); + urj_tap_chain_shift_instructions (bus->chain); + setup_address_data (bus, 0, dr); + if ((adr & 0x3fc) != 0x3fc) + dr->in->data[32] = 1; // auto-increment address + else + dr->in->data[32] = 0; // no auto-increment over 1 Kbyte boundary + urj_tap_chain_shift_data_registers (chain, 1); + + /* extract data from TDO stream */ + d = 0; + for (idx = 0; idx < 32; idx++) + if (dr->out->data[idx]) + d |= 1 << idx; + + /* reload address if at the end of a 1 Kbyte block */ + if ((adr & 0x3fc) == 0x3fc) + ahbjtag_bus_read_start (bus, adr + 4); + + urj_log (URJ_LOG_LEVEL_DETAIL, _("ahbjtag read : 0x%08x : 0x%08x\n"), adr, d); + read_addr = adr + 4; + + return d; +} + +/** + * bus->driver->(*read_end) + * + */ +static uint32_t +ahbjtag_bus_read_end (urj_bus_t *bus) +{ + urj_chain_t *chain = bus->chain; + urj_data_register_t *dr = AHBJTAG_DREG; + uint32_t d; + int idx; + + urj_part_set_instruction (bus->part, AHBJTAG_DATA_NAME); + urj_tap_chain_shift_instructions (bus->chain); + dr->in->data[32] = 0; // cancel auto-increment address + + urj_tap_chain_shift_data_registers (chain, 1); + + /* extract data from TDO stream */ + d = 0; + for (idx = 0; idx < 32; idx++) + if (dr->out->data[idx]) + d |= 1 << idx; + + urj_log (URJ_LOG_LEVEL_DETAIL, _("ahbjtag read : 0x%08x : 0x%08x\n"), read_addr, d); + return d; +} + +/** + * bus->driver->(*write) + * + */ +static void +ahbjtag_bus_write (urj_bus_t *bus, uint32_t adr, uint32_t data) +{ + urj_chain_t *chain = bus->chain; + urj_data_register_t *dr = AHBJTAG_AREG; + + urj_log (URJ_LOG_LEVEL_DETAIL, _("ahbjtag write: 0x%08x : 0x%08x\n"), adr, data); + + if ((next_waddr != adr) || ((adr & 0x3fc) == 0)) + { + urj_part_set_instruction (bus->part, AHBJTAG_ADDR_NAME); + urj_tap_chain_shift_instructions (bus->chain); + setup_address_data (bus, adr, dr); + + /* select write instruction */ + dr->in->data[34] = 1; + dr->in->data[33] = 1; + dr->in->data[32] = 0; + + urj_tap_chain_shift_data_registers (chain, 0); + } + + dr = AHBJTAG_DREG; + + urj_part_set_instruction (bus->part, AHBJTAG_DATA_NAME); + urj_tap_chain_shift_instructions (bus->chain); + setup_address_data (bus, data, dr); + dr->in->data[32] = 1; // auto-increment + + urj_tap_chain_shift_data_registers (chain, 1); + next_waddr = adr + 4; +} + +const urj_bus_driver_t urj_bus_ahbjtag_bus = { + "ahbjtag", + N_("GRLIB AHBJTAG driver via USER registers 2 & 3\n"), + ahbjtag_bus_new, + ahbjtag_bus_free, + ahbjtag_bus_printinfo, + ahbjtag_bus_prepare, + ahbjtag_bus_area, + ahbjtag_bus_read_start, + ahbjtag_bus_read_next, + ahbjtag_bus_read_end, + urj_bus_generic_read, + urj_bus_generic_write_start, + ahbjtag_bus_write, + urj_bus_generic_no_init, + urj_bus_generic_no_enable, + urj_bus_generic_no_disable, + URJ_BUS_TYPE_PARALLEL, +}; + + +/* + Local Variables: + mode:C + tab-width:2 + indent-tabs-mode:t + End: +*/ diff --git a/urjtag/src/bus/buses_list.h b/urjtag/src/bus/buses_list.h index 858da572..aaaacc91 100644 --- a/urjtag/src/bus/buses_list.h +++ b/urjtag/src/bus/buses_list.h @@ -27,6 +27,9 @@ * Please keep this list sorted alphabetically */ +#ifdef ENABLE_BUS_AHBJTAG +_URJ_BUS(ahbjtag) +#endif #ifdef ENABLE_BUS_ARM9TDMI _URJ_BUS(arm9tdmi) #endif -- 2.17.1
_______________________________________________ UrJTAG-development mailing list UrJTAG-development@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/urjtag-development