From 6ce3e9c2a2cfb8849dd471349fe5e6bc37c0f13f Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Tue, 16 Mar 2010 14:40:17 +0000 Subject: Blackfin: add support for the DBGA (debug assert) pseudo insn A few pseudo debug insns exist to make testing of simulators easier. Since these don't actually exist in the hardware, we have to have the exception handler take care of emulating these. This allows sim test cases to be executed unmodified under Linux and thus simplify debugging greatly. Signed-off-by: Robin Getz Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/pseudodbg.c | 73 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 arch/blackfin/kernel/pseudodbg.c (limited to 'arch/blackfin/kernel/pseudodbg.c') diff --git a/arch/blackfin/kernel/pseudodbg.c b/arch/blackfin/kernel/pseudodbg.c new file mode 100644 index 00000000000..4474b8db350 --- /dev/null +++ b/arch/blackfin/kernel/pseudodbg.c @@ -0,0 +1,73 @@ +/* The fake debug assert instructions + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later + */ + +#include +#include +#include + +#define PseudoDbg_Assert_opcode 0xf0000000 +#define PseudoDbg_Assert_expected_bits 0 +#define PseudoDbg_Assert_expected_mask 0xffff +#define PseudoDbg_Assert_regtest_bits 16 +#define PseudoDbg_Assert_regtest_mask 0x7 +#define PseudoDbg_Assert_grp_bits 19 +#define PseudoDbg_Assert_grp_mask 0x7 +#define PseudoDbg_Assert_dbgop_bits 22 +#define PseudoDbg_Assert_dbgop_mask 0x3 +#define PseudoDbg_Assert_dontcare_bits 24 +#define PseudoDbg_Assert_dontcare_mask 0x7 +#define PseudoDbg_Assert_code_bits 27 +#define PseudoDbg_Assert_code_mask 0x1f + +bool execute_pseudodbg_assert(struct pt_regs *fp, unsigned int opcode) +{ + int expected = ((opcode >> PseudoDbg_Assert_expected_bits) & PseudoDbg_Assert_expected_mask); + int dbgop = ((opcode >> (PseudoDbg_Assert_dbgop_bits)) & PseudoDbg_Assert_dbgop_mask); + int grp = ((opcode >> (PseudoDbg_Assert_grp_bits)) & PseudoDbg_Assert_grp_mask); + int regtest = ((opcode >> (PseudoDbg_Assert_regtest_bits)) & PseudoDbg_Assert_regtest_mask); + long *value = &fp->r0; + + if ((opcode & 0xFF000000) != PseudoDbg_Assert_opcode) + return false; + + /* Only do Dregs and Pregs for now */ + if (grp > 1) + return false; + + /* + * Unfortunately, the pt_regs structure is not laid out the same way as the + * hardware register file, so we need to do some fix ups. + */ + if (grp == 0 || (grp == 1 && regtest < 6)) + value -= (regtest + 8 * grp); + else if (grp == 1 && regtest == 6) + value = &fp->usp; + else if (grp == 1 && regtest == 7) + value = &fp->fp; + + if (dbgop == 0 || dbgop == 2) { + /* DBGA ( regs_lo , uimm16 ) */ + /* DBGAL ( regs , uimm16 ) */ + if (expected != (*value & 0xFFFF)) { + pr_notice("DBGA (%s%i.L,0x%x) failure, got 0x%x\n", grp ? "P" : "R", + regtest, expected, (unsigned int)(*value & 0xFFFF)); + return false; + } + + } else if (dbgop == 1 || dbgop == 3) { + /* DBGA ( regs_hi , uimm16 ) */ + /* DBGAH ( regs , uimm16 ) */ + if (expected != ((*value >> 16) & 0xFFFF)) { + pr_notice("DBGA (%s%i.H,0x%x) failure, got 0x%x\n", grp ? "P" : "R", + regtest, expected, (unsigned int)((*value >> 16) & 0xFFFF)); + return false; + } + } + + fp->pc += 4; + return true; +} -- cgit v1.2.3-70-g09d2 From dc89d97fc73176c883b32ff21ae6f1164ca20d05 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Sun, 28 Mar 2010 12:50:53 +0000 Subject: Blackfin: add support for the DBG (debug output) pseudo insn Another pseudo insn used by Blackfin simulators. Also factor some now common register lookup code out of the DBGA handlers. Signed-off-by: Robin Getz Signed-off-by: Mike Frysinger --- arch/blackfin/include/asm/pseudo_instructions.h | 1 + arch/blackfin/kernel/pseudodbg.c | 86 +++++++++++++++++++------ arch/blackfin/kernel/traps.c | 2 + 3 files changed, 71 insertions(+), 18 deletions(-) (limited to 'arch/blackfin/kernel/pseudodbg.c') diff --git a/arch/blackfin/include/asm/pseudo_instructions.h b/arch/blackfin/include/asm/pseudo_instructions.h index 7173719fb53..b00adfa0816 100644 --- a/arch/blackfin/include/asm/pseudo_instructions.h +++ b/arch/blackfin/include/asm/pseudo_instructions.h @@ -13,5 +13,6 @@ #include extern bool execute_pseudodbg_assert(struct pt_regs *fp, unsigned int opcode); +extern bool execute_pseudodbg(struct pt_regs *fp, unsigned int opcode); #endif diff --git a/arch/blackfin/kernel/pseudodbg.c b/arch/blackfin/kernel/pseudodbg.c index 4474b8db350..a5a4636124a 100644 --- a/arch/blackfin/kernel/pseudodbg.c +++ b/arch/blackfin/kernel/pseudodbg.c @@ -9,6 +9,30 @@ #include #include +/* + * Unfortunately, the pt_regs structure is not laid out the same way as the + * hardware register file, so we need to do some fix ups. + */ +static bool fix_up_reg(struct pt_regs *fp, long *value, int grp, int reg) +{ + long *val = &fp->r0; + + /* Only do Dregs and Pregs for now */ + if (grp > 1) + return false; + + if (grp == 0 || (grp == 1 && reg < 6)) + val -= (reg + 8 * grp); + else if (grp == 1 && reg == 6) + val = &fp->usp; + else if (grp == 1 && reg == 7) + val = &fp->fp; + + *value = *val; + return true; + +} + #define PseudoDbg_Assert_opcode 0xf0000000 #define PseudoDbg_Assert_expected_bits 0 #define PseudoDbg_Assert_expected_mask 0xffff @@ -23,47 +47,38 @@ #define PseudoDbg_Assert_code_bits 27 #define PseudoDbg_Assert_code_mask 0x1f +/* + * DBGA - debug assert + */ bool execute_pseudodbg_assert(struct pt_regs *fp, unsigned int opcode) { int expected = ((opcode >> PseudoDbg_Assert_expected_bits) & PseudoDbg_Assert_expected_mask); int dbgop = ((opcode >> (PseudoDbg_Assert_dbgop_bits)) & PseudoDbg_Assert_dbgop_mask); int grp = ((opcode >> (PseudoDbg_Assert_grp_bits)) & PseudoDbg_Assert_grp_mask); int regtest = ((opcode >> (PseudoDbg_Assert_regtest_bits)) & PseudoDbg_Assert_regtest_mask); - long *value = &fp->r0; + long value; if ((opcode & 0xFF000000) != PseudoDbg_Assert_opcode) return false; - /* Only do Dregs and Pregs for now */ - if (grp > 1) + if (!fix_up_reg(fp, &value, grp, regtest)) return false; - /* - * Unfortunately, the pt_regs structure is not laid out the same way as the - * hardware register file, so we need to do some fix ups. - */ - if (grp == 0 || (grp == 1 && regtest < 6)) - value -= (regtest + 8 * grp); - else if (grp == 1 && regtest == 6) - value = &fp->usp; - else if (grp == 1 && regtest == 7) - value = &fp->fp; - if (dbgop == 0 || dbgop == 2) { /* DBGA ( regs_lo , uimm16 ) */ /* DBGAL ( regs , uimm16 ) */ - if (expected != (*value & 0xFFFF)) { + if (expected != (value & 0xFFFF)) { pr_notice("DBGA (%s%i.L,0x%x) failure, got 0x%x\n", grp ? "P" : "R", - regtest, expected, (unsigned int)(*value & 0xFFFF)); + regtest, expected, (unsigned int)(value & 0xFFFF)); return false; } } else if (dbgop == 1 || dbgop == 3) { /* DBGA ( regs_hi , uimm16 ) */ /* DBGAH ( regs , uimm16 ) */ - if (expected != ((*value >> 16) & 0xFFFF)) { + if (expected != ((value >> 16) & 0xFFFF)) { pr_notice("DBGA (%s%i.H,0x%x) failure, got 0x%x\n", grp ? "P" : "R", - regtest, expected, (unsigned int)((*value >> 16) & 0xFFFF)); + regtest, expected, (unsigned int)((value >> 16) & 0xFFFF)); return false; } } @@ -71,3 +86,38 @@ bool execute_pseudodbg_assert(struct pt_regs *fp, unsigned int opcode) fp->pc += 4; return true; } + +#define PseudoDbg_opcode 0xf8000000 +#define PseudoDbg_reg_bits 0 +#define PseudoDbg_reg_mask 0x7 +#define PseudoDbg_grp_bits 3 +#define PseudoDbg_grp_mask 0x7 +#define PseudoDbg_fn_bits 6 +#define PseudoDbg_fn_mask 0x3 +#define PseudoDbg_code_bits 8 +#define PseudoDbg_code_mask 0xff + +/* + * DBG - debug (dump a register value out) + */ +bool execute_pseudodbg(struct pt_regs *fp, unsigned int opcode) +{ + int grp, fn, reg; + long value; + + if ((opcode & 0xFF000000) != PseudoDbg_opcode) + return false; + + opcode >>= 16; + grp = ((opcode >> PseudoDbg_grp_bits) & PseudoDbg_reg_mask); + fn = ((opcode >> PseudoDbg_fn_bits) & PseudoDbg_fn_mask); + reg = ((opcode >> PseudoDbg_reg_bits) & PseudoDbg_reg_mask); + + if (!fix_up_reg(fp, &value, grp, reg)) + return false; + + pr_notice("DBG %s%d = %08lx\n", grp ? "P" : "R", reg, value); + + fp->pc += 2; + return true; +} diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 9369836365b..59c1df75e4d 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -213,6 +213,8 @@ asmlinkage notrace void trap_c(struct pt_regs *fp) if (!kernel_mode_regs(fp) && get_instruction(&opcode, (unsigned short *)fp->pc)) { if (execute_pseudodbg_assert(fp, opcode)) goto traps_done; + if (execute_pseudodbg(fp, opcode)) + goto traps_done; } #endif info.si_code = ILL_ILLOPC; -- cgit v1.2.3-70-g09d2 From 5a132f7aeba772e1e1f9ccbad14a6779cd40cdfb Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Mon, 29 Mar 2010 02:04:45 +0000 Subject: Blackfin: support all possible registers in the pseudo instructions Rather than decoding just the common R/P registers, handle all of them. Signed-off-by: Robin Getz Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/pseudodbg.c | 67 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 6 deletions(-) (limited to 'arch/blackfin/kernel/pseudodbg.c') diff --git a/arch/blackfin/kernel/pseudodbg.c b/arch/blackfin/kernel/pseudodbg.c index a5a4636124a..e57ce2f64bf 100644 --- a/arch/blackfin/kernel/pseudodbg.c +++ b/arch/blackfin/kernel/pseudodbg.c @@ -9,16 +9,43 @@ #include #include +const char * const greg_names[] = { + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", + "P0", "P1", "P2", "P3", "P4", "P5", "SP", "FP", + "I0", "I1", "I2", "I3", "M0", "M1", "M2", "M3", + "B0", "B1", "B2", "B3", "L0", "L1", "L2", "L3", + "A0.X", "A0.W", "A1.X", "A1.W", "", "", "ASTAT", "RETS", + "", "", "", "", "", "", "", "", + "LC0", "LT0", "LB0", "LC1", "LT1", "LB1", "CYCLES", "CYCLES2", + "USP", "SEQSTAT", "SYSCFG", "RETI", "RETX", "RETN", "RETE", "EMUDAT", +}; + +static const char *get_allreg_name(int grp, int reg) +{ + return greg_names[(grp << 3) | reg]; +} + /* * Unfortunately, the pt_regs structure is not laid out the same way as the * hardware register file, so we need to do some fix ups. + * + * CYCLES is not stored in the pt_regs structure - so, we just read it from + * the hardware. + * + * Don't support: + * - All reserved registers + * - All in group 7 are (supervisors only) */ + static bool fix_up_reg(struct pt_regs *fp, long *value, int grp, int reg) { long *val = &fp->r0; + unsigned long tmp; /* Only do Dregs and Pregs for now */ - if (grp > 1) + if (grp == 5 || + (grp == 4 && (reg == 4 || reg == 5)) || + (grp == 7)) return false; if (grp == 0 || (grp == 1 && reg < 6)) @@ -27,6 +54,32 @@ static bool fix_up_reg(struct pt_regs *fp, long *value, int grp, int reg) val = &fp->usp; else if (grp == 1 && reg == 7) val = &fp->fp; + else if (grp == 2) { + val = &fp->i0; + val -= reg; + } else if (grp == 3 && reg >= 4) { + val = &fp->l0; + val -= (reg - 4); + } else if (grp == 3 && reg < 4) { + val = &fp->b0; + val -= reg; + } else if (grp == 4 && reg < 4) { + val = &fp->a0x; + val -= reg; + } else if (grp == 4 && reg == 6) + val = &fp->astat; + else if (grp == 4 && reg == 7) + val = &fp->rets; + else if (grp == 6 && reg < 6) { + val = &fp->lc0; + val -= reg; + } else if (grp == 6 && reg == 6) { + __asm__ __volatile__("%0 = cycles;\n" : "=d"(tmp)); + val = &tmp; + } else if (grp == 6 && reg == 7) { + __asm__ __volatile__("%0 = cycles2;\n" : "=d"(tmp)); + val = &tmp; + } *value = *val; return true; @@ -68,8 +121,9 @@ bool execute_pseudodbg_assert(struct pt_regs *fp, unsigned int opcode) /* DBGA ( regs_lo , uimm16 ) */ /* DBGAL ( regs , uimm16 ) */ if (expected != (value & 0xFFFF)) { - pr_notice("DBGA (%s%i.L,0x%x) failure, got 0x%x\n", grp ? "P" : "R", - regtest, expected, (unsigned int)(value & 0xFFFF)); + pr_notice("DBGA (%s.L,0x%x) failure, got 0x%x\n", + get_allreg_name(grp, regtest), + expected, (unsigned int)(value & 0xFFFF)); return false; } @@ -77,8 +131,9 @@ bool execute_pseudodbg_assert(struct pt_regs *fp, unsigned int opcode) /* DBGA ( regs_hi , uimm16 ) */ /* DBGAH ( regs , uimm16 ) */ if (expected != ((value >> 16) & 0xFFFF)) { - pr_notice("DBGA (%s%i.H,0x%x) failure, got 0x%x\n", grp ? "P" : "R", - regtest, expected, (unsigned int)((value >> 16) & 0xFFFF)); + pr_notice("DBGA (%s.H,0x%x) failure, got 0x%x\n", + get_allreg_name(grp, regtest), + expected, (unsigned int)((value >> 16) & 0xFFFF)); return false; } } @@ -116,7 +171,7 @@ bool execute_pseudodbg(struct pt_regs *fp, unsigned int opcode) if (!fix_up_reg(fp, &value, grp, reg)) return false; - pr_notice("DBG %s%d = %08lx\n", grp ? "P" : "R", reg, value); + pr_notice("DBG %s = %08lx\n", get_allreg_name(grp, reg), value); fp->pc += 2; return true; -- cgit v1.2.3-70-g09d2 From a6d9dbf5e4daaf21b33917a809a5ac1e7bce9e05 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Mon, 29 Mar 2010 04:30:40 +0000 Subject: Blackfin: show the whole accumulator in the pseudo DBG insn Rather than print just part of the accumulator register, show the whole 40 bits. This matches the simulator behavior better. Signed-off-by: Robin Getz Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/pseudodbg.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'arch/blackfin/kernel/pseudodbg.c') diff --git a/arch/blackfin/kernel/pseudodbg.c b/arch/blackfin/kernel/pseudodbg.c index e57ce2f64bf..db85bc94334 100644 --- a/arch/blackfin/kernel/pseudodbg.c +++ b/arch/blackfin/kernel/pseudodbg.c @@ -158,7 +158,7 @@ bool execute_pseudodbg_assert(struct pt_regs *fp, unsigned int opcode) bool execute_pseudodbg(struct pt_regs *fp, unsigned int opcode) { int grp, fn, reg; - long value; + long value, value1; if ((opcode & 0xFF000000) != PseudoDbg_opcode) return false; @@ -168,11 +168,24 @@ bool execute_pseudodbg(struct pt_regs *fp, unsigned int opcode) fn = ((opcode >> PseudoDbg_fn_bits) & PseudoDbg_fn_mask); reg = ((opcode >> PseudoDbg_reg_bits) & PseudoDbg_reg_mask); - if (!fix_up_reg(fp, &value, grp, reg)) - return false; + if (fn == 3 && (reg == 0 || reg == 1)) { + if (!fix_up_reg(fp, &value, 4, 2 * reg)) + return false; + if (!fix_up_reg(fp, &value1, 4, 2 * reg + 1)) + return false; - pr_notice("DBG %s = %08lx\n", get_allreg_name(grp, reg), value); + pr_notice("DBG A%i = %02lx%08lx\n", reg, value & 0xFF, value1); + fp->pc += 2; + return true; - fp->pc += 2; - return true; + } else if (fn == 0) { + if (!fix_up_reg(fp, &value, grp, reg)) + return false; + + pr_notice("DBG %s = %08lx\n", get_allreg_name(grp, reg), value); + fp->pc += 2; + return true; + } + + return false; } -- cgit v1.2.3-70-g09d2