From 4aa24728f9fde2896434b3908fcb9e90ea0dbbb9 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Tue, 26 Jan 2010 09:44:38 +0000 Subject: [PATCH] Add Blackfin commands. git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@1733 b68d4a1b-bc3d-0410-92ed-d4ac073336b7 --- urjtag/ChangeLog | 37 + urjtag/configure.ac | 1 + urjtag/include/urjtag/Makefile.am | 1 + urjtag/include/urjtag/bfin.h | 367 ++++++ urjtag/include/urjtag/chain.h | 1 + urjtag/include/urjtag/error.h | 2 + urjtag/include/urjtag/part.h | 21 + urjtag/include/urjtag/types.h | 2 + urjtag/src/Makefile.am | 2 + urjtag/src/bfin/Makefile.am | 34 + urjtag/src/bfin/bfin-part-bfin.c | 159 +++ urjtag/src/bfin/bfin-part.c | 169 +++ urjtag/src/bfin/bfin-part.h | 88 ++ urjtag/src/bfin/bfin.c | 1732 +++++++++++++++++++++++++++++ urjtag/src/bfin/insn-gen.c | 270 +++++ urjtag/src/cmd/Makefile.am | 3 +- urjtag/src/cmd/cmd_bfin.c | 570 ++++++++++ urjtag/src/cmd/cmd_list.h | 1 + urjtag/src/global/log-error.c | 2 + urjtag/src/part/part.c | 31 + urjtag/src/tap/detect.c | 13 + 21 files changed, 3505 insertions(+), 1 deletion(-) create mode 100644 urjtag/include/urjtag/bfin.h create mode 100644 urjtag/src/bfin/Makefile.am create mode 100644 urjtag/src/bfin/bfin-part-bfin.c create mode 100644 urjtag/src/bfin/bfin-part.c create mode 100644 urjtag/src/bfin/bfin-part.h create mode 100644 urjtag/src/bfin/bfin.c create mode 100644 urjtag/src/bfin/insn-gen.c create mode 100644 urjtag/src/cmd/cmd_bfin.c diff --git a/urjtag/ChangeLog b/urjtag/ChangeLog index 24be72e2..aeb42328 100644 --- a/urjtag/ChangeLog +++ b/urjtag/ChangeLog @@ -1,3 +1,40 @@ +2010-01-26 Jie Zhang + Mike Frysinger + + * configure.ac (AC_CONFIG_FILES): Add src/bfin/Makefile. + * include/urjtag/Makefile.am (pkginclude_HEADERS): Add bfin.h. + * include/urjtag/bfin.h: New file. + * include/urjtag/chain.h (struct URJ_CHAIN): Add main_part. + * include/urjtag/error.h (enum URJ_ERROR): Add URJ_ERROR_BFIN. + * include/urjtag/part.h (struct URJ_PART_PARAMS): Define. + (struct URJ_PART): Add params. + (urj_part_init_func_t): Typedef. + (struct URJ_PART_INIT): Define. + (urj_part_inits): Declare. + (urj_part_init_register): Declare. + (urj_part_find_init): Declare. + * include/urjtag/types.h (urj_part_params_t): Typedef. + (urj_part_init_t): Typedef. + * src/Makefile.am (SUBDIRS): Add bfin. + (liburjtag_la_LIBADD): Add bfin/libbfin.la. + * src/bfin/Makefile.am: New file. + * src/bfin/bfin-part-bfin.c: New file. + * src/bfin/bfin-part.c: New file. + * src/bfin/bfin-part.h: New file. + * src/bfin/bfin.c: New file. + * src/bfin/insn-gen.c: New file. + * src/cmd/Makefile.am (libcmd_la_SOURCES): Add cmd_bfin.c. + * src/cmd/cmd_bfin.c: New file. + * src/cmd/cmd_list.h: Add _URJ_CMD(bfin). + * src/global/log-error.c (urj_error_string): Handle URJ_ERROR_BFIN. + * src/part/part.c (urj_part_inits): Define. + (urj_part_alloc): Initialize params. + (urj_part_free): Free params. + (urj_part_init_register): New. + (urj_part_find_init): New. + * src/tap/detect.c (urj_tap_detect_parts): Do part initialization. + Initialize main_part. + 2010-01-24 Arnim Laeuger * src/tap/usbconn/libftdi.c, src/tap/usbconn/libftd2xx.c: diff --git a/urjtag/configure.ac b/urjtag/configure.ac index 8becd5dd..8ef581d7 100644 --- a/urjtag/configure.ac +++ b/urjtag/configure.ac @@ -76,6 +76,7 @@ AC_CONFIG_FILES( src/global/Makefile src/apps/jtag/Makefile src/apps/bsdl2jtag/Makefile + src/bfin/Makefile po/Makefile.in ) diff --git a/urjtag/include/urjtag/Makefile.am b/urjtag/include/urjtag/Makefile.am index 5dfe6333..532e95b1 100644 --- a/urjtag/include/urjtag/Makefile.am +++ b/urjtag/include/urjtag/Makefile.am @@ -24,6 +24,7 @@ include $(top_srcdir)/Makefile.rules pkginclude_HEADERS = \ + bfin.h \ bitmask.h \ bsbit.h \ bsdl.h \ diff --git a/urjtag/include/urjtag/bfin.h b/urjtag/include/urjtag/bfin.h new file mode 100644 index 00000000..902d8332 --- /dev/null +++ b/urjtag/include/urjtag/bfin.h @@ -0,0 +1,367 @@ +/* Copyright (C) 2008, 2009, 2010 Analog Devices, Inc. + * + * 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. + */ + +#ifndef BFIN_H +#define BFIN_H + +#include + +#include "types.h" +#include "tap.h" +#include "part.h" + + +/* High-Nibble: group code, low nibble: register code. */ +#define T_REG_R 0x00 +#define T_REG_P 0x10 +#define T_REG_I 0x20 +#define T_REG_B 0x30 +#define T_REG_L 0x34 +#define T_REG_M 0x24 +#define T_REG_A 0x40 + +enum core_regnum +{ + REG_R0 = T_REG_R, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, REG_R6, REG_R7, + REG_P0 = T_REG_P, REG_P1, REG_P2, REG_P3, REG_P4, REG_P5, REG_SP, REG_FP, + REG_I0 = T_REG_I, REG_I1, REG_I2, REG_I3, + REG_M0 = T_REG_M, REG_M1, REG_M2, REG_M3, + REG_B0 = T_REG_B, REG_B1, REG_B2, REG_B3, + REG_L0 = T_REG_L, REG_L1, REG_L2, REG_L3, + REG_A0x = T_REG_A, REG_A0w, REG_A1x, REG_A1w, + REG_ASTAT = 0x46, + REG_RETS = 0x47, + REG_LC0 = 0x60, REG_LT0, REG_LB0, REG_LC1, REG_LT1, REG_LB1, + REG_CYCLES, REG_CYCLES2, + REG_USP = 0x70, REG_SEQSTAT, REG_SYSCFG, + REG_RETI, REG_RETX, REG_RETN, REG_RETE, REG_EMUDAT, +}; + +#define CLASS_MASK 0xf0 +#define GROUP(x) (((x) & CLASS_MASK) >> 4) +#define DREG_P(x) (((x) & CLASS_MASK) == T_REG_R) +#define PREG_P(x) (((x) & CLASS_MASK) == T_REG_P) + + +#define DTEST_COMMAND 0xffe00300 +#define DTEST_DATA0 0xffe00400 +#define DTEST_DATA1 0xffe00404 + +#define ITEST_COMMAND 0xffe01300 +#define ITEST_DATA0 0xffe01400 +#define ITEST_DATA1 0xffe01404 + +/* OAB stands for Operations and Bits. */ + +struct emu_oab +{ + /* Operations */ + + void (*dbgctl_init) (urj_part_t *part, uint16_t value); + uint16_t (*dbgstat_value) (urj_part_t *part); + + /* Generate TEST_COMMAND from ADDR and W(rite). */ + uint32_t (*test_command) (uint32_t addr, int w); + + /* For existing Blackfin processors, it's actually DTEST_COMMAND + address. */ + uint32_t test_command_addr; + + /* For existing Blackfin processors, they are actually DTEST_DATA + addresses. */ + uint32_t test_data0_addr; + uint32_t test_data1_addr; + + /* No existing Blackfin processors use this. It should be 0. */ + int dbgctl_dbgstat_in_one_chain; + + /* No existing Blackfin processors use this. It should be 0. */ + int sticky_in_reset; + + /* Bits */ + uint16_t dbgctl_sram_init; + uint16_t dbgctl_wakeup; + uint16_t dbgctl_sysrst; + uint16_t dbgctl_esstep; + uint16_t dbgctl_emudatsz_32; + uint16_t dbgctl_emudatsz_40; + uint16_t dbgctl_emudatsz_48; + uint16_t dbgctl_emudatsz_mask; + uint16_t dbgctl_emuirlpsz_2; + uint16_t dbgctl_emuirsz_64; + uint16_t dbgctl_emuirsz_48; + uint16_t dbgctl_emuirsz_32; + uint16_t dbgctl_emuirsz_mask; + uint16_t dbgctl_empen; + uint16_t dbgctl_emeen; + uint16_t dbgctl_emfen; + uint16_t dbgctl_empwr; + + uint16_t dbgstat_lpdec1; + uint16_t dbgstat_in_powrgate; + uint16_t dbgstat_core_fault; + uint16_t dbgstat_idle; + uint16_t dbgstat_in_reset; + uint16_t dbgstat_lpdec0; + uint16_t dbgstat_bist_done; + uint16_t dbgstat_emucause_mask; + uint16_t dbgstat_emuack; + uint16_t dbgstat_emuready; + uint16_t dbgstat_emudiovf; + uint16_t dbgstat_emudoovf; + uint16_t dbgstat_emudif; + uint16_t dbgstat_emudof; +}; + +struct bfin_part_data +{ + int bypass; + struct emu_oab *emu_oab; + int scan; + uint16_t dbgctl; + uint16_t dbgstat; + uint64_t emuir_a; + uint64_t emuir_b; + uint64_t emudat_out; + uint64_t emudat_in; + uint32_t emupc; + uint32_t emupc_orig; +}; + +#define BFIN_PART_BYPASS(part) (((struct bfin_part_data *)((part)->params->data))->bypass) +#define EMU_OAB(part) (((struct bfin_part_data *)((part)->params->data))->emu_oab) + +#define BFIN_PART_SCAN(part) (((struct bfin_part_data *)((part)->params->data))->scan) +#define BFIN_PART_WPSTAT(part) (((struct bfin_part_data *)((part)->params->data))->wpstat) +#define BFIN_PART_DBGCTL(part) (((struct bfin_part_data *)((part)->params->data))->dbgctl) +#define BFIN_PART_DBGSTAT(part) (((struct bfin_part_data *)((part)->params->data))->dbgstat) +#define BFIN_PART_EMUIR_A(part) (((struct bfin_part_data *)((part)->params->data))->emuir_a) +#define BFIN_PART_EMUIR_B(part) (((struct bfin_part_data *)((part)->params->data))->emuir_b) +#define BFIN_PART_EMUDAT_OUT(part) (((struct bfin_part_data *)((part)->params->data))->emudat_out) +#define BFIN_PART_EMUDAT_IN(part) (((struct bfin_part_data *)((part)->params->data))->emudat_in) +#define BFIN_PART_EMUPC(part) (((struct bfin_part_data *)((part)->params->data))->emupc) +#define BFIN_PART_EMUPC_ORIG(part) (((struct bfin_part_data *)((part)->params->data))->emupc_orig) + +extern struct emu_oab bfin_emu_oab; + + +#define IDCODE_SCAN 0 +#define DBGSTAT_SCAN 1 +#define DBGCTL_SCAN 2 +#define EMUIR_SCAN 3 +#define EMUDAT_SCAN 4 +#define EMUPC_SCAN 5 +#define BYPASS 6 +#define EMUIR64_SCAN 7 +#define NUM_SCANS 8 + +extern const char *scans[]; + +#define INSN_NOP 0x0000 +#define INSN_RTE 0x0014 +#define INSN_CSYNC 0x0023 +#define INSN_SSYNC 0x0024 +#define INSN_ILLEGAL 0xffffffff + +#define INSN_BIT_MULTI 0x08 +#define INSN_IS_MULTI(insn) \ + (((insn) & 0xc0) == 0xc0 && ((insn) & INSN_BIT_MULTI) \ + && ((insn) & 0xe8) != 0xe8 /* not linkage */) + +enum bfin_insn_type +{ + /* Instruction is a normal instruction. */ + BFIN_INSN_NORMAL, + + /* Instruction is a value which should be set to EMUDAT. */ + BFIN_INSN_SET_EMUDAT +}; + +struct bfin_insn +{ + /* The instruction or the value to be set to EMUDAT. */ + uint64_t i; + + /* The type of this instruction. */ + enum bfin_insn_type type; + + /* Instructions to be executed are kept on a linked list. + This is the link. */ + struct bfin_insn *next; +}; + +enum { + LEAVE_NOP_DEFAULT, + LEAVE_NOP_YES, + LEAVE_NOP_NO +}; + +extern int bfin_check_emuready; + +/* From src/bfin/bfin.c */ + +int part_is_bfin (urj_chain_t *, int); +void part_bypass (urj_chain_t *, int); + +urj_tap_register_t *register_init_value (urj_tap_register_t *, uint64_t); +uint64_t register_value (urj_tap_register_t *); +int part_scan_select (urj_chain_t *, int, int); +int chain_scan_select (urj_chain_t *, int); + +#define DECLARE_PART_DBGCTL_SET_BIT(name) \ + void part_dbgctl_bit_set_##name (urj_chain_t *chain, int n); + +#define DECLARE_PART_DBGCTL_CLEAR_BIT(name) \ + void part_dbgctl_bit_clear_##name (urj_chain_t *chain, int n); + +#define DECLARE_PART_DBGCTL_IS(name) \ + int part_dbgctl_is_##name (urj_chain_t *chain, int n); + +#define DECLARE_CHAIN_DBGCTL_SET_BIT(name) \ + void chain_dbgctl_bit_set_##name (urj_chain_t *chain); + +#define DECLARE_CHAIN_DBGCTL_CLEAR_BIT(name) \ + void chain_dbgctl_bit_clear_##name (urj_chain_t *chain); + +#define DECLARE_DBGCTL_BIT_OP(name) \ + DECLARE_PART_DBGCTL_SET_BIT(name) \ + DECLARE_PART_DBGCTL_CLEAR_BIT(name) \ + DECLARE_PART_DBGCTL_IS(name) \ + DECLARE_CHAIN_DBGCTL_SET_BIT(name) \ + DECLARE_CHAIN_DBGCTL_CLEAR_BIT(name) + +/* These functions check cached DBGSTAT. So before calling them, + chain_dbgstat_get or part_dbgstat_get has to be called to update cached + DBGSTAT value. */ + +#define DECLARE_PART_DBGSTAT_BIT_IS(name) \ + int part_dbgstat_is_##name (urj_chain_t *chain, int n); + +DECLARE_DBGCTL_BIT_OP (sram_init) +DECLARE_DBGCTL_BIT_OP (wakeup) +DECLARE_DBGCTL_BIT_OP (sysrst) +DECLARE_DBGCTL_BIT_OP (esstep) +DECLARE_DBGCTL_BIT_OP (emudatsz_32) +DECLARE_DBGCTL_BIT_OP (emudatsz_40) +DECLARE_DBGCTL_BIT_OP (emudatsz_48) +DECLARE_DBGCTL_BIT_OP (emuirlpsz_2) +DECLARE_DBGCTL_BIT_OP (emuirsz_64) +DECLARE_DBGCTL_BIT_OP (emuirsz_48) +DECLARE_DBGCTL_BIT_OP (emuirsz_32) +DECLARE_DBGCTL_BIT_OP (empen) +DECLARE_DBGCTL_BIT_OP (emeen) +DECLARE_DBGCTL_BIT_OP (emfen) +DECLARE_DBGCTL_BIT_OP (empwr) + +DECLARE_PART_DBGSTAT_BIT_IS (lpdec1) +DECLARE_PART_DBGSTAT_BIT_IS (in_powrgate) +DECLARE_PART_DBGSTAT_BIT_IS (core_fault) +DECLARE_PART_DBGSTAT_BIT_IS (idle) +DECLARE_PART_DBGSTAT_BIT_IS (in_reset) +DECLARE_PART_DBGSTAT_BIT_IS (lpdec0) +DECLARE_PART_DBGSTAT_BIT_IS (bist_done) +DECLARE_PART_DBGSTAT_BIT_IS (emuack) +DECLARE_PART_DBGSTAT_BIT_IS (emuready) +DECLARE_PART_DBGSTAT_BIT_IS (emudiovf) +DECLARE_PART_DBGSTAT_BIT_IS (emudoovf) +DECLARE_PART_DBGSTAT_BIT_IS (emudif) +DECLARE_PART_DBGSTAT_BIT_IS (emudof) + +uint16_t part_dbgstat_emucause (urj_chain_t *, int); +void chain_dbgstat_get (urj_chain_t *); +void part_dbgstat_get (urj_chain_t *, int); +void chain_emupc_get (urj_chain_t *, int); +uint32_t part_emupc_get (urj_chain_t *, int, int); +void chain_dbgstat_clear_ovfs (urj_chain_t *); +void part_dbgstat_clear_ovfs (urj_chain_t *, int); +void chain_check_emuready (urj_chain_t *); +int part_sticky_in_reset (urj_chain_t *, int); +void chain_wait_in_reset (urj_chain_t *); +void part_wait_in_reset (urj_chain_t *, int); +void chain_wait_reset (urj_chain_t *); +void part_wait_reset (urj_chain_t *, int); +void part_check_emuready (urj_chain_t *, int); +void part_emudat_set (urj_chain_t *, int, uint32_t, int); +uint32_t part_emudat_get (urj_chain_t *, int, int); +void part_emudat_defer_get (urj_chain_t *, int, int); +uint32_t part_emudat_get_done (urj_chain_t *, int, int); +uint64_t emudat_value (urj_tap_register_t *); +void emudat_init_value (urj_tap_register_t *, uint32_t); +void chain_register_get (urj_chain_t *, enum core_regnum, uint32_t *); +uint32_t part_register_get (urj_chain_t *, int, enum core_regnum); +void chain_register_set (urj_chain_t *, enum core_regnum, uint32_t *); +void chain_register_set_same (urj_chain_t *, enum core_regnum, uint32_t); +void part_register_set (urj_chain_t *, int, enum core_regnum, uint32_t); +void chain_emuir_set_same (urj_chain_t *, uint64_t, int); +void part_emuir_set (urj_chain_t *, int, uint64_t, int); +void chain_emuir_set_same_2 (urj_chain_t *, uint64_t, uint64_t, int); +void part_emuir_set_2 (urj_chain_t *, int, uint64_t, uint64_t, int); +uint32_t part_get_r0 (urj_chain_t *, int); +uint32_t part_get_p0 (urj_chain_t *, int); +void part_set_r0 (urj_chain_t *, int, uint32_t); +void part_set_p0 (urj_chain_t *, int, uint32_t); +void chain_emulation_enable (urj_chain_t *); +void part_emulation_enable (urj_chain_t *, int); +void chain_emulation_disable (urj_chain_t *); +void part_emulation_disable (urj_chain_t *, int); +void chain_emulation_trigger (urj_chain_t *); +void part_emulation_trigger (urj_chain_t *, int); +void chain_emulation_return (urj_chain_t *); +void part_emulation_return (urj_chain_t *, int); +void part_execute_instructions (urj_chain_t *, int n, struct bfin_insn *); +void chain_system_reset (urj_chain_t *); +void bfin_core_reset (urj_chain_t *); +void software_reset (urj_chain_t *); +void chain_emupc_reset (urj_chain_t *, uint32_t *); +uint32_t part_mmr_read_clobber_r0 (urj_chain_t *, int, int32_t, int); +void part_mmr_write_clobber_r0 (urj_chain_t *, int, int32_t, uint32_t, int); +uint32_t part_mmr_read (urj_chain_t *, int, uint32_t, int); +void part_mmr_write (urj_chain_t *, int, uint32_t, uint32_t, int); + +/* From src/bfin/insn-gen.c */ + +uint32_t gen_move (enum core_regnum dest, enum core_regnum src); +uint32_t gen_load32_offset (enum core_regnum dest, enum core_regnum base, int32_t offset); +uint32_t gen_store32_offset (enum core_regnum base, int32_t offset, enum core_regnum src); +uint32_t gen_load16z_offset (enum core_regnum dest, enum core_regnum base, int32_t offset); +uint32_t gen_store16_offset (enum core_regnum base, int32_t offset, enum core_regnum src); +uint32_t gen_load8z_offset (enum core_regnum dest, enum core_regnum base, int32_t offset); +uint32_t gen_store8_offset (enum core_regnum base, int32_t offset, enum core_regnum src); +uint32_t gen_load32pi (enum core_regnum dest, enum core_regnum base); +uint32_t gen_store32pi (enum core_regnum base, enum core_regnum src); +uint32_t gen_load16zpi (enum core_regnum dest, enum core_regnum base); +uint32_t gen_store16pi (enum core_regnum base, enum core_regnum src); +uint32_t gen_load8zpi (enum core_regnum dest, enum core_regnum base); +uint32_t gen_store8pi (enum core_regnum base, enum core_regnum src); +uint32_t gen_load32 (enum core_regnum dest, enum core_regnum base); +uint32_t gen_store32 (enum core_regnum base, enum core_regnum src); +uint32_t gen_load16z (enum core_regnum dest, enum core_regnum base); +uint32_t gen_store16 (enum core_regnum base, enum core_regnum src); +uint32_t gen_load8z (enum core_regnum dest, enum core_regnum base); +uint32_t gen_store8 (enum core_regnum base, enum core_regnum src); +uint32_t gen_iflush (enum core_regnum addr); +uint32_t gen_iflush_pm (enum core_regnum addr); +uint32_t gen_flush (enum core_regnum addr); +uint32_t gen_flush_pm (enum core_regnum addr); +uint32_t gen_flushinv (enum core_regnum addr); +uint32_t gen_flushinv_pm (enum core_regnum addr); +uint32_t gen_prefetch (enum core_regnum addr); +uint32_t gen_prefetch_pm (enum core_regnum addr); +uint32_t gen_jump_reg (enum core_regnum addr); + +#endif /* BFIN_H */ diff --git a/urjtag/include/urjtag/chain.h b/urjtag/include/urjtag/chain.h index 8f91d4a7..c29b6bc3 100644 --- a/urjtag/include/urjtag/chain.h +++ b/urjtag/include/urjtag/chain.h @@ -44,6 +44,7 @@ struct URJ_CHAIN int active_part; urj_cable_t *cable; urj_bsdl_globs_t bsdl; + int main_part; }; urj_chain_t *urj_tap_chain_alloc (void); diff --git a/urjtag/include/urjtag/error.h b/urjtag/include/urjtag/error.h index 6b36ea7c..35e119c9 100644 --- a/urjtag/include/urjtag/error.h +++ b/urjtag/include/urjtag/error.h @@ -68,6 +68,8 @@ typedef enum URJ_ERROR URJ_ERROR_BSDL_VHDL, URJ_ERROR_BSDL_BSDL, + URJ_ERROR_BFIN, + URJ_ERROR_UNIMPLEMENTED, } urj_error_t; diff --git a/urjtag/include/urjtag/part.h b/urjtag/include/urjtag/part.h index dd8d761b..8515964f 100644 --- a/urjtag/include/urjtag/part.h +++ b/urjtag/include/urjtag/part.h @@ -31,6 +31,12 @@ #define URJ_PART_PART_MAXLEN 20 #define URJ_PART_STEPPING_MAXLEN 8 +struct URJ_PART_PARAMS +{ + void (*free) (void *); + void *data; +}; + struct URJ_PART { urj_tap_register_t *id; @@ -46,6 +52,7 @@ struct URJ_PART urj_data_register_t *data_registers; int boundary_length; urj_bsbit_t **bsbits; + urj_part_params_t *params; }; urj_part_t *urj_part_alloc (const urj_tap_register_t *id); @@ -86,6 +93,20 @@ urj_part_instruction_t *urj_part_instruction_define (urj_part_t *part, const char *code, const char *data_register); +typedef void (*urj_part_init_func_t) (urj_part_t *); + +struct URJ_PART_INIT +{ + char part[URJ_PART_PART_MAXLEN + 1]; + urj_part_init_func_t init; + urj_part_init_t *next; +}; + +/* List of registered part initializers. */ +extern urj_part_init_t *urj_part_inits; + +void urj_part_init_register (char *part, urj_part_init_func_t init); +urj_part_init_func_t urj_part_find_init (char *part); /** * parts diff --git a/urjtag/include/urjtag/types.h b/urjtag/include/urjtag/types.h index f05cc1ea..79203800 100644 --- a/urjtag/include/urjtag/types.h +++ b/urjtag/include/urjtag/types.h @@ -37,6 +37,8 @@ typedef struct URJ_PARTS urj_parts_t; typedef struct URJ_PART_SIGNAL urj_part_signal_t; typedef struct URJ_PART_SALIAS urj_part_salias_t; typedef struct URJ_PART_INSTRUCTION urj_part_instruction_t; +typedef struct URJ_PART_PARAMS urj_part_params_t; +typedef struct URJ_PART_INIT urj_part_init_t; typedef struct URJ_DATA_REGISTER urj_data_register_t; typedef struct URJ_BSBIT urj_bsbit_t; typedef struct URJ_TAP_REGISTER urj_tap_register_t; diff --git a/urjtag/src/Makefile.am b/urjtag/src/Makefile.am index 40ad698f..381d35eb 100644 --- a/urjtag/src/Makefile.am +++ b/urjtag/src/Makefile.am @@ -28,6 +28,7 @@ SUBDIRS = \ lib \ tap \ part \ + bfin \ bus \ cmd \ global @@ -54,6 +55,7 @@ liburjtag_la_LIBADD = \ part/libpart.la \ lib/libjtaglib.la \ flash/libflash.la \ + bfin/libbfin.la \ bus/libbus.la \ cmd/libcmd.la \ global/libglobal.la \ diff --git a/urjtag/src/bfin/Makefile.am b/urjtag/src/bfin/Makefile.am new file mode 100644 index 00000000..a7a82c3c --- /dev/null +++ b/urjtag/src/bfin/Makefile.am @@ -0,0 +1,34 @@ +# +# $Id: Makefile.am 506 2003-08-13 10:05:15Z telka $ +# +# Copyright (C) 2002 ETC s.r.o. +# +# 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 Marcel Telka , 2002. +# + +include $(top_srcdir)/Makefile.rules + +noinst_LTLIBRARIES = libbfin.la + +libbfin_la_SOURCES = \ + insn-gen.c \ + bfin.c \ + bfin-part.c \ + bfin-part-bfin.c + +AM_CFLAGS = $(WARNINGCFLAGS) diff --git a/urjtag/src/bfin/bfin-part-bfin.c b/urjtag/src/bfin/bfin-part-bfin.c new file mode 100644 index 00000000..364720dd --- /dev/null +++ b/urjtag/src/bfin/bfin-part-bfin.c @@ -0,0 +1,159 @@ +/* Copyright (C) 2008, 2009, 2010 Analog Devices, Inc. + * + * This file is subject to the terms and conditions of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. See the file COPYING for more details. + * + * This file 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. + * + * Non-GPL License is also available. Please contact + * for more information. + * + * Implementation of `Blackfin' target for the GDB proxy server. + */ + + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* The helper functions for Blackfin DBGCTL and DBGSTAT operations. */ + +static void +bfin_dbgctl_init (urj_part_t *part, uint16_t v) +{ + register_init_value (part->active_instruction->data_register->in, v); +} + +static uint16_t +bfin_dbgstat_value (urj_part_t *part) +{ + return register_value (part->active_instruction->data_register->out); +} + +static uint32_t +bfin_test_command (uint32_t addr, int w) +{ + uint32_t test_command; + + /* We can only access [15:0] range. */ + if ((addr & 0xf0000) != 0) + return 0; + + test_command = + (addr & 0x0800) << 15 /* Address bit 11 */ + | (addr & 0x8000) << 8 /* Address bit 15 */ + | (addr & 0x3000) << 4 /* Address bits [13:12] */ + | (addr & 0x47f8) /* Address bits 14 and [10:3] */ + | 0x1000000 /* Access instruction */ + | 0x4; /* Access data array */ + + if (w) + test_command |= 0x2; /* Write */ + + return test_command; +} + +struct emu_oab bfin_emu_oab = +{ + bfin_dbgctl_init, + bfin_dbgstat_value, + + bfin_test_command, + + DTEST_COMMAND, + DTEST_DATA0, + DTEST_DATA1, + + 0, /* dbgctl_dbgstat_in_one_chain */ + 0, /* sticky_in_reset */ + + 0x1000, /* DBGCTL_SRAM_INIT */ + 0x0800, /* DBGCTL_WAKEUP */ + 0x0400, /* DBGCTL_SYSRST */ + 0x0200, /* DBGCTL_ESSTEP */ + 0x0000, /* DBGCTL_EMUDATSZ_32 */ + 0x0080, /* DBGCTL_EMUDATSZ_40 */ + 0x0100, /* DBGCTL_EMUDATSZ_48 */ + 0x0180, /* DBGCTL_EMUDATSZ_MASK */ + 0x0040, /* DBGCTL_EMUIRLPSZ_2 */ + 0x0000, /* DBGCTL_EMUIRSZ_64 */ + 0x0010, /* DBGCTL_EMUIRSZ_48 */ + 0x0020, /* DBGCTL_EMUIRSZ_32 */ + 0x0030, /* DBGCTL_EMUIRSZ_MASK */ + 0x0008, /* DBGCTL_EMPEN */ + 0x0004, /* DBGCTL_EMEEN */ + 0x0002, /* DBGCTL_EMFEN */ + 0x0001, /* DBGCTL_EMPWR */ + + 0x8000, /* DBGSTAT_LPDEC1 */ + 0x0000, /* No DBGSTAT_IN_POWRGATE for bfin */ + 0x4000, /* DBGSTAT_CORE_FAULT */ + 0x2000, /* DBGSTAT_IDLE */ + 0x1000, /* DBGSTAT_IN_RESET */ + 0x0800, /* DBGSTAT_LPDEC0 */ + 0x0400, /* DBGSTAT_BIST_DONE */ + 0x03c0, /* DBGSTAT_EMUCAUSE_MASK */ + 0x0020, /* DBGSTAT_EMUACK */ + 0x0010, /* DBGSTAT_EMUREADY */ + 0x0008, /* DBGSTAT_EMUDIOVF */ + 0x0004, /* DBGSTAT_EMUDOOVF */ + 0x0002, /* DBGSTAT_EMUDIF */ + 0x0001, /* DBGSTAT_EMUDOF */ +}; + +static void +bfin_part_init (urj_part_t *part) +{ + int i; + + assert (part && part->params); + + part->params->free = free; + part->params->data = malloc (sizeof (struct bfin_part_data)); + EMU_OAB (part) = &bfin_emu_oab; + + BFIN_PART_BYPASS (part) = 0; + + for (i = 0; i < NUM_SCANS; i++) + if (strcmp (part->active_instruction->name, scans[i]) == 0) + break; + + assert (i < NUM_SCANS); + + BFIN_PART_SCAN (part) = i; + BFIN_PART_DBGCTL (part) = 0; + BFIN_PART_DBGSTAT (part) = 0; + BFIN_PART_EMUIR_A (part) = INSN_ILLEGAL; + BFIN_PART_EMUIR_B (part) = INSN_ILLEGAL; + BFIN_PART_EMUDAT_OUT (part) = 0; + BFIN_PART_EMUDAT_IN (part) = 0; + BFIN_PART_EMUPC (part) = -1; +} + +extern void bfin_init (void); + +void +bfin_init () +{ + urj_part_init_register ("BF506", bfin_part_init); + urj_part_init_register ("BF518", bfin_part_init); + urj_part_init_register ("BF526", bfin_part_init); + urj_part_init_register ("BF527", bfin_part_init); + urj_part_init_register ("BF533", bfin_part_init); + urj_part_init_register ("BF534", bfin_part_init); + urj_part_init_register ("BF537", bfin_part_init); + urj_part_init_register ("BF538", bfin_part_init); + urj_part_init_register ("BF548", bfin_part_init); + urj_part_init_register ("BF561", bfin_part_init); +} diff --git a/urjtag/src/bfin/bfin-part.c b/urjtag/src/bfin/bfin-part.c new file mode 100644 index 00000000..3e6795e5 --- /dev/null +++ b/urjtag/src/bfin/bfin-part.c @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2008, 2009, 2010 Analog Devices, Inc. + * + * 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. + */ + +#include +#include +#include + +#include +#include +#include "bfin-part.h" + +/* Wrappers of the helper functions. */ + +void +_part_dbgctl_init (urj_part_t *part, uint16_t value) +{ + EMU_OAB (part)->dbgctl_init (part, value); +} + +uint16_t +_part_dbgstat_value (urj_part_t *part) +{ + return EMU_OAB (part)->dbgstat_value (part); +} + +/* Routines to access DBGCTL and DBGSTAT bits. */ + +#define _PART_DBGCTL_CLEAR_OR_SET_BIT(name) \ + uint16_t \ + _part_dbgctl_bit_clear_or_set_##name (urj_part_t *part, uint16_t dbgctl, int set) \ + { \ + if (set) \ + return dbgctl | EMU_OAB (part)->dbgctl_##name; \ + else \ + return dbgctl & ~EMU_OAB (part)->dbgctl_##name; \ + } + +#define _PART_DBGCTL_BIT_IS(name) \ + int \ + _part_dbgctl_is_##name (urj_part_t *part, uint16_t dbgctl) \ + { \ + if (dbgctl & EMU_OAB (part)->dbgctl_##name) \ + return 1; \ + else \ + return 0; \ + } + +#define _PART_DBGCTL(name) \ + _PART_DBGCTL_CLEAR_OR_SET_BIT(name) \ + _PART_DBGCTL_BIT_IS(name) + +#define _PART_DBGCTL_BIT_IS_MASK(base, sfx) \ + int \ + _part_dbgctl_is_##base##_##sfx (urj_part_t *part, uint16_t dbgctl) \ + { \ + if ((dbgctl & EMU_OAB (part)->dbgctl_##base##_mask) == \ + EMU_OAB (part)->dbgctl_##base##_##sfx) \ + return 1; \ + else \ + return 0; \ + } + +#define _PART_DBGCTL_MASK(base, sfx) \ + _PART_DBGCTL_CLEAR_OR_SET_BIT(base##_##sfx) \ + _PART_DBGCTL_BIT_IS_MASK(base, sfx) + +_PART_DBGCTL (sram_init) +_PART_DBGCTL (wakeup) +_PART_DBGCTL (sysrst) +_PART_DBGCTL (esstep) +_PART_DBGCTL_MASK (emudatsz, 32) +_PART_DBGCTL_MASK (emudatsz, 40) +_PART_DBGCTL_MASK (emudatsz, 48) +_PART_DBGCTL (emuirlpsz_2) +_PART_DBGCTL_MASK (emuirsz, 64) +_PART_DBGCTL_MASK (emuirsz, 48) +_PART_DBGCTL_MASK (emuirsz, 32) +_PART_DBGCTL (empen) +_PART_DBGCTL (emeen) +_PART_DBGCTL (emfen) +_PART_DBGCTL (empwr) + +#define _PART_DBGSTAT_BIT_IS(name) \ + int \ + _part_dbgstat_is_##name (urj_part_t *part, uint16_t dbgstat) \ + { \ + if (dbgstat & EMU_OAB (part)->dbgstat_##name) \ + return 1; \ + else \ + return 0; \ + } + +#define _PART_DBGSTAT_CLEAR_BIT(name) \ + uint16_t \ + _part_dbgstat_bit_clear_##name (urj_part_t *part, uint16_t dbgstat) \ + { \ + return dbgstat & ~EMU_OAB (part)->dbgstat_##name; \ + } + +#define _PART_DBGSTAT_SET_BIT(name) \ + uint16_t \ + _part_dbgstat_bit_set_##name (urj_part_t *part, uint16_t dbgstat) \ + { \ + return dbgstat | EMU_OAB (part)->dbgstat_##name; \ + } + +_PART_DBGSTAT_BIT_IS (lpdec1) +_PART_DBGSTAT_BIT_IS (in_powrgate) +_PART_DBGSTAT_BIT_IS (core_fault) +_PART_DBGSTAT_BIT_IS (idle) +_PART_DBGSTAT_BIT_IS (in_reset) +_PART_DBGSTAT_BIT_IS (lpdec0) +_PART_DBGSTAT_BIT_IS (bist_done) +_PART_DBGSTAT_BIT_IS (emuack) +_PART_DBGSTAT_BIT_IS (emuready) +_PART_DBGSTAT_BIT_IS (emudiovf) +_PART_DBGSTAT_BIT_IS (emudoovf) +_PART_DBGSTAT_BIT_IS (emudif) +_PART_DBGSTAT_BIT_IS (emudof) + +_PART_DBGSTAT_CLEAR_BIT (emudiovf) +_PART_DBGSTAT_CLEAR_BIT (emudoovf) + +_PART_DBGSTAT_SET_BIT (emudiovf) +_PART_DBGSTAT_SET_BIT (emudoovf) + +int +_part_dbgctl_dbgstat_in_one_chain (urj_part_t *part) +{ + return EMU_OAB (part)->dbgctl_dbgstat_in_one_chain; +} + +int +_part_sticky_in_reset (urj_part_t *part) +{ + return EMU_OAB (part)->sticky_in_reset; +} + +uint16_t +_part_dbgstat_emucause_mask (urj_part_t *part) +{ + return EMU_OAB (part)->dbgstat_emucause_mask; +} + +void _bfin_part_init (void) __attribute__((constructor)); + +extern void bfin_init (void); + +void +_bfin_part_init () +{ + bfin_init (); +} diff --git a/urjtag/src/bfin/bfin-part.h b/urjtag/src/bfin/bfin-part.h new file mode 100644 index 00000000..690f30f5 --- /dev/null +++ b/urjtag/src/bfin/bfin-part.h @@ -0,0 +1,88 @@ +/* Copyright (C) 2008, 2009, 2010 Analog Devices, Inc. + * + * This file is subject to the terms and conditions of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. See the file COPYING for more details. + * + * This file 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. + * + * Non-GPL License is also available. Please contact + * for more information. + * + * Implementation of `Blackfin' target for the GDB proxy server. + */ + + +#ifndef _BLACKFIN_PART_H_ +#define _BLACKFIN_PART_H_ + +#include + +void _part_dbgctl_init (urj_part_t *, uint16_t); +uint16_t _part_dbgstat_value (urj_part_t *); +uint16_t _part_dbgstat_emucause_mask (urj_part_t *); + +#define DECLARE__PART_DBGCTL_CLEAR_OR_SET_BIT(name) \ + uint16_t _part_dbgctl_bit_clear_or_set_##name (urj_part_t *, uint16_t, int); + +#define DECLARE__PART_DBGCTL_IS(name) \ + extern int _part_dbgctl_is_##name (urj_part_t *, uint16_t); + +#define DECLARE__PART_DBGCTL(name) \ + DECLARE__PART_DBGCTL_CLEAR_OR_SET_BIT(name) \ + DECLARE__PART_DBGCTL_IS(name) + +DECLARE__PART_DBGCTL (sram_init) +DECLARE__PART_DBGCTL (wakeup) +DECLARE__PART_DBGCTL (sysrst) +DECLARE__PART_DBGCTL (esstep) +DECLARE__PART_DBGCTL (emudatsz_32) +DECLARE__PART_DBGCTL (emudatsz_40) +DECLARE__PART_DBGCTL (emudatsz_48) +DECLARE__PART_DBGCTL (emuirlpsz_2) +DECLARE__PART_DBGCTL (emuirsz_64) +DECLARE__PART_DBGCTL (emuirsz_48) +DECLARE__PART_DBGCTL (emuirsz_32) +DECLARE__PART_DBGCTL (empen) +DECLARE__PART_DBGCTL (emeen) +DECLARE__PART_DBGCTL (emfen) +DECLARE__PART_DBGCTL (empwr) + +#define DECLARE__PART_DBGSTAT_BIT_IS(name) \ + int _part_dbgstat_is_##name (urj_part_t *, uint16_t); + +#define DECLARE__PART_DBGSTAT_CLEAR_BIT(name) \ + uint16_t _part_dbgstat_bit_clear_##name (urj_part_t *, uint16_t); + +#define DECLARE__PART_DBGSTAT_SET_BIT(name) \ + uint16_t _part_dbgstat_bit_set_##name (urj_part_t *, uint16_t); + +DECLARE__PART_DBGSTAT_BIT_IS (lpdec1) +DECLARE__PART_DBGSTAT_BIT_IS (in_powrgate) +DECLARE__PART_DBGSTAT_BIT_IS (core_fault) +DECLARE__PART_DBGSTAT_BIT_IS (idle) +DECLARE__PART_DBGSTAT_BIT_IS (in_reset) +DECLARE__PART_DBGSTAT_BIT_IS (lpdec0) +DECLARE__PART_DBGSTAT_BIT_IS (bist_done) +DECLARE__PART_DBGSTAT_BIT_IS (emuack) +DECLARE__PART_DBGSTAT_BIT_IS (emuready) +DECLARE__PART_DBGSTAT_BIT_IS (emudiovf) +DECLARE__PART_DBGSTAT_BIT_IS (emudoovf) +DECLARE__PART_DBGSTAT_BIT_IS (emudif) +DECLARE__PART_DBGSTAT_BIT_IS (emudof) + +DECLARE__PART_DBGSTAT_CLEAR_BIT (emudiovf) +DECLARE__PART_DBGSTAT_CLEAR_BIT (emudoovf) + +DECLARE__PART_DBGSTAT_SET_BIT (emudiovf) +DECLARE__PART_DBGSTAT_SET_BIT (emudoovf) + +int _part_sticky_in_reset (urj_part_t *); +int _part_dbgctl_dbgstat_in_one_chain (urj_part_t *); + + +#endif /* _BLACKFIN_PART_H_ */ diff --git a/urjtag/src/bfin/bfin.c b/urjtag/src/bfin/bfin.c new file mode 100644 index 00000000..09e30cb0 --- /dev/null +++ b/urjtag/src/bfin/bfin.c @@ -0,0 +1,1732 @@ +/* Copyright (C) 2008, 2009, 2010 Analog Devices, Inc. + * + * 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. + */ + +#include "sysdep.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "bfin-part.h" + +const char *scans[] = { + "IDCODE", + "DBGSTAT_SCAN", + "DBGCTL_SCAN", + "EMUIR_SCAN", + "EMUDAT40_SCAN", + "EMUPC_SCAN", + "BYPASS", + "EMUIR64_SCAN", +}; + +#define SWRST 0xffc00100 + + +#ifdef __MINGW32__ +struct timespec { unsigned long tv_sec, tv_nsec; }; +#define nanosleep(req, rem) usleep((req)->tv_sec * 1000 * 1000 + (req)->tv_nsec / 1000) +#endif + +int bfin_check_emuready = 1; + +static struct timespec bfin_emu_wait_ts = {0, 5000000}; + + +static int +is_bfin_part (urj_part_t *part) +{ + /* FIXME: We now assume only Blackfin parts have initialized params. */ + if (part->params && part->params->data) + return 1; + else + return 0; +} + +int +part_is_bfin (urj_chain_t *chain, int n) +{ + return is_bfin_part (chain->parts->parts[n]); +} + +static int +part_is_bypassed (urj_chain_t *chain, int n) +{ + urj_part_t *part; + + part = chain->parts->parts[n]; + + if (part_is_bfin (chain, n)) + return BFIN_PART_BYPASS (part); + + /* Other parts are all bypassed. */ + else + return 1; +} + +void +part_bypass (urj_chain_t *chain, int n) +{ + urj_part_t *part; + + part = chain->parts->parts[n]; + if (is_bfin_part (part)) + BFIN_PART_BYPASS (part) = 1; +} + +urj_tap_register_t * +register_init_value (urj_tap_register_t *tr, uint64_t value) +{ + int i; + + for (i = 0; i < tr->len; i++) + tr->data[i] = (value >> (tr->len - i - 1)) & 1; + + return tr; +} + +uint64_t +register_value (urj_tap_register_t *tr) +{ + uint64_t v = 0; + int i; + + for (i = 0; i < tr->len; i++) + v = (v << 1) | tr->data[i]; + + return v; +} + +static int +bfin_set_scan (urj_part_t *part, int scan) +{ + if (is_bfin_part (part)) + { + if (BFIN_PART_SCAN (part) != scan) + { + urj_part_set_instruction (part, scans[scan]); + assert (part->active_instruction != NULL); + BFIN_PART_SCAN (part) = scan; + return 1; + } + else + return 0; + } + else + { + urj_part_set_instruction (part, scans[scan]); + return 1; + } +} + +static void emuir_init_value (urj_tap_register_t *r, uint64_t insn); + +#if 0 +static int +chain_scan_select_array (urj_chain_t *chain, int *scan) +{ + int i; + int changed; + + changed = 0; + + for (i = 0; i < chain->parts->len; i++) + { + urj_part_t *part = chain->parts->parts[i]; + + if (part_is_bypassed (chain, i)) + changed += bfin_set_scan (part, BYPASS); + else + changed += bfin_set_scan (part, scan[i]); + } + + if (changed) + urj_tap_chain_shift_instructions_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + return 0; +} +#endif + +int +chain_scan_select (urj_chain_t *chain, int scan) +{ + int i; + int changed; + + changed = 0; + + for (i = 0; i < chain->parts->len; i++) + if (part_is_bypassed (chain, i)) + changed += bfin_set_scan (chain->parts->parts[i], BYPASS); + else + changed += bfin_set_scan (chain->parts->parts[i], scan); + + if (changed) + urj_tap_chain_shift_instructions_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + return 0; +} + +int +part_scan_select (urj_chain_t *chain, int n, int scan) +{ + int i; + int changed; + urj_part_t *part; + + changed = 0; + + part = chain->parts->parts[n]; + + changed += bfin_set_scan (part, scan); + + if (part->active_instruction == NULL) + { + urj_log (URJ_LOG_LEVEL_ERROR, + _("%s: unknown instruction '%s'\n"), part->part, scans[scan]); + return -1; + } + + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + if (i != n) + { + part = chain->parts->parts[i]; + changed += bfin_set_scan (part, BYPASS); + } + } + + if (changed) + urj_tap_chain_shift_instructions_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + return 0; +} + +#define PART_DBGCTL_CLEAR_OR_SET_BIT(name) \ + static void \ + part_dbgctl_bit_clear_or_set_##name (urj_chain_t *chain, int n, int set) \ + { \ + urj_part_t *part = chain->parts->parts[n]; \ + uint16_t dbgctl = BFIN_PART_DBGCTL (part); \ + \ + dbgctl = _part_dbgctl_bit_clear_or_set_##name (part, dbgctl, set); \ + _part_dbgctl_init (part, dbgctl); \ + BFIN_PART_DBGCTL (part) = dbgctl; \ + } + +#define CHAIN_DBGCTL_CLEAR_OR_SET_BIT(name) \ + static void \ + chain_dbgctl_bit_clear_or_set_##name (urj_chain_t *chain, int set) \ + { \ + int i; \ + \ + for (i = 0; i < chain->parts->len; i++) \ + { \ + if (part_is_bypassed (chain, i)) \ + continue; \ + \ + part_dbgctl_bit_clear_or_set_##name (chain, i, set); \ + } \ + } + +#define PART_DBGCTL_SET_BIT(name) \ + void \ + part_dbgctl_bit_set_##name (urj_chain_t *chain, int n) \ + { \ + part_dbgctl_bit_clear_or_set_##name (chain, n, 1); \ + } + +#define PART_DBGCTL_IS(name) \ + int \ + part_dbgctl_is_##name (urj_chain_t *chain, int n) \ + { \ + urj_part_t *part = chain->parts->parts[n]; \ + return _part_dbgctl_is_##name (part, BFIN_PART_DBGCTL (part)); \ + } + +#define PART_DBGCTL_CLEAR_BIT(name) \ + void \ + part_dbgctl_bit_clear_##name (urj_chain_t *chain, int n) \ + { \ + part_dbgctl_bit_clear_or_set_##name (chain, n, 0); \ + } + +#define CHAIN_DBGCTL_SET_BIT(name) \ + void \ + chain_dbgctl_bit_set_##name (urj_chain_t *chain) \ + { \ + chain_dbgctl_bit_clear_or_set_##name (chain, 1); \ + } + +#define CHAIN_DBGCTL_CLEAR_BIT(name) \ + void \ + chain_dbgctl_bit_clear_##name (urj_chain_t *chain) \ + { \ + chain_dbgctl_bit_clear_or_set_##name (chain, 0); \ + } + +#define DBGCTL_BIT_OP(name) \ + PART_DBGCTL_CLEAR_OR_SET_BIT(name) \ + PART_DBGCTL_SET_BIT(name) \ + PART_DBGCTL_CLEAR_BIT(name) \ + PART_DBGCTL_IS(name) \ + CHAIN_DBGCTL_CLEAR_OR_SET_BIT(name) \ + CHAIN_DBGCTL_SET_BIT(name) \ + CHAIN_DBGCTL_CLEAR_BIT(name) + + +/* These functions check cached DBGSTAT. So before calling them, + dbgstat_get or core_dbgstat_get has to be called to update cached + DBGSTAT value. */ + +#define PART_DBGSTAT_BIT_IS(name) \ + int \ + part_dbgstat_is_##name (urj_chain_t *chain, int n) \ + { \ + urj_part_t *part = chain->parts->parts[n]; \ + return _part_dbgstat_is_##name (part, BFIN_PART_DBGSTAT (part)); \ + } + +#define PART_DBGSTAT_CLEAR_BIT(name) \ + static void \ + part_dbgstat_bit_clear_##name (urj_chain_t *chain, int n) \ + { \ + urj_part_t *part = chain->parts->parts[n]; \ + urj_tap_register_t *r = part->active_instruction->data_register->in; \ + BFIN_PART_DBGSTAT (part) \ + = _part_dbgstat_bit_clear_##name (part, BFIN_PART_DBGSTAT (part)); \ + register_init_value (r, BFIN_PART_DBGSTAT (part)); \ + } + +#define PART_DBGSTAT_SET_BIT(name) \ + static void \ + part_dbgstat_bit_set_##name (urj_chain_t *chain, int n) \ + { \ + urj_part_t *part = chain->parts->parts[n]; \ + urj_tap_register_t *r = part->active_instruction->data_register->in; \ + BFIN_PART_DBGSTAT (part) \ + = _part_dbgstat_bit_set_##name (part, BFIN_PART_DBGSTAT (part)); \ + register_init_value (r, BFIN_PART_DBGSTAT (part)); \ + } + +DBGCTL_BIT_OP (sram_init) +DBGCTL_BIT_OP (wakeup) +DBGCTL_BIT_OP (sysrst) +DBGCTL_BIT_OP (esstep) +DBGCTL_BIT_OP (emudatsz_32) +DBGCTL_BIT_OP (emudatsz_40) +DBGCTL_BIT_OP (emudatsz_48) +DBGCTL_BIT_OP (emuirlpsz_2) +DBGCTL_BIT_OP (emuirsz_64) +DBGCTL_BIT_OP (emuirsz_48) +DBGCTL_BIT_OP (emuirsz_32) +DBGCTL_BIT_OP (empen) +DBGCTL_BIT_OP (emeen) +DBGCTL_BIT_OP (emfen) +DBGCTL_BIT_OP (empwr) + +PART_DBGSTAT_BIT_IS (lpdec1) +PART_DBGSTAT_BIT_IS (in_powrgate) +PART_DBGSTAT_BIT_IS (core_fault) +PART_DBGSTAT_BIT_IS (idle) +PART_DBGSTAT_BIT_IS (in_reset) +PART_DBGSTAT_BIT_IS (lpdec0) +PART_DBGSTAT_BIT_IS (bist_done) +PART_DBGSTAT_BIT_IS (emuack) +PART_DBGSTAT_BIT_IS (emuready) +PART_DBGSTAT_BIT_IS (emudiovf) +PART_DBGSTAT_BIT_IS (emudoovf) +PART_DBGSTAT_BIT_IS (emudif) +PART_DBGSTAT_BIT_IS (emudof) + +PART_DBGSTAT_CLEAR_BIT (emudiovf) +PART_DBGSTAT_CLEAR_BIT (emudoovf) + +PART_DBGSTAT_SET_BIT (emudiovf) +PART_DBGSTAT_SET_BIT (emudoovf) + + +uint16_t +part_dbgstat_emucause (urj_chain_t *chain, int n) +{ + urj_part_t *part; + uint16_t mask; + uint16_t emucause; + + part = chain->parts->parts[n]; + mask = _part_dbgstat_emucause_mask (part); + emucause = BFIN_PART_DBGSTAT (part) & mask; + + while (!(mask & 0x1)) + { + mask >>= 1; + emucause >>= 1; + } + + return emucause; +} + +void +chain_dbgstat_get (urj_chain_t *chain) +{ + urj_part_t *part; + int i; + + chain_scan_select (chain, DBGSTAT_SCAN); + + /* After doing a shiftDR you always must eventually do an + update-DR. The dbgstat and dbgctl registers are in the same scan + chain. Therefore when you want to read dbgstat you have to be + careful not to corrupt the dbgctl register in the process. So you + have to shift out the value that is currently in the dbgctl and + dbgstat registers, then shift back the same value into the dbgctl + so that when you do an updateDR you will not change the dbgctl + register when all you wanted to do is read the dbgstat value. */ + + for (i = 0; i < chain->parts->len; i++) + { + part = chain->parts->parts[i]; + + if (part_is_bypassed (chain, i)) + continue; + + if (_part_dbgctl_dbgstat_in_one_chain (part)) + _part_dbgctl_init (part, BFIN_PART_DBGCTL (part)); + } + + urj_tap_chain_shift_data_registers_mode (chain, 1, 1, URJ_CHAIN_EXITMODE_UPDATE); + + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + part = chain->parts->parts[i]; + BFIN_PART_DBGSTAT (part) = _part_dbgstat_value (part); + } +} + +void +part_dbgstat_get (urj_chain_t *chain, int n) +{ + urj_part_t *part; + + assert (n >= 0 && n < chain->parts->len); + + part_scan_select (chain, n, DBGSTAT_SCAN); + + /* See above comments. */ + + part = chain->parts->parts[n]; + + if (_part_dbgctl_dbgstat_in_one_chain (part)) + _part_dbgctl_init (part, BFIN_PART_DBGCTL (part)); + + urj_tap_chain_shift_data_registers_mode (chain, 1, 1, URJ_CHAIN_EXITMODE_UPDATE); + + BFIN_PART_DBGSTAT (part) = _part_dbgstat_value (part); +} + +void +chain_emupc_get (urj_chain_t *chain, int save) +{ + urj_part_t *part; + urj_tap_register_t *r; + int i; + + chain_scan_select (chain, EMUPC_SCAN); + + urj_tap_chain_shift_data_registers_mode (chain, 1, 1, URJ_CHAIN_EXITMODE_UPDATE); + for (i = 0; i < chain->parts->len; i++) + { + part = chain->parts->parts[i]; + + if (part_is_bypassed (chain, i)) + continue; + + r = part->active_instruction->data_register->out; + BFIN_PART_EMUPC (part) = register_value (r); + if (save) + BFIN_PART_EMUPC_ORIG (part) = BFIN_PART_EMUPC (part); + } +} + +uint32_t +part_emupc_get (urj_chain_t *chain, int n, int save) +{ + urj_part_t *part; + urj_tap_register_t *r; + + assert (n >= 0 && n < chain->parts->len); + + part_scan_select (chain, n, EMUPC_SCAN); + + urj_tap_chain_shift_data_registers_mode (chain, 1, 1, URJ_CHAIN_EXITMODE_UPDATE); + + part = chain->parts->parts[n]; + r = part->active_instruction->data_register->out; + BFIN_PART_EMUPC (part) = register_value (r); + if (save) + BFIN_PART_EMUPC_ORIG (part) = BFIN_PART_EMUPC (part); + + return BFIN_PART_EMUPC (part); +} + +void +chain_dbgstat_clear_ovfs (urj_chain_t *chain) +{ + int i; + + chain_scan_select (chain, DBGSTAT_SCAN); + + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + part_dbgstat_bit_set_emudiovf (chain, i); + part_dbgstat_bit_set_emudoovf (chain, i); + } + + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + part_dbgstat_bit_clear_emudiovf (chain, i); + part_dbgstat_bit_clear_emudoovf (chain, i); + } +} + +void +part_dbgstat_clear_ovfs (urj_chain_t *chain, int n) +{ + part_scan_select (chain, n, DBGSTAT_SCAN); + + part_dbgstat_bit_set_emudiovf (chain, n); + part_dbgstat_bit_set_emudoovf (chain, n); + + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + part_dbgstat_bit_clear_emudiovf (chain, n); + part_dbgstat_bit_clear_emudoovf (chain, n); +} + +void +chain_check_emuready (urj_chain_t *chain) +{ + int emuready; + int i; + + chain_dbgstat_get (chain); + emuready = 1; + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + if (!(part_dbgstat_is_emuready (chain, i))) + { + emuready = 0; + break; + } + } + + assert (emuready); +} + +void +part_check_emuready (urj_chain_t *chain, int n) +{ + int emuready; + + part_dbgstat_get (chain, n); + if (part_dbgstat_is_emuready (chain, n)) + emuready = 1; + else + emuready = 0; + + assert (emuready); +} + +int +part_sticky_in_reset (urj_chain_t *chain, int n) +{ + urj_part_t *part = chain->parts->parts[n]; + return _part_sticky_in_reset (part); +} + +void +chain_wait_in_reset (urj_chain_t *chain) +{ + int in_reset; + int i; + int waited = 0; + + try_again: + + chain_dbgstat_get (chain); + in_reset = 1; + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + if (!(part_dbgstat_is_in_reset (chain, i))) + { + in_reset = 0; + break; + } + } + + if (waited) + assert (in_reset); + + if (!in_reset) + { + nanosleep (&bfin_emu_wait_ts, NULL); + waited = 1; + goto try_again; + } +} + +void +part_wait_in_reset (urj_chain_t *chain, int n) +{ + int in_reset; + int waited = 0; + + try_again: + + part_dbgstat_get (chain, n); + if (part_dbgstat_is_in_reset (chain, n)) + in_reset = 1; + else + in_reset = 0; + + if (waited) + assert (in_reset); + + if (!in_reset) + { + nanosleep (&bfin_emu_wait_ts, NULL); + waited = 1; + goto try_again; + } +} + +void +chain_wait_reset (urj_chain_t *chain) +{ + int in_reset; + int i; + int waited = 0; + + try_again: + + chain_dbgstat_get (chain); + in_reset = 0; + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + if (part_dbgstat_is_in_reset (chain, i) && !part_sticky_in_reset (chain, i)) + { + in_reset = 1; + break; + } + } + + if (waited) + assert (!in_reset); + + if (in_reset) + { + nanosleep (&bfin_emu_wait_ts, NULL); + waited = 1; + goto try_again; + } +} + +void +part_wait_reset (urj_chain_t *chain, int n) +{ + int in_reset; + int waited = 0; + + try_again: + + part_dbgstat_get (chain, n); + if (part_dbgstat_is_in_reset (chain, n) && !part_sticky_in_reset (chain, n)) + in_reset = 1; + else + in_reset = 0; + + if (waited) + assert (!in_reset); + + if (in_reset) + { + nanosleep (&bfin_emu_wait_ts, NULL); + waited = 1; + goto try_again; + } +} + +static void +emuir_init_value (urj_tap_register_t *r, uint64_t insn) +{ + if (r->len == 32 || r->len == 34) + { + assert ((insn & 0xffffffff00000000ULL) == 0); + + if ((insn & 0xffffffffffff0000ULL) == 0) + register_init_value (r, insn << 16); + else + register_init_value (r, insn); + } + else + { + if ((insn & 0xffffffffffff0000ULL) == 0) + register_init_value (r, insn << 48); + else if ((insn & 0xffffffff00000000ULL) == 0) + register_init_value (r, insn << 32); + else + register_init_value (r, insn); + } + + /* If EMUIR has two identify bits, set it properly. + [len-1:len-2] is + 1 for 16-bit instruction. + 2 for 32-bit instruction. + 3 for 64-bit instruction. + [len-1] is in data[0] and [len-2] is in data[1]. */ + + if (r->len % 32 == 2) + { + if ((insn & 0xffffffffffff0000ULL) == 0) + { + r->data[0] = 0; + r->data[1] = 1; + } + else if ((insn & 0xffffffff00000000ULL) == 0) + { + r->data[0] = 1; + r->data[1] = 0; + } + else + r->data[0] = r->data[1] = 1; + } +} + +void +chain_emuir_set_same (urj_chain_t *chain, uint64_t insn, int exit) +{ + int emuir_scan; + urj_part_t *part; + urj_tap_register_t *r; + int i; + + assert (exit == URJ_CHAIN_EXITMODE_UPDATE || exit == URJ_CHAIN_EXITMODE_IDLE); + + if ((insn & 0xffffffff00000000ULL) == 0) + { + emuir_scan = EMUIR_SCAN; + + chain_scan_select (chain, DBGCTL_SCAN); + chain_dbgctl_bit_set_emuirsz_32 (chain); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + } + else + { + emuir_scan = EMUIR64_SCAN; + + chain_scan_select (chain, DBGCTL_SCAN); + chain_dbgctl_bit_set_emuirsz_64 (chain); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + } + + chain_scan_select (chain, emuir_scan); + + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + part = chain->parts->parts[i]; + r = part->active_instruction->data_register->in; + emuir_init_value (r, insn); + BFIN_PART_EMUIR_A (part) = insn; + } + + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, exit); + + if (exit == URJ_CHAIN_EXITMODE_IDLE && bfin_check_emuready) + chain_check_emuready (chain); +} + +void +part_emuir_set (urj_chain_t *chain, int n, uint64_t insn, int exit) +{ + int emuir_scan; + urj_part_t *part; + urj_tap_register_t *r; + int *changed; + int scan_changed; + int i; + + assert (exit == URJ_CHAIN_EXITMODE_UPDATE || exit == URJ_CHAIN_EXITMODE_IDLE); + + if ((insn & 0xffffffff00000000ULL) == 0) + { + emuir_scan = EMUIR_SCAN; + + part_scan_select (chain, n, DBGCTL_SCAN); + part_dbgctl_bit_set_emuirsz_32 (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + } + else + { + emuir_scan = EMUIR64_SCAN; + + part_scan_select (chain, n, DBGCTL_SCAN); + part_dbgctl_bit_set_emuirsz_64 (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + } + + assert (n >= 0 && n < chain->parts->len); + + changed = (int *) malloc (chain->parts->len *sizeof (int)); + + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + if (i == n && BFIN_PART_EMUIR_A (chain->parts->parts[i]) != insn) + { + BFIN_PART_EMUIR_A (chain->parts->parts[i]) = insn; + changed[i] = 1; + } + else if (i != n && BFIN_PART_EMUIR_A (chain->parts->parts[i]) != INSN_NOP) + { + BFIN_PART_EMUIR_A (chain->parts->parts[i]) = INSN_NOP; + changed[i] = 1; + } + else + changed[i] = 0; + } + + scan_changed = 0; + + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + if (changed[i]) + scan_changed += bfin_set_scan (chain->parts->parts[i], emuir_scan); + else + scan_changed += bfin_set_scan (chain->parts->parts[i], BYPASS); + } + + if (scan_changed) + urj_tap_chain_shift_instructions_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + if (changed[i]) + { + part = chain->parts->parts[i]; + r = part->active_instruction->data_register->in; + emuir_init_value (r, BFIN_PART_EMUIR_A (part)); + } + } + + free (changed); + + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, exit); + + if (exit == URJ_CHAIN_EXITMODE_IDLE && bfin_check_emuready) + part_check_emuready (chain, n); +} + +void +chain_emuir_set_same_2 (urj_chain_t *chain, uint64_t insn1, uint64_t insn2, int exit) +{ + urj_part_t *part; + urj_tap_register_t *r; + int emuir_scan; + int i; + + assert (exit == URJ_CHAIN_EXITMODE_UPDATE || exit == URJ_CHAIN_EXITMODE_IDLE); + + if ((insn1 & 0xffffffff00000000ULL) == 0 + && (insn2 & 0xffffffff00000000ULL) == 0) + { + emuir_scan = EMUIR_SCAN; + + chain_scan_select (chain, DBGCTL_SCAN); + chain_dbgctl_bit_set_emuirsz_32 (chain); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + } + else + { + emuir_scan = EMUIR64_SCAN; + + chain_scan_select (chain, DBGCTL_SCAN); + chain_dbgctl_bit_set_emuirsz_64 (chain); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + } + + chain_scan_select (chain, emuir_scan); + + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + part = chain->parts->parts[i]; + r = part->active_instruction->data_register->in; + emuir_init_value (r, insn2); + BFIN_PART_EMUIR_B (part) = insn2; + } + + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + part = chain->parts->parts[i]; + r = part->active_instruction->data_register->in; + emuir_init_value (r, insn1); + BFIN_PART_EMUIR_A (part) = insn1; + } + + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, exit); + if (exit == URJ_CHAIN_EXITMODE_IDLE && bfin_check_emuready) + chain_check_emuready (chain); +} + +void +part_emuir_set_2 (urj_chain_t *chain, int n, uint64_t insn1, uint64_t insn2, int exit) +{ + int emuir_scan; + urj_part_t *part; + urj_tap_register_t *r; + int *changed; + int scan_changed; + int i; + + assert (exit == URJ_CHAIN_EXITMODE_UPDATE || exit == URJ_CHAIN_EXITMODE_IDLE); + + if ((insn1 & 0xffffffff00000000ULL) == 0 + && (insn2 & 0xffffffff00000000ULL) == 0) + { + emuir_scan = EMUIR_SCAN; + + part_scan_select (chain, n, DBGCTL_SCAN); + part_dbgctl_bit_set_emuirsz_32 (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + } + else + { + emuir_scan = EMUIR64_SCAN; + + part_scan_select (chain, n, DBGCTL_SCAN); + part_dbgctl_bit_set_emuirsz_64 (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + } + + assert (n >= 0 && n < chain->parts->len); + + changed = (int *) malloc (chain->parts->len * sizeof (int)); + + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + if (i == n + && (BFIN_PART_EMUIR_A (chain->parts->parts[i]) != insn1 + || BFIN_PART_EMUIR_B (chain->parts->parts[i]) != insn2)) + { + BFIN_PART_EMUIR_A (chain->parts->parts[i]) = insn1; + BFIN_PART_EMUIR_B (chain->parts->parts[i]) = insn2; + changed[i] = 1; + } + else if (i != n + && BFIN_PART_EMUIR_A (chain->parts->parts[i]) != INSN_NOP) + { + BFIN_PART_EMUIR_A (chain->parts->parts[i]) = INSN_NOP; + changed[i] = 1; + } + else + changed[i] = 0; + } + + scan_changed = 0; + + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + if (changed[i]) + scan_changed += bfin_set_scan (chain->parts->parts[i], emuir_scan); + else + scan_changed += bfin_set_scan (chain->parts->parts[i], BYPASS); + } + + if (scan_changed) + urj_tap_chain_shift_instructions_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + if (changed[i] && i == n) + { + part = chain->parts->parts[i]; + r = part->active_instruction->data_register->in; + emuir_init_value (r, insn2); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + emuir_init_value (r, insn1); + } + else if (changed[i] && i != chain->active_part) + { + part = chain->parts->parts[i]; + r = part->active_instruction->data_register->in; + emuir_init_value (r, BFIN_PART_EMUIR_A (part)); + } + } + + free (changed); + + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, exit); + + if (exit == URJ_CHAIN_EXITMODE_IDLE && bfin_check_emuready) + part_check_emuready (chain, n); +} + +uint64_t +emudat_value (urj_tap_register_t *r) +{ + uint64_t value; + + value = register_value (r); + value >>= (r->len - 32); + + return value; +} + +void +emudat_init_value (urj_tap_register_t *r, uint32_t value) +{ + uint64_t v = value; + + v <<= (r->len - 32); + /* If the register size is larger than 32 bits, set EMUDIF. */ + if (r->len == 34 || r->len == 40 || r->len == 48) + v |= 0x1 << (r->len - 34); + + register_init_value (r, v); +} + +void +part_emudat_defer_get (urj_chain_t *chain, int n, int exit) +{ + int i; + urj_parts_t *ps; + + assert (exit == URJ_CHAIN_EXITMODE_UPDATE || exit == URJ_CHAIN_EXITMODE_IDLE); + + if (exit == URJ_CHAIN_EXITMODE_IDLE) + { + assert (urj_tap_state (chain) & URJ_TAP_STATE_IDLE); + urj_tap_chain_defer_clock (chain, 0, 0, 1); + } + + if (part_scan_select (chain, n, EMUDAT_SCAN) < 0) + abort (); + + if (!chain || !chain->parts) + return; + + ps = chain->parts; + + for (i = 0; i < ps->len; i++) + { + if (ps->parts[i]->active_instruction == NULL) + { + urj_log (URJ_LOG_LEVEL_ERROR, + _("Part %d without active instruction\n"), i); + return; + } + if (ps->parts[i]->active_instruction->data_register == NULL) + { + urj_log (URJ_LOG_LEVEL_ERROR, + _("Part %d without data register\n"), i); + return; + } + } + + urj_tap_capture_dr (chain); + + /* new implementation: split into defer + retrieve part + shift the data register of each part in the chain one by one */ + + for (i = 0; i < ps->len; i++) + { + urj_tap_defer_shift_register (chain, ps->parts[i]->active_instruction->data_register->in, + ps->parts[i]->active_instruction->data_register->out, + (i + 1) == ps->len ? URJ_CHAIN_EXITMODE_UPDATE : URJ_CHAIN_EXITMODE_SHIFT); + } +} + +uint32_t +part_emudat_get_done (urj_chain_t *chain, int n, int exit) +{ + urj_part_t *part; + urj_tap_register_t *r; + uint64_t value; + int i; + urj_parts_t *ps; + + ps = chain->parts; + + for (i = 0; i < ps->len; i++) + { + urj_tap_shift_register_output (chain, ps->parts[i]->active_instruction->data_register->in, + ps->parts[i]->active_instruction->data_register->out, + (i + 1) == ps->len ? URJ_CHAIN_EXITMODE_UPDATE : URJ_CHAIN_EXITMODE_SHIFT); + } + + part = chain->parts->parts[n]; + r = part->active_instruction->data_register->out; + value = emudat_value (r); + + /* TODO Is it good to check EMUDOF here if it's available? */ + + return value; +} + +/* These two emudat functions only care the payload data, which is the + upper 32 bits. Then follows EMUDOF and EMUDIF if the register size + is larger than 32 bits. Then the remaining is reserved or don't + care bits. */ + +uint32_t +part_emudat_get (urj_chain_t *chain, int n, int exit) +{ + urj_part_t *part; + urj_tap_register_t *r; + uint64_t value; + + assert (exit == URJ_CHAIN_EXITMODE_UPDATE || exit == URJ_CHAIN_EXITMODE_IDLE); + + if (exit == URJ_CHAIN_EXITMODE_IDLE) + { + assert (urj_tap_state (chain) & URJ_TAP_STATE_IDLE); + urj_tap_chain_defer_clock (chain, 0, 0, 1); + } + + if (part_scan_select (chain, n, EMUDAT_SCAN) < 0) + return -1; + + urj_tap_chain_shift_data_registers_mode (chain, 1, 1, URJ_CHAIN_EXITMODE_UPDATE); + part = chain->parts->parts[n]; + r = part->active_instruction->data_register->out; + value = emudat_value (r); + + /* TODO Is it good to check EMUDOF here if it's available? */ + + return value; +} + +void +part_emudat_set (urj_chain_t *chain, int n, uint32_t value, int exit) +{ + urj_part_t *part; + urj_tap_register_t *r; + + assert (exit == URJ_CHAIN_EXITMODE_UPDATE || exit == URJ_CHAIN_EXITMODE_IDLE); + + if (part_scan_select (chain, n, EMUDAT_SCAN) < 0) + return; + + part = chain->parts->parts[n]; + r = part->active_instruction->data_register->in; + emudat_init_value (r, value); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, exit); + + if (exit == URJ_CHAIN_EXITMODE_IDLE && bfin_check_emuready) + part_check_emuready (chain, n); +} + +/* Forward declarations */ +void chain_register_set (urj_chain_t *chain, enum core_regnum reg, uint32_t *value); +void part_register_set (urj_chain_t *chain, int n, enum core_regnum reg, + uint32_t value); + +void +chain_register_get (urj_chain_t *chain, enum core_regnum reg, uint32_t *value) +{ + urj_part_t *part; + urj_tap_register_t *r; + int i; + uint32_t *r0 = NULL; + + if (DREG_P (reg) || PREG_P (reg)) + chain_emuir_set_same (chain, gen_move (REG_EMUDAT, reg), URJ_CHAIN_EXITMODE_IDLE); + else + { + r0 = (uint32_t *)malloc (chain->parts->len * sizeof (uint32_t)); + if (!r0) + abort (); + + chain_register_get (chain, REG_R0, r0); + + chain_scan_select (chain, DBGCTL_SCAN); + chain_dbgctl_bit_set_emuirlpsz_2 (chain); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + chain_emuir_set_same_2 (chain, gen_move (REG_R0, reg), + gen_move (REG_EMUDAT, REG_R0), URJ_CHAIN_EXITMODE_IDLE); + + chain_scan_select (chain, DBGCTL_SCAN); + chain_dbgctl_bit_clear_emuirlpsz_2 (chain); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + } + + chain_scan_select (chain, EMUDAT_SCAN); + urj_tap_chain_shift_data_registers_mode (chain, 1, 1, URJ_CHAIN_EXITMODE_UPDATE); + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + part = chain->parts->parts[i]; + r = part->active_instruction->data_register->out; + value[i] = emudat_value (r); + } + + if (!DREG_P (reg) && !PREG_P (reg)) + { + chain_register_set (chain, REG_R0, r0); + free (r0); + } +} + +uint32_t +part_register_get (urj_chain_t *chain, int n, enum core_regnum reg) +{ + urj_part_t *part; + urj_tap_register_t *r; + uint32_t r0 = 0; + + if (DREG_P (reg) || PREG_P (reg)) + part_emuir_set (chain, n, gen_move (REG_EMUDAT, reg), URJ_CHAIN_EXITMODE_IDLE); + else + { + r0 = part_register_get (chain, n, REG_R0); + + part_scan_select (chain, n, DBGCTL_SCAN); + part_dbgctl_bit_set_emuirlpsz_2 (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + part_emuir_set_2 (chain, n, gen_move (REG_R0, reg), + gen_move (REG_EMUDAT, REG_R0), URJ_CHAIN_EXITMODE_IDLE); + + part_scan_select (chain, n, DBGCTL_SCAN); + part_dbgctl_bit_clear_emuirlpsz_2 (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + } + + part_scan_select (chain, n, EMUDAT_SCAN); + urj_tap_chain_shift_data_registers_mode (chain, 1, 1, URJ_CHAIN_EXITMODE_UPDATE); + part = chain->parts->parts[n]; + r = part->active_instruction->data_register->out; + + if (!DREG_P (reg) && !PREG_P (reg)) + part_register_set (chain, n, REG_R0, r0); + + return emudat_value (r); +} + +static void +chain_register_set_1 (urj_chain_t *chain, enum core_regnum reg, uint32_t *value, bool array) +{ + urj_part_t *part; + urj_tap_register_t *r; + int i; + uint32_t *r0 = NULL; + + if (!DREG_P (reg) && !PREG_P (reg)) + { + r0 = (uint32_t *)malloc (chain->parts->len * sizeof (uint32_t)); + if (!r0) + abort (); + + chain_register_get (chain, REG_R0, r0); + } + + chain_scan_select (chain, EMUDAT_SCAN); + for (i = 0; i < chain->parts->len; i++) + { + if (part_is_bypassed (chain, i)) + continue; + + part = chain->parts->parts[i]; + r = part->active_instruction->data_register->in; + emudat_init_value (r, array ? value[i] : *value); + } + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + if (DREG_P (reg) || PREG_P (reg)) + chain_emuir_set_same (chain, gen_move (reg, REG_EMUDAT), URJ_CHAIN_EXITMODE_IDLE); + else + { + chain_scan_select (chain, DBGCTL_SCAN); + chain_dbgctl_bit_set_emuirlpsz_2 (chain); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + chain_emuir_set_same_2 (chain, gen_move (REG_R0, REG_EMUDAT), + gen_move (reg, REG_R0), URJ_CHAIN_EXITMODE_IDLE); + + chain_scan_select (chain, DBGCTL_SCAN); + chain_dbgctl_bit_clear_emuirlpsz_2 (chain); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + chain_register_set (chain, REG_R0, r0); + free (r0); + } +} + +void +chain_register_set (urj_chain_t *chain, enum core_regnum reg, uint32_t *value) +{ + chain_register_set_1 (chain, reg, value, true); +} + +void +chain_register_set_same (urj_chain_t *chain, enum core_regnum reg, uint32_t value) +{ + chain_register_set_1 (chain, reg, &value, false); +} + +void +part_register_set (urj_chain_t *chain, int n, enum core_regnum reg, uint32_t value) +{ + urj_part_t *part; + urj_tap_register_t *r; + uint32_t r0 = 0; + + if (!DREG_P (reg) && !PREG_P (reg)) + r0 = part_register_get (chain, n, REG_R0); + + part_scan_select (chain, n, EMUDAT_SCAN); + + part = chain->parts->parts[n]; + r = part->active_instruction->data_register->in; + BFIN_PART_EMUDAT_IN (part) = value; + emudat_init_value (r, value); + + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + if (DREG_P (reg) || PREG_P (reg)) + part_emuir_set (chain, n, gen_move (reg, REG_EMUDAT), URJ_CHAIN_EXITMODE_IDLE); + else + { + part_scan_select (chain, n, DBGCTL_SCAN); + part_dbgctl_bit_set_emuirlpsz_2 (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + part_emuir_set_2 (chain, n, gen_move (REG_R0, REG_EMUDAT), + gen_move (reg, REG_R0), URJ_CHAIN_EXITMODE_IDLE); + + part_scan_select (chain, n, DBGCTL_SCAN); + part_dbgctl_bit_clear_emuirlpsz_2 (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + part_register_set (chain, n, REG_R0, r0); + } +} + +uint32_t +part_get_r0 (urj_chain_t *chain, int n) +{ + return part_register_get (chain, n, REG_R0); +} + +uint32_t +part_get_p0 (urj_chain_t *chain, int n) +{ + return part_register_get (chain, n, REG_P0); +} + +void +part_set_r0 (urj_chain_t *chain, int n, uint32_t value) +{ + part_register_set (chain, n, REG_R0, value); +} + +void +part_set_p0 (urj_chain_t *chain, int n, uint32_t value) +{ + part_register_set (chain, n, REG_P0, value); +} + +void +chain_emulation_enable (urj_chain_t *chain) +{ + chain_scan_select (chain, DBGCTL_SCAN); + + chain_dbgctl_bit_set_empwr (chain); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + chain_dbgctl_bit_set_emfen (chain); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + chain_dbgctl_bit_set_emuirsz_32 (chain); + chain_dbgctl_bit_set_emudatsz_40 (chain); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); +} + +void +part_emulation_enable (urj_chain_t *chain, int n) +{ + part_scan_select (chain, n, DBGCTL_SCAN); + + part_dbgctl_bit_set_empwr (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + part_dbgctl_bit_set_emfen (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + part_dbgctl_bit_set_emuirsz_32 (chain, n); + part_dbgctl_bit_set_emudatsz_40 (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); +} + +void +chain_emulation_disable (urj_chain_t *chain) +{ + chain_scan_select (chain, DBGCTL_SCAN); + chain_dbgctl_bit_clear_empwr (chain); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); +} + +void +part_emulation_disable (urj_chain_t *chain, int n) +{ + part_scan_select (chain, n, DBGCTL_SCAN); + part_dbgctl_bit_clear_empwr (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); +} + + +void +chain_emulation_trigger (urj_chain_t *chain) +{ + chain_emuir_set_same (chain, INSN_NOP, URJ_CHAIN_EXITMODE_UPDATE); + + chain_scan_select (chain, DBGCTL_SCAN); + chain_dbgctl_bit_set_wakeup (chain); + chain_dbgctl_bit_set_emeen (chain); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_IDLE); + + /* I don't know why, but the following code works. */ + /* Enter the emulation mode */ + urj_tap_chain_defer_clock (chain, 1, 0, 1); + /* Bring the TAP state to Update-DR */ + urj_tap_chain_defer_clock (chain, 0, 0, 1); + urj_tap_chain_defer_clock (chain, 1, 0, 2); +} + +void +part_emulation_trigger (urj_chain_t *chain, int n) +{ + part_emuir_set (chain, n, INSN_NOP, URJ_CHAIN_EXITMODE_UPDATE); + + part_scan_select (chain, n, DBGCTL_SCAN); + part_dbgctl_bit_set_wakeup (chain, n); + part_dbgctl_bit_set_emeen (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_IDLE); + + /* I don't know why, but the following code works. */ + /* Enter the emulation mode */ + urj_tap_chain_defer_clock (chain, 1, 0, 1); + /* Bring the TAP state to Update-DR */ + urj_tap_chain_defer_clock (chain, 0, 0, 1); + urj_tap_chain_defer_clock (chain, 1, 0, 2); +} + +void +chain_emulation_return (urj_chain_t *chain) +{ + chain_emuir_set_same (chain, INSN_RTE, URJ_CHAIN_EXITMODE_UPDATE); + + chain_scan_select (chain, DBGCTL_SCAN); + chain_dbgctl_bit_clear_emeen (chain); + chain_dbgctl_bit_clear_wakeup (chain); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_IDLE); +} + +void +part_emulation_return (urj_chain_t *chain, int n) +{ + part_emuir_set (chain, n, INSN_RTE, URJ_CHAIN_EXITMODE_UPDATE); + + part_scan_select (chain, n, DBGCTL_SCAN); + part_dbgctl_bit_clear_emeen (chain, n); + part_dbgctl_bit_clear_wakeup (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_IDLE); +} + +void +part_execute_instructions (urj_chain_t *chain, int n, struct bfin_insn *insns) +{ + while (insns) + { + if (insns->type == BFIN_INSN_NORMAL) + part_emuir_set (chain, n, insns->i, URJ_CHAIN_EXITMODE_IDLE); + else /* insns->type == BFIN_INSN_SET_EMUDAT */ + part_emudat_set (chain, n, insns->i, URJ_CHAIN_EXITMODE_UPDATE); + + insns = insns->next; + } + + return; +} + +void +chain_system_reset (urj_chain_t *chain) +{ + uint32_t p0, r0; + + p0 = part_get_p0 (chain, chain->main_part); + r0 = part_get_r0 (chain, chain->main_part); + + part_set_p0 (chain, chain->main_part, SWRST); + part_set_r0 (chain, chain->main_part, 0x7); + part_emuir_set (chain, chain->main_part, gen_store16_offset (REG_P0, 0, REG_R0), URJ_CHAIN_EXITMODE_IDLE); + part_emuir_set (chain, chain->main_part, INSN_SSYNC, URJ_CHAIN_EXITMODE_IDLE); + part_set_r0 (chain, chain->main_part, 0); + part_emuir_set (chain, chain->main_part, gen_store16_offset (REG_P0, 0, REG_R0), URJ_CHAIN_EXITMODE_IDLE); + part_emuir_set (chain, chain->main_part, INSN_SSYNC, URJ_CHAIN_EXITMODE_IDLE); + + part_set_p0 (chain, chain->main_part, p0); + part_set_r0 (chain, chain->main_part, r0); +} + +void +bfin_core_reset (urj_chain_t *chain) +{ + chain_emulation_disable (chain); + + part_emuir_set (chain, chain->main_part, INSN_NOP, URJ_CHAIN_EXITMODE_UPDATE); + + chain_scan_select (chain, DBGCTL_SCAN); + chain_dbgctl_bit_set_sram_init (chain); + part_dbgctl_bit_set_sysrst (chain, chain->main_part); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + chain_wait_in_reset (chain); + + chain_scan_select (chain, DBGCTL_SCAN); + part_dbgctl_bit_clear_sysrst (chain, chain->main_part); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + chain_wait_reset (chain); + + chain_emulation_enable (chain); + chain_emulation_trigger (chain); + + chain_scan_select (chain, DBGCTL_SCAN); + chain_dbgctl_bit_clear_sram_init (chain); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); +} + +void +software_reset (urj_chain_t *chain) +{ + chain_system_reset (chain); + bfin_core_reset (chain); +} + +void +chain_emupc_reset (urj_chain_t *chain, uint32_t *new_pc) +{ + uint32_t p0[chain->parts->len]; + int i; + + chain_register_get (chain, REG_P0, p0); + + for (i = 0; i < chain->parts->len; i++) + { + urj_part_t *part = chain->parts->parts[i]; + + if (part_is_bypassed (chain, i)) + continue; + + BFIN_PART_EMUPC (part) = new_pc[i]; + } + + chain_register_set (chain, REG_P0, new_pc); + chain_emuir_set_same (chain, gen_jump_reg (REG_P0), URJ_CHAIN_EXITMODE_IDLE); + + chain_register_set (chain, REG_P0, p0); +} + +uint32_t +part_mmr_read_clobber_r0 (urj_chain_t *chain, int n, int32_t offset, int size) +{ + uint32_t value; + + assert (size == 2 || size == 4); + + if (offset == 0) + { + part_scan_select (chain, n, DBGCTL_SCAN); + part_dbgctl_bit_set_emuirlpsz_2 (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + if (size == 2) + part_emuir_set_2 (chain, n, + gen_load16z (REG_R0, REG_P0), + gen_move (REG_EMUDAT, REG_R0), + URJ_CHAIN_EXITMODE_UPDATE); + else + part_emuir_set_2 (chain, n, + gen_load32 (REG_R0, REG_P0), + gen_move (REG_EMUDAT, REG_R0), + URJ_CHAIN_EXITMODE_UPDATE); + } + else + { + if (size == 2) + part_emuir_set (chain, n, gen_load16z_offset (REG_R0, REG_P0, offset), URJ_CHAIN_EXITMODE_IDLE); + else + part_emuir_set (chain, n, gen_load32_offset (REG_R0, REG_P0, offset), URJ_CHAIN_EXITMODE_IDLE); + part_emuir_set (chain, n, gen_move (REG_EMUDAT, REG_R0), URJ_CHAIN_EXITMODE_UPDATE); + } + value = part_emudat_get (chain, n, URJ_CHAIN_EXITMODE_IDLE); + + if (offset == 0) + { + part_scan_select (chain, n, DBGCTL_SCAN); + part_dbgctl_bit_clear_emuirlpsz_2 (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + } + + return value; +} + +uint32_t +part_mmr_read (urj_chain_t *chain, int n, uint32_t addr, int size) +{ + uint32_t p0, r0; + uint32_t value; + + p0 = part_register_get (chain, n, REG_P0); + r0 = part_register_get (chain, n, REG_R0); + + part_register_set (chain, n, REG_P0, addr); + value = part_mmr_read_clobber_r0 (chain, n, 0, size); + + part_register_set (chain, n, REG_P0, p0); + part_register_set (chain, n, REG_R0, r0); + + return value; +} + +void +part_mmr_write_clobber_r0 (urj_chain_t *chain, int n, int32_t offset, uint32_t data, int size) +{ + assert (size == 2 || size == 4); + + part_emudat_set (chain, n, data, URJ_CHAIN_EXITMODE_UPDATE); + + if (offset == 0) + { + part_scan_select (chain, n, DBGCTL_SCAN); + part_dbgctl_bit_set_emuirlpsz_2 (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + + if (size == 2) + part_emuir_set_2 (chain, n, + gen_move (REG_R0, REG_EMUDAT), + gen_store16 (REG_P0, REG_R0), + URJ_CHAIN_EXITMODE_IDLE); + else + part_emuir_set_2 (chain, n, + gen_move (REG_R0, REG_EMUDAT), + gen_store32 (REG_P0, REG_R0), + URJ_CHAIN_EXITMODE_IDLE); + } + else + { + part_emuir_set (chain, n, gen_move (REG_R0, REG_EMUDAT), URJ_CHAIN_EXITMODE_IDLE); + if (size == 2) + part_emuir_set (chain, n, gen_store16_offset (REG_P0, offset, REG_R0), URJ_CHAIN_EXITMODE_IDLE); + else + part_emuir_set (chain, n, gen_store32_offset (REG_P0, offset, REG_R0), URJ_CHAIN_EXITMODE_IDLE); + } + + if (offset == 0) + { + part_scan_select (chain, n, DBGCTL_SCAN); + part_dbgctl_bit_clear_emuirlpsz_2 (chain, n); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + } +} + +void +part_mmr_write (urj_chain_t *chain, int n, uint32_t addr, uint32_t data, int size) +{ + uint32_t p0, r0; + + p0 = part_register_get (chain, n, REG_P0); + r0 = part_register_get (chain, n, REG_R0); + + part_register_set (chain, n, REG_P0, addr); + part_mmr_write_clobber_r0 (chain, n, 0, data, size); + + part_register_set (chain, n, REG_P0, p0); + part_register_set (chain, n, REG_R0, r0); +} diff --git a/urjtag/src/bfin/insn-gen.c b/urjtag/src/bfin/insn-gen.c new file mode 100644 index 00000000..40df1acc --- /dev/null +++ b/urjtag/src/bfin/insn-gen.c @@ -0,0 +1,270 @@ +/* Copyright (C) 2008, 2009, 2010 Analog Devices, Inc. + * + * This file is subject to the terms and conditions of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2, or (at your option) any later + * version. See the file COPYING for more details. + * + * This file 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. + * + * Non-GPL License is also available. Please contact + * for more information. + */ + + +#include +#include + +#include + + +uint32_t +gen_move (enum core_regnum dest, enum core_regnum src) +{ + uint32_t insn; + + insn = 0x3000; + insn |= src & 0xf; + insn |= (dest & 0xf) << 3; + insn |= GROUP (src) << 6; + insn |= GROUP (dest) << 9; + + return insn; +} + +static uint32_t +gen_ldstidxi (enum core_regnum reg, + enum core_regnum ptr, int32_t offset, int w, int sz) +{ + uint32_t insn; + + insn = 0xe4000000; + insn |= (reg & 0xf) << 16; + insn |= (ptr & 0xf) << 19; + + switch (sz) + { + case 0: + offset >>= 2; + break; + case 1: + offset >>= 1; + break; + case 2: + break; + default: + abort (); + } + if (offset > 32767 || offset < -32768) + abort (); + insn |= offset & 0xffff; + + insn |= w << 25; + insn |= sz << 22; + + return insn; +} + +uint32_t +gen_load32_offset (enum core_regnum dest, enum core_regnum base, int32_t offset) +{ + return gen_ldstidxi (dest, base, offset, 0, 0); +} + +uint32_t +gen_store32_offset (enum core_regnum base, int32_t offset, enum core_regnum src) +{ + return gen_ldstidxi (src, base, offset, 1, 0); +} + +uint32_t +gen_load16z_offset (enum core_regnum dest, enum core_regnum base, int32_t offset) +{ + return gen_ldstidxi (dest, base, offset, 0, 1); +} + +uint32_t +gen_store16_offset (enum core_regnum base, int32_t offset, enum core_regnum src) +{ + return gen_ldstidxi (src, base, offset, 1, 1); +} + +uint32_t +gen_load8z_offset (enum core_regnum dest, enum core_regnum base, int32_t offset) +{ + return gen_ldstidxi (dest, base, offset, 0, 2); +} + +uint32_t +gen_store8_offset (enum core_regnum base, int32_t offset, enum core_regnum src) +{ + return gen_ldstidxi (src, base, offset, 1, 2); +} + +static uint32_t +gen_ldst (enum core_regnum reg, + enum core_regnum ptr, int post_dec, int w, int sz) +{ + uint32_t insn; + + insn = 0x9000; + insn |= reg & 0xf; + insn |= (ptr & 0xf) << 3; + insn |= post_dec << 7; + insn |= w << 9; + insn |= sz << 10; + + return insn; +} + +uint32_t +gen_load32pi (enum core_regnum dest, enum core_regnum base) +{ + return gen_ldst (dest, base, 0, 0, 0); +} + +uint32_t +gen_store32pi (enum core_regnum base, enum core_regnum src) +{ + return gen_ldst (src, base, 0, 1, 0); +} + +uint32_t +gen_load16zpi (enum core_regnum dest, enum core_regnum base) +{ + return gen_ldst (dest, base, 0, 0, 1); +} + +uint32_t +gen_store16pi (enum core_regnum base, enum core_regnum src) +{ + return gen_ldst (src, base, 0, 1, 1); +} + +uint32_t +gen_load8zpi (enum core_regnum dest, enum core_regnum base) +{ + return gen_ldst (dest, base, 0, 0, 2); +} + +uint32_t +gen_store8pi (enum core_regnum base, enum core_regnum src) +{ + return gen_ldst (src, base, 0, 1, 2); +} + +uint32_t +gen_load32 (enum core_regnum dest, enum core_regnum base) +{ + return gen_ldst (dest, base, 2, 0, 0); +} + +uint32_t +gen_store32 (enum core_regnum base, enum core_regnum src) +{ + return gen_ldst (src, base, 2, 1, 0); +} + +uint32_t +gen_load16z (enum core_regnum dest, enum core_regnum base) +{ + return gen_ldst (dest, base, 2, 0, 1); +} + +uint32_t +gen_store16 (enum core_regnum base, enum core_regnum src) +{ + return gen_ldst (src, base, 2, 1, 1); +} + +uint32_t +gen_load8z (enum core_regnum dest, enum core_regnum base) +{ + return gen_ldst (dest, base, 2, 0, 2); +} + +uint32_t +gen_store8 (enum core_regnum base, enum core_regnum src) +{ + return gen_ldst (src, base, 2, 1, 2); +} + +/* op + 0 prefetch + 1 flushinv + 2 flush + 3 iflush */ +static uint32_t +gen_flush_insn (enum core_regnum addr, int op, int post_modify) +{ + uint32_t insn; + + insn = 0x0240; + insn |= addr & 0xf; + insn |= op << 3; + insn |= post_modify << 5; + + return insn; +} + +uint32_t +gen_iflush (enum core_regnum addr) +{ + return gen_flush_insn (addr, 3, 0); +} + +uint32_t +gen_iflush_pm (enum core_regnum addr) +{ + return gen_flush_insn (addr, 3, 1); +} + +uint32_t +gen_flush (enum core_regnum addr) +{ + return gen_flush_insn (addr, 2, 0); +} + +uint32_t +gen_flush_pm (enum core_regnum addr) +{ + return gen_flush_insn (addr, 2, 1); +} + +uint32_t +gen_flushinv (enum core_regnum addr) +{ + return gen_flush_insn (addr, 1, 0); +} + +uint32_t +gen_flushinv_pm (enum core_regnum addr) +{ + return gen_flush_insn (addr, 1, 1); +} + +uint32_t +gen_prefetch (enum core_regnum addr) +{ + return gen_flush_insn (addr, 0, 0); +} + +uint32_t +gen_prefetch_pm (enum core_regnum addr) +{ + return gen_flush_insn (addr, 0, 1); +} + +uint32_t +gen_jump_reg (enum core_regnum addr) +{ + uint32_t insn; + + insn = 0x0050; + insn |= addr & 0x7; + + return insn; +} diff --git a/urjtag/src/cmd/Makefile.am b/urjtag/src/cmd/Makefile.am index 0b1402ad..a240c877 100644 --- a/urjtag/src/cmd/Makefile.am +++ b/urjtag/src/cmd/Makefile.am @@ -64,7 +64,8 @@ libcmd_la_SOURCES = \ cmd_include.c \ cmd_addpart.c \ cmd_cmd.c \ - cmd_usleep.c + cmd_usleep.c \ + cmd_bfin.c if ENABLE_SVF libcmd_la_SOURCES += cmd_svf.c diff --git a/urjtag/src/cmd/cmd_bfin.c b/urjtag/src/cmd/cmd_bfin.c new file mode 100644 index 00000000..4df9bd26 --- /dev/null +++ b/urjtag/src/cmd/cmd_bfin.c @@ -0,0 +1,570 @@ +/* Copyright (C) 2008, 2009, 2010 Analog Devices, Inc. + * + * 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. + */ + + +#include "sysdep.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "cmd.h" + +/* For "bfin execute", Blackfin assembler assembles instruction(s) + into a temporary object file. When this variable is non-zero, there + should be only one instruction in the object file. For example, + assembler assembles one instruction a time, which is how we do now. + + Blackfin GAS rounds the section size to 4 bytes. Usually we don't + want the padding bytes to be executed as a NOP. With this variable + set, only the first instruction in the object file will be + executed. */ + +int bfin_one_insn_a_file = 1; + +#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) + +static int +cmd_bfin_run (urj_chain_t *chain, char *params[]) +{ + int num_params; + + num_params = urj_cmd_params (params); + + if (num_params < 2) + { + urj_error_set (URJ_ERROR_SYNTAX, + "#parameters should be >= 2, not %d", + num_params); + return URJ_STATUS_FAIL; + } + + /* These commands don't need cable or parts. */ + + if (strcmp (params[1], "set") == 0) + { + if (num_params != 4) + { + urj_error_set (URJ_ERROR_BFIN, + "'bfin set' requires 2 parameters, not %d", + num_params - 2); + return URJ_STATUS_FAIL; + } + + if (strcmp (params[2], "one-insn-a-file") == 0) + { + if (strcmp (params[3], "0") == 0) + bfin_one_insn_a_file = 0; + else if (strcmp (params[3], "1") == 0) + bfin_one_insn_a_file = 1; + else + { + urj_error_set (URJ_ERROR_BFIN, + "bad value for one-insn-a-file '%s'", + params[3]); + return URJ_STATUS_FAIL; + } + } + else + { + urj_error_set (URJ_ERROR_BFIN, + "unknown set variable '%s'", + params[2]); + return URJ_STATUS_FAIL; + } + + return URJ_STATUS_OK; + } + else if (strcmp (params[1], "show") == 0) + { + int found = 0; + + if (num_params > 3) + { + urj_error_set (URJ_ERROR_BFIN, + "'bfin show' requires 0 or 1 parameter, not %d", + num_params - 2); + return URJ_STATUS_FAIL; + } + + if (num_params == 2 || strcmp (params[2], "one-insn-a-file") == 0) + { + found = 1; + urj_log (URJ_LOG_LEVEL_NORMAL, + "one-insn-a-file: %d\n", bfin_one_insn_a_file); + } + + if (!found && num_params == 3) + { + urj_error_set (URJ_ERROR_BFIN, + "unknown set variable '%s'", + params[2]); + return URJ_STATUS_FAIL; + } + + return URJ_STATUS_OK; + } + + /* The remaining commands require cable or parts. */ + + if (urj_cmd_test_cable (chain) != URJ_STATUS_OK) + return URJ_STATUS_FAIL; + + if (!chain->parts) + { + urj_error_set (URJ_ERROR_ILLEGAL_STATE, "no parts, Run '%s' first", + "detect"); + return URJ_STATUS_FAIL; + } + + if (chain->active_part >= chain->parts->len) + { + urj_error_set (URJ_ERROR_ILLEGAL_STATE, "no active part"); + return URJ_STATUS_FAIL; + } + + assert (chain->active_part >= 0 && chain->active_part < chain->parts->len); + + if (strcmp (params[1], "emulation") == 0) + { + if (num_params != 3) + { + urj_error_set (URJ_ERROR_BFIN, + "'bfin emulation' requires 1 parameter, not %d", + num_params - 2); + return URJ_STATUS_FAIL; + } + + if (strcmp (params[2], "enable") == 0) + { + part_emulation_enable (chain, chain->active_part); + } + else if (strcmp (params[2], "trigger") == 0) + { + part_emulation_trigger (chain, chain->active_part); + } + else if (strcmp (params[2], "enter") == 0) + { + part_emulation_enable (chain, chain->active_part); + part_emulation_trigger (chain, chain->active_part); + } + else if (strcmp (params[2], "return") == 0) + { + part_emulation_return (chain, chain->active_part); + } + else if (strcmp (params[2], "disable") == 0) + { + part_emulation_disable (chain, chain->active_part); + } + else if (strcmp (params[2], "exit") == 0) + { + part_emulation_return (chain, chain->active_part); + part_emulation_disable (chain, chain->active_part); + } + else if (strcmp (params[2], "status") == 0) + { + uint16_t dbgstat, excause; + const char *str_excause; + urj_part_t *part; + + part_dbgstat_get (chain, chain->active_part); + part = chain->parts->parts[chain->active_part]; + dbgstat = BFIN_PART_DBGSTAT (part); + excause = part_dbgstat_emucause (chain, chain->active_part); + + switch (excause) + { + case 0x0: str_excause = "EMUEXCPT was executed"; break; + case 0x1: str_excause = "EMUIN pin was asserted"; break; + case 0x2: str_excause = "Watchpoint event occurred"; break; + case 0x4: str_excause = "Performance Monitor 0 overflowed"; break; + case 0x5: str_excause = "Performance Monitor 1 overflowed"; break; + case 0x8: str_excause = "Emulation single step"; break; + default: str_excause = "Reserved??"; break; + } + + urj_log (URJ_LOG_LEVEL_NORMAL, "Core [%d] DBGSTAT = 0x%"PRIx16"\n", + chain->active_part, dbgstat); + + urj_log (URJ_LOG_LEVEL_NORMAL, + "\tEMUDOF = %u\n" + "\tEMUDIF = %u\n" + "\tEMUDOOVF = %u\n" + "\tEMUDIOVF = %u\n" + "\tEMUREADY = %u\n" + "\tEMUACK = %u\n" + "\tEMUCAUSE = 0x%x (%s)\n" + "\tBIST_DONE = %u\n" + "\tLPDEC0 = %u\n" + "\tIN_RESET = %u\n" + "\tIDLE = %u\n" + "\tCORE_FAULT = %u\n" + "\tLPDEC1 = %u\n", + part_dbgstat_is_emudof (chain, chain->active_part), + part_dbgstat_is_emudif (chain, chain->active_part), + part_dbgstat_is_emudoovf (chain, chain->active_part), + part_dbgstat_is_emudiovf (chain, chain->active_part), + part_dbgstat_is_emuready (chain, chain->active_part), + part_dbgstat_is_emuack (chain, chain->active_part), + excause, str_excause, + part_dbgstat_is_bist_done (chain, chain->active_part), + part_dbgstat_is_lpdec0 (chain, chain->active_part), + part_dbgstat_is_in_reset (chain, chain->active_part), + part_dbgstat_is_idle (chain, chain->active_part), + part_dbgstat_is_core_fault (chain, chain->active_part), + part_dbgstat_is_lpdec1 (chain, chain->active_part)); + } + else if (strcmp (params[2], "singlestep") == 0) + { + part_dbgstat_get (chain, chain->active_part); + + if (!part_dbgstat_is_emuready (chain, chain->active_part)) + { + urj_error_set (URJ_ERROR_BFIN, "Run '%s' first", + "bfin emulation enter"); + return URJ_STATUS_FAIL; + } + + /* TODO Allow an argument to specify how many single steps. */ + + part_scan_select (chain, chain->active_part, DBGCTL_SCAN); + part_dbgctl_bit_set_esstep (chain, chain->active_part); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + part_emuir_set (chain, chain->active_part, INSN_RTE, URJ_CHAIN_EXITMODE_IDLE); + part_scan_select (chain, chain->active_part, DBGCTL_SCAN); + part_dbgctl_bit_clear_esstep (chain, chain->active_part); + urj_tap_chain_shift_data_registers_mode (chain, 0, 1, URJ_CHAIN_EXITMODE_UPDATE); + } + else + { + urj_error_set (URJ_ERROR_BFIN, + "unknown emulation subcommand '%s'", params[2]); + return URJ_STATUS_FAIL; + } + + return URJ_STATUS_OK; + } + else if (strcmp (params[1], "execute") == 0) + { + int execute_ret = URJ_STATUS_FAIL; + + part_dbgstat_get (chain, chain->active_part); + + if (!part_dbgstat_is_emuready (chain, chain->active_part)) + { + urj_error_set (URJ_ERROR_BFIN, "Run '%s' first", + "bfin emulation enter"); + return URJ_STATUS_FAIL; + } + + if (num_params > 2) + { + int i; + struct bfin_insn *insns = NULL; + struct bfin_insn **last = &insns; + char tmp[8]; + char *tmpfile = NULL; + + for (i = 2; i < num_params; i++) + { + if (params[i][0] == '[' && params[i][1] == '0') + { + uint64_t n; + + if (sscanf (params[i], "[0%[xX]%"PRIx64"]", tmp, &n) != 2) + goto execute_cleanup; + + *last = (struct bfin_insn *) malloc (sizeof (struct bfin_insn)); + if (*last == NULL) + goto execute_cleanup; + + (*last)->i = n; + (*last)->type = BFIN_INSN_SET_EMUDAT; + (*last)->next = NULL; + last = &((*last)->next); + } + else if (params[i][0] == '0') + { + uint64_t n; + + if (sscanf (params[i], "0%[xX]%"PRIx64, tmp, &n) != 2) + goto execute_cleanup; + + *last = (struct bfin_insn *) malloc (sizeof (struct bfin_insn)); + if (*last == NULL) + goto execute_cleanup; + + (*last)->i = n; + (*last)->type = BFIN_INSN_NORMAL; + (*last)->next = NULL; + last = &((*last)->next); + } + else + { +#ifdef __MINGW32__ + urj_error_set (URJ_ERROR_BFIN, + "Sorry, dynamic code not available in windows"); + goto execute_cleanup; +#else + unsigned char raw_insn[4]; + char *tmp_buf; + char *tuples[] = {"uclinux", "linux-uclibc", "elf"}; + size_t t; + FILE *fp; + + /* 1024 should be plenty; MAXINPUTLINE is 100 in parse.c */ + char insns_string[1024]; + char *p = insns_string; + + for (; i < num_params; i++) + { + p += snprintf (p, sizeof (insns_string) - (p - insns_string), + "%s ", params[i]); + if (params[i][strlen (params[i]) - 1] == '"') + break; + if (params[i][strlen (params[i]) - 1] == ';') + break; + } + if (i == num_params) + { + urj_error_set (URJ_ERROR_BFIN, + "unbalanced double quotes"); + goto execute_cleanup; + } + + /* p points past the '\0'. p - 1 points to the ending '\0'. + p - 2 points to the last double quote. */ + *(p - 2) = ';'; + if (insns_string[0] == '"') + insns_string[0] = ' '; + + /* HRM states that branches and hardware loop setup results + in undefined behavior. Should check opcode instead? */ + if (strcasestr(insns_string, "jump") || + strcasestr(insns_string, "call") || + strcasestr(insns_string, "lsetup")) + urj_warning (_("jump/call/lsetup insns may not work in emulation\n")); + + + /* get a temporary file to work with -- a little racy */ + if (!tmpfile) + { + tmpfile = tmpnam (NULL); + if (!tmpfile) + goto execute_cleanup; + tmpfile = strdup (tmpfile); + if (!tmpfile) + goto execute_cleanup; + } + + /* try to find a toolchain in $PATH */ + for (t = 0; t < ARRAY_SIZE(tuples); ++t) + { + int ret; + + /* TODO Pass -mcpu= to gas. */ + asprintf (&tmp_buf, + "bfin-%3$s-as --version >/dev/null 2>&1 || exit $?;" + "echo '%1$s' | bfin-%3$s-as - -o \"%2$s\"" + " && bfin-%3$s-objcopy -O binary \"%2$s\"", + insns_string, tmpfile, tuples[t]); + ret = system (tmp_buf); + free (tmp_buf); + if (WIFEXITED(ret)) + { + if (WEXITSTATUS(ret) == 0) + break; + /* 127 -> not found in $PATH */ + else if (WEXITSTATUS(ret) == 127) + continue; + else + { + urj_error_set (URJ_ERROR_BFIN, "GAS failed parsing: %s", + insns_string); + goto execute_cleanup; + } + } + } + if (t == ARRAY_SIZE(tuples)) + { + urj_error_set (URJ_ERROR_BFIN, + "unable to find Blackfin toolchain in $PATH\n"); + goto execute_cleanup; + } + + /* Read the binary blob from the toolchain */ + fp = fopen (tmpfile, "rb"); + if (fp == NULL) + goto execute_cleanup; + + while (fread (raw_insn, 1, 2, fp) == 2) + { + uint16_t iw = raw_insn[0] | (raw_insn[1] << 8); + uint64_t n = iw; + int is_multiinsn = INSN_IS_MULTI (raw_insn[1]); + + if ((iw & 0xf000) >= 0xc000) + { + if (fread (raw_insn, 1, 2, fp) != 2) + goto execute_cleanup; + + iw = raw_insn[0] | (raw_insn[1] << 8); + n = (n << 16) | iw; + } + + if (is_multiinsn) + { + if (fread (raw_insn, 1, 4, fp) != 4) + goto execute_cleanup; + + n = (n << 32) + | ((uint64_t)raw_insn[0] << 16) + | ((uint64_t)raw_insn[1] << 24) + | raw_insn[2] | (raw_insn[3] << 8); + } + + *last = (struct bfin_insn *) malloc (sizeof (struct bfin_insn)); + if (*last == NULL) + goto execute_cleanup; + + (*last)->i = n; + (*last)->type = BFIN_INSN_NORMAL; + (*last)->next = NULL; + last = &((*last)->next); + + if (bfin_one_insn_a_file) + break; + } + + fclose (fp); +#endif + } + } + + part_execute_instructions (chain, chain->active_part, insns); + execute_ret = URJ_STATUS_OK; + + execute_cleanup: + if (tmpfile) + { + unlink (tmpfile); + free (tmpfile); + } + while (insns) + { + struct bfin_insn *tmp = insns->next; + free (insns); + insns = tmp; + } + } + + if (execute_ret == URJ_STATUS_OK) + { + uint64_t emudat; + + emudat = part_emudat_get (chain, chain->active_part, URJ_CHAIN_EXITMODE_UPDATE); + urj_log (URJ_LOG_LEVEL_NORMAL, "EMUDAT = 0x%"PRIx64"\n", emudat); + + part_dbgstat_get (chain, chain->active_part); + if (part_dbgstat_is_core_fault (chain, chain->active_part)) + urj_warning (_("core fault detected\n")); + } + + return execute_ret; + } + else if (strcmp (params[1], "reset") == 0) + { + int reset_what = 0; + + if (num_params == 3) + { + if (!strcmp (params[2], "core")) + reset_what |= 0x1; + else if (!strcmp (params[2], "system")) + reset_what |= 0x2; + else + { + urj_error_set (URJ_ERROR_BFIN, "bad parameter '%s'", params[2]); + return URJ_STATUS_FAIL; + } + } + else if (num_params == 2) + reset_what = 0x1 | 0x2; + else + { + urj_error_set (URJ_ERROR_BFIN, + "'bfin emulation' requires 0 or 1 parameter, not %d", + num_params - 2); + return URJ_STATUS_FAIL; + } + + urj_log (URJ_LOG_LEVEL_NORMAL, + _("%s: reseting processor ... "), "bfin"); + fflush (stdout); + if (reset_what == 0x3) + software_reset (chain); + else if (reset_what & 0x1) + bfin_core_reset (chain); + else if (reset_what & 0x2) + chain_system_reset (chain); + urj_log (URJ_LOG_LEVEL_NORMAL, _("OK\n")); + + return URJ_STATUS_OK; + } + else + { + urj_error_set (URJ_ERROR_BFIN, + "unknown command '%s'", params[1]); + return URJ_STATUS_FAIL; + } + + return URJ_STATUS_OK; +} + + +static void +cmd_bfin_help (void) +{ + urj_log (URJ_LOG_LEVEL_NORMAL, + _("Usage: %s execute INSTRUCTIONs\n" + "Usage: %s emulation enter|exit|singlestep|status\n" + "Usage: %s reset [core|system]\n" + "Usage: %s set one-insn-a-file VALUE\n" + "Usage: %s show [one-insn-a-file]\n" + "Blackfin specific commands\n" + "\n" + "INSTRUCTIONs are a sequence of Blackfin encoded instructions,\n" + "double quoted assembly statements and [EMUDAT_IN]s\n"), + "bfin", "bfin", "bfin", "bfin", "bfin" ); +} + +const urj_cmd_t urj_cmd_bfin = { + "bfin", + N_("Blackfin specific commands"), + cmd_bfin_help, + cmd_bfin_run +}; diff --git a/urjtag/src/cmd/cmd_list.h b/urjtag/src/cmd/cmd_list.h index 83459d14..6634e529 100644 --- a/urjtag/src/cmd/cmd_list.h +++ b/urjtag/src/cmd/cmd_list.h @@ -75,5 +75,6 @@ _URJ_CMD(svf) _URJ_CMD(bsdl) #endif _URJ_CMD(debug) +_URJ_CMD(bfin) #undef _URJ_CMD diff --git a/urjtag/src/global/log-error.c b/urjtag/src/global/log-error.c index f59b6249..7c3ab7f5 100644 --- a/urjtag/src/global/log-error.c +++ b/urjtag/src/global/log-error.c @@ -131,6 +131,8 @@ urj_error_string (urj_error_t err) case URJ_ERROR_BSDL_VHDL: return "vhdl subsystem"; case URJ_ERROR_BSDL_BSDL: return "bsdl subsystem"; + case URJ_ERROR_BFIN: return "blackfin"; + case URJ_ERROR_UNIMPLEMENTED: return "unimplemented"; } diff --git a/urjtag/src/part/part.c b/urjtag/src/part/part.c index a7a238e1..bf3a8421 100644 --- a/urjtag/src/part/part.c +++ b/urjtag/src/part/part.c @@ -35,6 +35,8 @@ #include #include +urj_part_init_t *urj_part_inits = NULL; + /* part */ urj_part_t * @@ -61,6 +63,7 @@ urj_part_alloc (const urj_tap_register_t *id) p->data_registers = NULL; p->boundary_length = 0; p->bsbits = NULL; + p->params = NULL; return p; } @@ -116,6 +119,10 @@ urj_part_free (urj_part_t *p) urj_part_bsbit_free (p->bsbits[i]); free (p->bsbits); + if (p->params && p->params->free) + p->params->free (p->params->data); + free (p->params); + free (p); } @@ -475,3 +482,27 @@ urj_part_parts_print (urj_log_level_t ll, urj_parts_t *ps) return URJ_STATUS_OK; } + +void +urj_part_init_register (char *part, urj_part_init_func_t init) +{ + urj_part_init_t *pi; + + pi = (urj_part_init_t *) malloc (sizeof (urj_part_init_t)); + strncpy (pi->part, part, URJ_PART_PART_MAXLEN); + pi->init = init; + pi->next = urj_part_inits; + urj_part_inits = pi; +} + +urj_part_init_func_t +urj_part_find_init (char *part) +{ + urj_part_init_t *pi; + + for (pi = urj_part_inits; pi; pi = pi->next) + if (strcmp (pi->part, part) == 0) + return pi->init; + + return NULL; +} diff --git a/urjtag/src/tap/detect.c b/urjtag/src/tap/detect.c index cb867799..9392f065 100644 --- a/urjtag/src/tap/detect.c +++ b/urjtag/src/tap/detect.c @@ -253,6 +253,7 @@ urj_tap_detect_parts (urj_chain_t *chain, const char *db_path) urj_tap_register_t *key; struct id_record idr; char *p; + urj_part_init_func_t part_init_func; urj_tap_shift_register (chain, one, br, URJ_CHAIN_EXITMODE_SHIFT); if (urj_tap_register_compare (one, br) == 0) @@ -392,8 +393,20 @@ urj_tap_detect_parts (urj_chain_t *chain, const char *db_path) if (part->active_instruction == NULL) part->active_instruction = urj_part_find_instruction (part, "IDCODE"); + + /* Do part specific initialization. */ + part_init_func = urj_part_find_init (part->part); + if (part_init_func) + { + part->params = (urj_part_params_t *) malloc (sizeof (urj_part_params_t)); + (*part_init_func) (part); + } + else + part->params = NULL; } + chain->main_part = ps->len - 1; + for (i = 0; i < 32; i++) { urj_tap_shift_register (chain, one, br, URJ_CHAIN_EXITMODE_SHIFT);