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 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); }
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) = bfin_register_get_value (r); if (save) BFIN_PART_EMUPC_ORIG (part) = BFIN_PART_EMUPC (part); return BFIN_PART_EMUPC (part); }
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_bfin (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_bfin (chain, i) && 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_bfin (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]) { 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); }
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; } /* 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; } if (!part_is_bfin (chain, chain->active_part)) { urj_error_set (URJ_ERROR_ILLEGAL_STATE, "not a Blackfin 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 { #ifndef HAVE_SYS_WAIT_H urj_error_set (URJ_ERROR_BFIN, "Sorry, dynamic code not available for your platform"); 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. */ 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. */ ret = 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]); if (ret == -1) { urj_error_set (URJ_ERROR_OUT_OF_MEMORY, _("asprintf() failed")); goto execute_cleanup; } 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, FOPEN_R); if (fp == NULL) goto execute_cleanup; /* Figure out how many instructions there are */ t = 0; p = insns_string; while ((p = strchr(p, ';')) != NULL) { ++t; ++p; } while (t-- && 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); } 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; 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 == 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, chain->active_part); else if (reset_what & 0x1) bfin_core_reset (chain, chain->active_part); 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; }