diff --git a/urjtag/ChangeLog b/urjtag/ChangeLog index d2820c14..666d6738 100644 --- a/urjtag/ChangeLog +++ b/urjtag/ChangeLog @@ -43,6 +43,11 @@ * src/cmd/cmd_debug.c: Drop local log level converters and use new common helpers. + * include/urjtag/bfin.h, src/bfin/bfin-part-bfin.c: Rewrite test_command + support to dynamically look up the set of MMRs needed in order to access + the requested memory. Some parts can only use ITEST, so hardcoding the + DTEST MMRs no longer works. + 2011-06-27 Jie Zhang * include/urjtag/Makefile.am (nodist_pkginclude_HEADERS): New and diff --git a/urjtag/include/urjtag/bfin.h b/urjtag/include/urjtag/bfin.h index af84ec62..20ce5f5a 100644 --- a/urjtag/include/urjtag/bfin.h +++ b/urjtag/include/urjtag/bfin.h @@ -75,17 +75,15 @@ struct emu_oab 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; + /* Get the MMRs needed to access this L1 address. */ + void (*test_command_mmrs) (urj_part_t *part, uint32_t addr, int icache, + uint32_t *command_addr, + uint32_t *data0_addr, uint32_t *data1_addr); + + /* Generate TEST_COMMAND from ADDR and W(rite), and return the MMRs + that need to be used for this access. */ + void (*test_command) (urj_part_t *part, uint32_t addr, int w, + uint32_t command_addr, uint32_t *command_value); /* No existing Blackfin processors use this. It should be 0. */ int dbgctl_dbgstat_in_one_chain; diff --git a/urjtag/src/bfin/bfin-part-bfin.c b/urjtag/src/bfin/bfin-part-bfin.c index 8991fbd1..c957cf33 100644 --- a/urjtag/src/bfin/bfin-part-bfin.c +++ b/urjtag/src/bfin/bfin-part-bfin.c @@ -46,27 +46,110 @@ bfin_dbgstat_value (urj_part_t *part) return urj_tap_register_get_value (part->active_instruction->data_register->out); } -static uint32_t -bfin_test_command (uint32_t addr, int w) +static void +bfin_test_command_mmrs (urj_part_t *part, uint32_t addr, int icache, + uint32_t *command_addr, + uint32_t *data0_addr, uint32_t *data1_addr) { - 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 */ + if (icache) { + *command_addr = ITEST_COMMAND; + *data0_addr = ITEST_DATA0; + *data1_addr = ITEST_DATA1; + } else { + *command_addr = DTEST_COMMAND; + *data0_addr = DTEST_DATA0; + *data1_addr = DTEST_DATA1; + } +} - return test_command; +static void +bfin_test_command (urj_part_t *part, uint32_t addr, int w, + uint32_t command_addr, uint32_t *command_value) +{ + /* The shifting here is a bit funky, but should be straight forward and + easier to maintain than hand coded masks. So, start with the break + down of the [DI]TEST_COMMAND MMR in the HRM and follow along: + + We need to put bit 11 of the address into bit 26 of the MMR. So first + we mask off ADDR[11] with: + (addr & (1 << 11)) + + Then we shift it from its current position (11) to its new one (26): + ((...) << (26 - 11)) + */ + + /* Start with the bits ITEST/DTEST share. */ + *command_value = + ((addr & (0x03 << 12)) << (16 - 12)) | /* ADDR[13:12] -> MMR[17:16] */ + ((addr & (0x01 << 14)) << (14 - 14)) | /* ADDR[14] -> MMR[14] */ + ((addr & (0xff << 3)) << ( 3 - 3)) | /* ADDR[10:3] -> MMR[10:3] */ + (1 << 2) | /* 1 (data) -> MMR[2] */ + (w << 1); /* read/write -> MMR[1] */ + + /* Now for the bits that aren't the same. */ + if (command_addr == ITEST_COMMAND) + *command_value |= + ((addr & (0x03 << 10)) << (26 - 10)); /* ADDR[11:10] -> MMR[27:26] */ + else + *command_value |= + ((addr & (0x01 << 11)) << (26 - 11)) | /* ADDR[11] -> MMR[26] */ + ((addr & (0x01 << 21)) << (24 - 21)); /* ADDR[21] -> MMR[24] */ + + /* Now, just for fun, some parts are slightly different. */ + if (command_addr == DTEST_COMMAND) + { + /* BF50x has no additional needs. */ + if (!strcmp (part->part, "BF518")) + { + /* MMR[23]: + 0 - Data Bank A (0xff800000) / Inst Bank A (0xffa00000) + 1 - Data Bank B (0xff900000) / Inst Bank B (0xffa04000) + */ + if ((addr & 0xfff04000) == 0xffa04000 || + (addr & 0xfff00000) == 0xff900000) + *command_value |= (1 << 23); + } + else if (!strcmp (part->part, "BF526") || + !strcmp (part->part, "BF527") || + !strcmp (part->part, "BF533") || + !strcmp (part->part, "BF534") || + !strcmp (part->part, "BF537") || + !strcmp (part->part, "BF538") || + !strcmp (part->part, "BF548") || + !strcmp (part->part, "BF548M")) + { + /* MMR[23]: + 0 - Data Bank A (0xff800000) / Inst Bank A (0xffa00000) + 1 - Data Bank B (0xff900000) / Inst Bank B (0xffa08000) + */ + if ((addr & 0xfff08000) == 0xffa08000 || + (addr & 0xfff00000) == 0xff900000) + *command_value |= (1 << 23); + } + else if (!strcmp (part->part, "BF561")) + { + /* MMR[23]: + 0 - Data Bank A (Core A: 0xff800000 Core B: 0xff400000) + Inst Bank A (Core A: 0xffa00000 Core B: 0xff600000) + 1 - Data Bank B (Core A: 0xff900000 Core B: 0xff500000) + N/A for Inst (no Bank B) + */ + uint32_t hi = (addr >> 20); + if (hi == 0xff9 || hi == 0xff5) + *command_value |= (1 << 23); + } + else if (!strcmp (part->part, "BF592")) + { + /* ADDR[15] -> MMR[15] + MMR[22]: + 0 - L1 Inst (0xffa00000) + 1 - L1 ROM (0xffa10000) + */ + *command_value |= (addr & (1 << 15)); + if ((addr >> 16) == 0xffa1) + *command_value |= (1 << 22); + } + } } struct emu_oab bfin_emu_oab = @@ -74,12 +157,9 @@ struct emu_oab bfin_emu_oab = bfin_dbgctl_init, bfin_dbgstat_value, + bfin_test_command_mmrs, bfin_test_command, - DTEST_COMMAND, - DTEST_DATA0, - DTEST_DATA1, - 0, /* dbgctl_dbgstat_in_one_chain */ 0, /* sticky_in_reset */ @@ -200,7 +280,7 @@ bfin_part_init (urj_part_t *part) extern void bfin_init (void); void -bfin_init () +bfin_init (void) { /* Keep in sync with data/analog/PARTS */ urj_part_init_register ("BF506", bfin_part_init);