mirror of
https://github.com/pspdev/pspsdk.git
synced 2025-12-25 13:04:59 +00:00
first commit
This commit is contained in:
50
src/debug/Makefile.am
Normal file
50
src/debug/Makefile.am
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
libdir = @PSPSDK_LIBDIR@
|
||||
|
||||
CC = @PSP_CC@
|
||||
CCAS = $(CC)
|
||||
AR = @PSP_AR@
|
||||
RANLIB = @PSP_RANLIB@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/base \
|
||||
-I$(top_srcdir)/src/kernel \
|
||||
-I$(top_srcdir)/src/display \
|
||||
-I$(top_srcdir)/src/ge \
|
||||
-I$(top_srcdir)/src/user \
|
||||
-I$(top_srcdir)/src/ctrl
|
||||
CFLAGS = @PSPSDK_CFLAGS@
|
||||
CCASFLAGS = $(CFLAGS) $(INCLUDES)
|
||||
|
||||
SCRPRINT_OBJS = pspDebugScreenInit.o pspDebugScreenPrintf.o pspDebugScreenKprintf.o
|
||||
|
||||
libpspdebugincludedir = @PSPSDK_INCLUDEDIR@
|
||||
libpspdebuginclude_HEADERS = \
|
||||
pspdebug.h pspdebugkb.h
|
||||
|
||||
lib_LIBRARIES = libpspdebug.a libpspgdb.a libpspgdb_user.a libpspgdb_kernel.a libpspdebugkb.a
|
||||
|
||||
libpspdebug_a_SOURCES = \
|
||||
callstack.c \
|
||||
callstackget.S \
|
||||
font.c \
|
||||
scr_printf.c \
|
||||
exception.c \
|
||||
exception_asm.S \
|
||||
kprintf.c \
|
||||
stacktrace.c \
|
||||
profiler.c \
|
||||
stdio.c \
|
||||
sio.c
|
||||
|
||||
libpspdebug_a_LIBADD = $(SCRPRINT_OBJS)
|
||||
|
||||
libpspgdb_a_SOURCES = gdb-stub.c
|
||||
|
||||
libpspgdb_user_a_SOURCES = gdb-userlib.c
|
||||
|
||||
libpspgdb_kernel_a_SOURCES = gdb-kernellib.c
|
||||
|
||||
libpspdebugkb_a_SOURCES = pspdebugkb.c
|
||||
|
||||
$(SCRPRINT_OBJS): scr_printf.c
|
||||
$(COMPILE) -DF_$* $< -c -o $@
|
||||
256
src/debug/callstack.c
Normal file
256
src/debug/callstack.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* callstack.c - Return stack generation for MIPS processors.
|
||||
*
|
||||
* Copyright (c) 1992, 1998 The Open Group
|
||||
* Copyright (c) 2005 Marcus R. Brown <mrbrown@ocgnet.org>
|
||||
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
||||
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
|
||||
*
|
||||
* $Id: callstack.c 1492 2005-11-26 23:19:30Z mrbrown $
|
||||
*/
|
||||
|
||||
#include "pspdebug.h"
|
||||
|
||||
/*
|
||||
* $Xorg: getretmips.c,v 1.4 2001/02/09 02:06:19 xorgcvs Exp$
|
||||
*
|
||||
Copyright 1992, 1998 The Open Group
|
||||
|
||||
Permission to use, copy, modify, distribute, and sell this software and its
|
||||
documentation for any purpose is hereby granted without fee, provided that
|
||||
the above copyright notice appear in all copies and that both that
|
||||
copyright notice and this permission notice appear in supporting
|
||||
documentation.
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of The Open Group shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from The Open Group.
|
||||
*
|
||||
* Author: Keith Packard, MIT X Consortium
|
||||
* cleaned up slighly by emoon and added ee related opcodes and checking.
|
||||
*/
|
||||
|
||||
/* Return stack generation for MIPS processors
|
||||
* This is tricky as MIPS stack frames aren't
|
||||
* easily unrolled -- we look for pc restoration
|
||||
* and stack adjustment instructions beyond the return
|
||||
* address to discover the correct values
|
||||
*/
|
||||
|
||||
/* lw $31,const($sp) is : 100 011 11101 11111 const */
|
||||
/* 1000 1111 1011 1111 */
|
||||
|
||||
#define RESTORE_RETURNVAL 0x8fbf0000
|
||||
#define RESTORE_RETURNVAL_MASK 0xffff0000
|
||||
|
||||
/* ld $31,const($sp) is : 110 111 11101 11111 const */
|
||||
/* 1101 1111 1011 1111 */
|
||||
|
||||
#define RESTORE_RETURNVAL2 0xdfbf0000
|
||||
|
||||
/* lq $31,const($sp) is : 011110 11101 11111 const */
|
||||
/* ee Related 0111 1011 1011 1111 */
|
||||
|
||||
#define RESTORE_RETURNVAL3 0x7bbf0000
|
||||
|
||||
/* addiu $sp, $sp, const is 001 001 11101 11101 const */
|
||||
/* 0010 0111 1011 1101 const */
|
||||
|
||||
#define ADJUST_STACKP_C 0x27bd0000
|
||||
#define ADJUST_STACKP_C_MASK 0xffff0000
|
||||
|
||||
/* addu $sp, $sp, $at is 000 000 11101 00001 11101 00000 100 001 */
|
||||
/* 0000 0011 1010 0001 1110 1000 0010 0001 */
|
||||
|
||||
#define ADJUST_STACKP_V 0x03a1e821
|
||||
#define ADJUST_STACKP_V_MASK 0xffffffff
|
||||
|
||||
/* lui $at, const is 001 111 00000 00001 const */
|
||||
/* 0011 1100 0000 0001 const */
|
||||
|
||||
#define SET_UPPER_C 0x3c010000
|
||||
#define SET_UPPER_C_MASK 0xffff0000
|
||||
|
||||
/* ori $at, $at, const is 001 101 00001 00001 const */
|
||||
/* 0011 0100 0010 0001 const */
|
||||
|
||||
#define OR_LOWER_C 0x34210000
|
||||
#define OR_LOWER_C_MASK 0xffff0000
|
||||
|
||||
/* ori $at, $zero, const is 001 101 00000 00001 const */
|
||||
/* 0011 0100 0000 0001 const */
|
||||
|
||||
#define SET_LOWER_C 0x34010000
|
||||
#define SET_LOWER_C_MASK 0xffff0000
|
||||
|
||||
/* jr $ra */
|
||||
#define RETURN 0x03e00008
|
||||
|
||||
#define CALL(f) (0x0c000000 | (((int) (f)) >> 2))
|
||||
|
||||
/*
|
||||
* This computation is expensive, so we cache the results;
|
||||
* a simple hash function and straight-forward replacement.
|
||||
*/
|
||||
|
||||
#define HASH_SIZE 256
|
||||
|
||||
typedef struct _returnCache
|
||||
{
|
||||
unsigned int *returnAddress;
|
||||
int raOffset;
|
||||
int spAdjust;
|
||||
} ReturnCacheRec, *ReturnCachePtr;
|
||||
|
||||
static ReturnCacheRec returnCache[HASH_SIZE];
|
||||
|
||||
#define HASH(ra) ((((int) (ra)) >> 2) & (HASH_SIZE - 1))
|
||||
|
||||
typedef int Bool;
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
extern unsigned int *pspGetReturnAddress();
|
||||
extern unsigned int *pspGetStackPointer();
|
||||
extern int main();
|
||||
|
||||
int pspDebugGetStackTrace(unsigned int *results, int max)
|
||||
{
|
||||
unsigned int *ra;
|
||||
unsigned int *ra_limit;
|
||||
unsigned int *sp;
|
||||
unsigned int inst;
|
||||
unsigned int mainCall;
|
||||
unsigned short const_upper;
|
||||
unsigned short const_lower;
|
||||
int ra_offset;
|
||||
int sp_adjust;
|
||||
Bool found_ra_offset, found_sp_adjust;
|
||||
Bool found_const_upper, found_const_lower;
|
||||
ReturnCachePtr rc;
|
||||
int total = max;
|
||||
|
||||
ra = pspGetReturnAddress();
|
||||
sp = pspGetStackPointer();
|
||||
mainCall = CALL(main);
|
||||
|
||||
while (ra && max)
|
||||
{
|
||||
rc = &returnCache[HASH(ra)];
|
||||
if (rc->returnAddress != ra)
|
||||
{
|
||||
found_ra_offset = FALSE;
|
||||
found_sp_adjust = FALSE;
|
||||
found_const_upper = FALSE;
|
||||
found_const_lower = FALSE;
|
||||
const_upper = 0;
|
||||
const_lower = 0;
|
||||
rc->returnAddress = ra;
|
||||
ra_limit = (unsigned int *) 0x200000;
|
||||
ra_offset = 0;
|
||||
sp_adjust = -1;
|
||||
|
||||
while ((!found_ra_offset || !found_sp_adjust) && ra < ra_limit)
|
||||
{
|
||||
inst = *ra;
|
||||
/* look for the offset of the PC in the stack frame */
|
||||
if ((inst & RESTORE_RETURNVAL_MASK) == RESTORE_RETURNVAL)
|
||||
{
|
||||
ra_offset = inst & ~RESTORE_RETURNVAL_MASK;
|
||||
found_ra_offset = TRUE;
|
||||
}
|
||||
else if ((inst & RESTORE_RETURNVAL_MASK) == RESTORE_RETURNVAL2)
|
||||
{
|
||||
ra_offset = inst & ~RESTORE_RETURNVAL_MASK;
|
||||
found_ra_offset = TRUE;
|
||||
}
|
||||
else if ((inst & RESTORE_RETURNVAL_MASK) == RESTORE_RETURNVAL3)
|
||||
{
|
||||
ra_offset = inst & ~RESTORE_RETURNVAL_MASK;
|
||||
found_ra_offset = TRUE;
|
||||
}
|
||||
else if ((inst & ADJUST_STACKP_C_MASK) == ADJUST_STACKP_C)
|
||||
{
|
||||
sp_adjust = inst & ~ADJUST_STACKP_C_MASK;
|
||||
found_sp_adjust = TRUE;
|
||||
}
|
||||
else if ((inst & ADJUST_STACKP_V_MASK) == ADJUST_STACKP_V)
|
||||
{
|
||||
sp_adjust = 0;
|
||||
found_sp_adjust = TRUE;
|
||||
}
|
||||
else if ((inst & SET_UPPER_C_MASK) == SET_UPPER_C)
|
||||
{
|
||||
const_upper = inst & ~SET_UPPER_C_MASK;
|
||||
const_lower = 0;
|
||||
found_const_upper = TRUE;
|
||||
}
|
||||
else if ((inst & OR_LOWER_C_MASK) == OR_LOWER_C)
|
||||
{
|
||||
const_lower = inst & ~OR_LOWER_C_MASK;
|
||||
found_const_lower = TRUE;
|
||||
}
|
||||
else if ((inst & SET_LOWER_C_MASK) == SET_LOWER_C)
|
||||
{
|
||||
const_lower = inst & ~SET_LOWER_C_MASK;
|
||||
const_upper = 0;
|
||||
found_const_lower = TRUE;
|
||||
}
|
||||
else if (inst == RETURN)
|
||||
ra_limit = ra + 2;
|
||||
|
||||
ra++;
|
||||
}
|
||||
|
||||
if (sp_adjust == 0 && (found_const_upper || found_const_lower))
|
||||
sp_adjust = (const_upper << 16) | const_lower;
|
||||
rc->raOffset = ra_offset;
|
||||
rc->spAdjust = sp_adjust;
|
||||
}
|
||||
/* if something went wrong, punt */
|
||||
if (rc->spAdjust <= 0)
|
||||
{
|
||||
*results++ = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ra = (unsigned int *) sp[rc->raOffset >> 2];
|
||||
sp += rc->spAdjust >> 2;
|
||||
|
||||
if (ra == 0)
|
||||
{
|
||||
*results++ = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
*results++ = ((unsigned int) ra) - 8;
|
||||
max--;
|
||||
|
||||
if (ra[-2] == mainCall)
|
||||
{
|
||||
*results++ = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return total - max;
|
||||
}
|
||||
46
src/debug/callstackget.S
Normal file
46
src/debug/callstackget.S
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* $XConsortium: mipsstack.s,v 1.3 94/04/17 20:59:45 keith Exp $
|
||||
*
|
||||
Copyright (c) 1992 X Consortium
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"),
|
||||
to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of the X Consortium shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from the X Consortium.
|
||||
*
|
||||
* Author: Keith Packard, MIT X Consortium
|
||||
*/
|
||||
|
||||
.globl pspGetReturnAddress
|
||||
.ent pspGetReturnAddress
|
||||
pspGetReturnAddress:
|
||||
.frame $sp, 0, $31
|
||||
move $2,$31
|
||||
j $31
|
||||
.end pspGetReturnAddress
|
||||
|
||||
.globl pspGetStackPointer
|
||||
.ent pspGetStackPointer
|
||||
pspGetStackPointer:
|
||||
.frame $sp, 0, $31
|
||||
move $2,$29
|
||||
j $31
|
||||
.end pspGetStackPointer
|
||||
103
src/debug/exception.c
Normal file
103
src/debug/exception.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* pspexception.c - Basic exception handler for applications.
|
||||
*
|
||||
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
||||
*
|
||||
* $Id: exception.c 1777 2006-02-01 22:23:22Z tyranid $
|
||||
*/
|
||||
|
||||
#include <pspkernel.h>
|
||||
#include <pspdisplay.h>
|
||||
#include <pspdebug.h>
|
||||
|
||||
static PspDebugErrorHandler curr_handler = NULL;
|
||||
|
||||
void _pspDebugExceptionHandler(void);
|
||||
PspDebugRegBlock _pspDebugExceptRegs;
|
||||
|
||||
int sceKernelRegisterDefaultExceptionHandler(void *func);
|
||||
|
||||
/* Install an error handler */
|
||||
int pspDebugInstallErrorHandler(PspDebugErrorHandler handler)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
curr_handler = handler;
|
||||
|
||||
addr = (u32) _pspDebugExceptionHandler;
|
||||
addr |= 0x80000000;
|
||||
|
||||
return sceKernelRegisterDefaultExceptionHandler((void *) addr);
|
||||
}
|
||||
|
||||
/* Mnemonic register names */
|
||||
static const unsigned char regName[32][5] =
|
||||
{
|
||||
"zr", "at", "v0", "v1", "a0", "a1", "a2", "a3",
|
||||
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
|
||||
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
|
||||
"t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
|
||||
};
|
||||
|
||||
/* Taken from the ps2, might not be 100% correct */
|
||||
static const char *codeTxt[32] =
|
||||
{
|
||||
"Interrupt", "TLB modification", "TLB load/inst fetch", "TLB store",
|
||||
"Address load/inst fetch", "Address store", "Bus error (instr)",
|
||||
"Bus error (data)", "Syscall", "Breakpoint", "Reserved instruction",
|
||||
"Coprocessor unusable", "Arithmetic overflow", "Unknown 13", "Unknown 14",
|
||||
"FPU Exception", "Unknown 16", "Unknown 17", "Unknown 18",
|
||||
"Unknown 20", "Unknown 21", "Unknown 22", "Unknown 23",
|
||||
"Unknown 24", "Unknown 25", "Unknown 26", "Unknown 27",
|
||||
"Unknown 28", "Unknown 29", "Unknown 30", "Unknown 31"
|
||||
};
|
||||
|
||||
/* Dump an exception to screen */
|
||||
void pspDebugDumpException(PspDebugRegBlock *regs)
|
||||
{
|
||||
int i;
|
||||
|
||||
pspDebugScreenPrintf("Exception - %s\n", codeTxt[(regs->cause >> 2) & 31]);
|
||||
pspDebugScreenPrintf("EPC - %08X\n", regs->epc);
|
||||
pspDebugScreenPrintf("Cause - %08X\n", regs->cause);
|
||||
pspDebugScreenPrintf("Status - %08X\n", regs->status);
|
||||
pspDebugScreenPrintf("BadVAddr - %08X\n", regs->badvaddr);
|
||||
for(i = 0; i < 32; i+=4)
|
||||
{
|
||||
pspDebugScreenPrintf("%s:%08X %s:%08X %s:%08X %s:%08X\n", regName[i], regs->r[i],
|
||||
regName[i+1], regs->r[i+1], regName[i+2], regs->r[i+2], regName[i+3], regs->r[i+3]);
|
||||
}
|
||||
|
||||
sceDisplayWaitVblankStart();
|
||||
}
|
||||
|
||||
/* Our default handler in case nothing else is installed */
|
||||
static void _pspDebugDefaultHandler(PspDebugRegBlock *regs)
|
||||
{
|
||||
pspDebugScreenInit();
|
||||
pspDebugDumpException(regs);
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry point for our exception "trap"
|
||||
*/
|
||||
void _pspDebugTrapEntry(void)
|
||||
{
|
||||
/* No special stack is used here, if the thread's stack is trashed we might be in trouble */
|
||||
if(curr_handler != NULL)
|
||||
{
|
||||
curr_handler(&_pspDebugExceptRegs);
|
||||
}
|
||||
else
|
||||
{
|
||||
_pspDebugDefaultHandler(&_pspDebugExceptRegs);
|
||||
}
|
||||
|
||||
/* Kill this thread as we cannot necessarily continue */
|
||||
/* Technically you might be able to "restart" after something like a break */
|
||||
sceKernelExitDeleteThread(0);
|
||||
}
|
||||
334
src/debug/exception_asm.S
Normal file
334
src/debug/exception_asm.S
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* pspexception_asm.S - Basic exception handler for applications.
|
||||
*
|
||||
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "as_reg_compat.h"
|
||||
|
||||
.set noreorder
|
||||
.set noat
|
||||
|
||||
#define BadVAddr $8 // Address for the most recent address-related exception
|
||||
#define Status $12 // Processor status and control
|
||||
#define Cause $13 // Cause of last general exception
|
||||
#define EPC $14 // Program counter at last exception
|
||||
#define PRId $15 // Processor identification and revision
|
||||
|
||||
#define FSR $31
|
||||
#define FIR $0
|
||||
|
||||
#define REG_GPR_0 (6*4)
|
||||
#define REG_GPR_1 (REG_GPR_0 + 4)
|
||||
#define REG_GPR_2 (REG_GPR_1 + 4)
|
||||
#define REG_GPR_3 (REG_GPR_2 + 4)
|
||||
#define REG_GPR_4 (REG_GPR_3 + 4)
|
||||
#define REG_GPR_5 (REG_GPR_4 + 4)
|
||||
#define REG_GPR_6 (REG_GPR_5 + 4)
|
||||
#define REG_GPR_7 (REG_GPR_6 + 4)
|
||||
#define REG_GPR_8 (REG_GPR_7 + 4)
|
||||
#define REG_GPR_9 (REG_GPR_8 + 4)
|
||||
#define REG_GPR_10 (REG_GPR_9 + 4)
|
||||
#define REG_GPR_11 (REG_GPR_10 + 4)
|
||||
#define REG_GPR_12 (REG_GPR_11 + 4)
|
||||
#define REG_GPR_13 (REG_GPR_12 + 4)
|
||||
#define REG_GPR_14 (REG_GPR_13 + 4)
|
||||
#define REG_GPR_15 (REG_GPR_14 + 4)
|
||||
#define REG_GPR_16 (REG_GPR_15 + 4)
|
||||
#define REG_GPR_17 (REG_GPR_16 + 4)
|
||||
#define REG_GPR_18 (REG_GPR_17 + 4)
|
||||
#define REG_GPR_19 (REG_GPR_18 + 4)
|
||||
#define REG_GPR_20 (REG_GPR_19 + 4)
|
||||
#define REG_GPR_21 (REG_GPR_20 + 4)
|
||||
#define REG_GPR_22 (REG_GPR_21 + 4)
|
||||
#define REG_GPR_23 (REG_GPR_22 + 4)
|
||||
#define REG_GPR_24 (REG_GPR_23 + 4)
|
||||
#define REG_GPR_25 (REG_GPR_24 + 4)
|
||||
#define REG_GPR_26 (REG_GPR_25 + 4)
|
||||
#define REG_GPR_27 (REG_GPR_26 + 4)
|
||||
#define REG_GPR_28 (REG_GPR_27 + 4)
|
||||
#define REG_GPR_29 (REG_GPR_28 + 4)
|
||||
#define REG_GPR_30 (REG_GPR_29 + 4)
|
||||
#define REG_GPR_31 (REG_GPR_30 + 4)
|
||||
|
||||
#define REG_STATUS (REG_GPR_31 + 4)
|
||||
#define REG_LO (REG_STATUS + 4)
|
||||
#define REG_HI (REG_LO + 4)
|
||||
#define REG_BADVADDR (REG_HI + 4)
|
||||
#define REG_CAUSE (REG_BADVADDR + 4)
|
||||
#define REG_EPC (REG_CAUSE + 4)
|
||||
|
||||
#define REG_FPR_0 (REG_EPC + 4)
|
||||
#define REG_FPR_1 (REG_FPR_0 + 4)
|
||||
#define REG_FPR_2 (REG_FPR_1 + 4)
|
||||
#define REG_FPR_3 (REG_FPR_2 + 4)
|
||||
#define REG_FPR_4 (REG_FPR_3 + 4)
|
||||
#define REG_FPR_5 (REG_FPR_4 + 4)
|
||||
#define REG_FPR_6 (REG_FPR_5 + 4)
|
||||
#define REG_FPR_7 (REG_FPR_6 + 4)
|
||||
#define REG_FPR_8 (REG_FPR_7 + 4)
|
||||
#define REG_FPR_9 (REG_FPR_8 + 4)
|
||||
#define REG_FPR_10 (REG_FPR_9 + 4)
|
||||
#define REG_FPR_11 (REG_FPR_10 + 4)
|
||||
#define REG_FPR_12 (REG_FPR_11 + 4)
|
||||
#define REG_FPR_13 (REG_FPR_12 + 4)
|
||||
#define REG_FPR_14 (REG_FPR_13 + 4)
|
||||
#define REG_FPR_15 (REG_FPR_14 + 4)
|
||||
#define REG_FPR_16 (REG_FPR_15 + 4)
|
||||
#define REG_FPR_17 (REG_FPR_16 + 4)
|
||||
#define REG_FPR_18 (REG_FPR_17 + 4)
|
||||
#define REG_FPR_19 (REG_FPR_18 + 4)
|
||||
#define REG_FPR_20 (REG_FPR_19 + 4)
|
||||
#define REG_FPR_21 (REG_FPR_20 + 4)
|
||||
#define REG_FPR_22 (REG_FPR_21 + 4)
|
||||
#define REG_FPR_23 (REG_FPR_22 + 4)
|
||||
#define REG_FPR_24 (REG_FPR_23 + 4)
|
||||
#define REG_FPR_25 (REG_FPR_24 + 4)
|
||||
#define REG_FPR_26 (REG_FPR_25 + 4)
|
||||
#define REG_FPR_27 (REG_FPR_26 + 4)
|
||||
#define REG_FPR_28 (REG_FPR_27 + 4)
|
||||
#define REG_FPR_29 (REG_FPR_28 + 4)
|
||||
#define REG_FPR_30 (REG_FPR_29 + 4)
|
||||
#define REG_FPR_31 (REG_FPR_30 + 4)
|
||||
|
||||
#define REG_FSR (REG_FPR_31 + 4)
|
||||
#define REG_FIR (REG_FSR + 4)
|
||||
#define REG_FP (REG_FIR + 4)
|
||||
|
||||
.extern _pspDebugExceptRegs
|
||||
.extern _pspDebugTrapEntry
|
||||
|
||||
.global pspDebugResumeFromException
|
||||
.ent pspDebugResumeFromException
|
||||
pspDebugResumeFromException:
|
||||
|
||||
break
|
||||
|
||||
.end pspDebugResumeFromException
|
||||
|
||||
.global _pspDebugExceptionHandler
|
||||
.ent _pspDebugExceptionHandler
|
||||
_pspDebugExceptionHandler:
|
||||
nop
|
||||
nop
|
||||
la $v1, pspDebugResumeFromException
|
||||
mfc0 $v0, EPC
|
||||
beq $v0, $v1, _pspDebugExceptionResume
|
||||
nop
|
||||
|
||||
la $v0, _pspDebugExceptRegs
|
||||
sw $0, REG_GPR_0($v0)
|
||||
sw $1, REG_GPR_1($v0)
|
||||
|
||||
cfc0 $1, $4 # Get original v0
|
||||
sw $1, REG_GPR_2($v0)
|
||||
cfc0 $1, $5 # Get original v1
|
||||
sw $1, REG_GPR_3($v0)
|
||||
sw $4, REG_GPR_4($v0)
|
||||
sw $5, REG_GPR_5($v0)
|
||||
sw $6, REG_GPR_6($v0)
|
||||
sw $7, REG_GPR_7($v0)
|
||||
sw $8, REG_GPR_8($v0)
|
||||
sw $9, REG_GPR_9($v0)
|
||||
sw $10, REG_GPR_10($v0)
|
||||
sw $11, REG_GPR_11($v0)
|
||||
sw $12, REG_GPR_12($v0)
|
||||
sw $13, REG_GPR_13($v0)
|
||||
sw $14, REG_GPR_14($v0)
|
||||
sw $15, REG_GPR_15($v0)
|
||||
sw $16, REG_GPR_16($v0)
|
||||
sw $17, REG_GPR_17($v0)
|
||||
sw $18, REG_GPR_18($v0)
|
||||
sw $19, REG_GPR_19($v0)
|
||||
sw $20, REG_GPR_20($v0)
|
||||
sw $21, REG_GPR_21($v0)
|
||||
sw $22, REG_GPR_22($v0)
|
||||
sw $23, REG_GPR_23($v0)
|
||||
sw $24, REG_GPR_24($v0)
|
||||
sw $25, REG_GPR_25($v0)
|
||||
sw $26, REG_GPR_26($v0)
|
||||
sw $27, REG_GPR_27($v0)
|
||||
sw $28, REG_GPR_28($v0)
|
||||
sw $29, REG_GPR_29($v0)
|
||||
sw $30, REG_GPR_30($v0)
|
||||
sw $31, REG_GPR_31($v0)
|
||||
|
||||
mflo $v1
|
||||
sw $v1, REG_LO($v0)
|
||||
mfhi $v1
|
||||
sw $v1, REG_HI($v0)
|
||||
mfc0 $v1, BadVAddr
|
||||
sw $v1, REG_BADVADDR($v0)
|
||||
mfc0 $v1, Cause
|
||||
sw $v1, REG_CAUSE($v0)
|
||||
mfc0 $v1, EPC
|
||||
sw $v1, REG_EPC($v0)
|
||||
mfc0 $v1, Status
|
||||
sw $v1, REG_STATUS($v0)
|
||||
|
||||
# Check if cop1 is enable and skip if not
|
||||
lui $a0, 0x2000
|
||||
and $a0, $a0, $v1
|
||||
beq $a0, $0, 1f
|
||||
nop
|
||||
|
||||
swc1 $0, REG_FPR_0($v0)
|
||||
swc1 $1, REG_FPR_1($v0)
|
||||
swc1 $2, REG_FPR_2($v0)
|
||||
swc1 $3, REG_FPR_3($v0)
|
||||
swc1 $4, REG_FPR_4($v0)
|
||||
swc1 $5, REG_FPR_5($v0)
|
||||
swc1 $6, REG_FPR_6($v0)
|
||||
swc1 $7, REG_FPR_7($v0)
|
||||
swc1 $8, REG_FPR_8($v0)
|
||||
swc1 $9, REG_FPR_9($v0)
|
||||
swc1 $10, REG_FPR_10($v0)
|
||||
swc1 $11, REG_FPR_11($v0)
|
||||
swc1 $12, REG_FPR_12($v0)
|
||||
swc1 $13, REG_FPR_13($v0)
|
||||
swc1 $14, REG_FPR_14($v0)
|
||||
swc1 $15, REG_FPR_15($v0)
|
||||
swc1 $16, REG_FPR_16($v0)
|
||||
swc1 $17, REG_FPR_17($v0)
|
||||
swc1 $18, REG_FPR_18($v0)
|
||||
swc1 $19, REG_FPR_19($v0)
|
||||
swc1 $20, REG_FPR_20($v0)
|
||||
swc1 $21, REG_FPR_21($v0)
|
||||
swc1 $22, REG_FPR_22($v0)
|
||||
swc1 $23, REG_FPR_23($v0)
|
||||
swc1 $24, REG_FPR_24($v0)
|
||||
swc1 $25, REG_FPR_25($v0)
|
||||
swc1 $26, REG_FPR_26($v0)
|
||||
swc1 $27, REG_FPR_27($v0)
|
||||
swc1 $28, REG_FPR_28($v0)
|
||||
swc1 $29, REG_FPR_29($v0)
|
||||
swc1 $30, REG_FPR_30($v0)
|
||||
swc1 $31, REG_FPR_31($v0)
|
||||
|
||||
cfc1 $t0, FSR
|
||||
sw $t0, REG_FSR($v0)
|
||||
cfc1 $t0, FIR
|
||||
sw $t0, REG_FIR($v0)
|
||||
ctc1 $0, FSR # Clear any cause flags
|
||||
|
||||
# Jump target for ignore cop1
|
||||
1:
|
||||
|
||||
sw $sp, REG_FP($v0)
|
||||
|
||||
la $2, _pspDebugTrapEntry
|
||||
mtc0 $2, $14
|
||||
nop
|
||||
nop
|
||||
eret
|
||||
nop
|
||||
nop
|
||||
|
||||
.end _pspDebugExceptionHandler
|
||||
|
||||
.ent _pspDebugExceptionResume
|
||||
|
||||
_pspDebugExceptionResume:
|
||||
|
||||
# Resume from the exception in user mode (possibly, could be kernel but we don't really know that)
|
||||
|
||||
la $v0, _pspDebugExceptRegs
|
||||
|
||||
lw $v1, REG_STATUS($v0)
|
||||
|
||||
# Check if cop1 is enable and skip if not
|
||||
lui $a0, 0x2000
|
||||
and $a0, $a0, $v1
|
||||
beq $a0, $0, 1f
|
||||
nop
|
||||
|
||||
lwc1 $0, REG_FPR_0($v0)
|
||||
lwc1 $1, REG_FPR_1($v0)
|
||||
lwc1 $2, REG_FPR_2($v0)
|
||||
lwc1 $3, REG_FPR_3($v0)
|
||||
lwc1 $4, REG_FPR_4($v0)
|
||||
lwc1 $5, REG_FPR_5($v0)
|
||||
lwc1 $6, REG_FPR_6($v0)
|
||||
lwc1 $7, REG_FPR_7($v0)
|
||||
lwc1 $8, REG_FPR_8($v0)
|
||||
lwc1 $9, REG_FPR_9($v0)
|
||||
lwc1 $10, REG_FPR_10($v0)
|
||||
lwc1 $11, REG_FPR_11($v0)
|
||||
lwc1 $12, REG_FPR_12($v0)
|
||||
lwc1 $13, REG_FPR_13($v0)
|
||||
lwc1 $14, REG_FPR_14($v0)
|
||||
lwc1 $15, REG_FPR_15($v0)
|
||||
lwc1 $16, REG_FPR_16($v0)
|
||||
lwc1 $17, REG_FPR_17($v0)
|
||||
lwc1 $18, REG_FPR_18($v0)
|
||||
lwc1 $19, REG_FPR_19($v0)
|
||||
lwc1 $20, REG_FPR_20($v0)
|
||||
lwc1 $21, REG_FPR_21($v0)
|
||||
lwc1 $22, REG_FPR_22($v0)
|
||||
lwc1 $23, REG_FPR_23($v0)
|
||||
lwc1 $24, REG_FPR_24($v0)
|
||||
lwc1 $25, REG_FPR_25($v0)
|
||||
lwc1 $26, REG_FPR_26($v0)
|
||||
lwc1 $27, REG_FPR_27($v0)
|
||||
lwc1 $28, REG_FPR_28($v0)
|
||||
lwc1 $29, REG_FPR_29($v0)
|
||||
lwc1 $30, REG_FPR_30($v0)
|
||||
lwc1 $31, REG_FPR_31($v0)
|
||||
|
||||
lw $t0, REG_FSR($v0)
|
||||
li $t1, 0xFFFC0F83
|
||||
and $t0, $t0, $t1 # Clear the cause and flags before ret
|
||||
ctc1 $t0, FSR
|
||||
1:
|
||||
|
||||
# lw $0, REG_GPR_0($v0)
|
||||
# lw $1, REG_GPR_1($v0)
|
||||
# Don't do 2 yet
|
||||
lw $3, REG_GPR_3($v0)
|
||||
lw $4, REG_GPR_4($v0)
|
||||
lw $5, REG_GPR_5($v0)
|
||||
lw $6, REG_GPR_6($v0)
|
||||
lw $7, REG_GPR_7($v0)
|
||||
lw $8, REG_GPR_8($v0)
|
||||
lw $9, REG_GPR_9($v0)
|
||||
lw $10, REG_GPR_10($v0)
|
||||
lw $11, REG_GPR_11($v0)
|
||||
lw $12, REG_GPR_12($v0)
|
||||
lw $13, REG_GPR_13($v0)
|
||||
lw $14, REG_GPR_14($v0)
|
||||
lw $15, REG_GPR_15($v0)
|
||||
lw $16, REG_GPR_16($v0)
|
||||
lw $17, REG_GPR_17($v0)
|
||||
lw $18, REG_GPR_18($v0)
|
||||
lw $19, REG_GPR_19($v0)
|
||||
lw $20, REG_GPR_20($v0)
|
||||
lw $21, REG_GPR_21($v0)
|
||||
lw $22, REG_GPR_22($v0)
|
||||
lw $23, REG_GPR_23($v0)
|
||||
lw $24, REG_GPR_24($v0)
|
||||
lw $25, REG_GPR_25($v0)
|
||||
lw $26, REG_GPR_26($v0)
|
||||
lw $27, REG_GPR_27($v0)
|
||||
lw $28, REG_GPR_28($v0)
|
||||
lw $29, REG_GPR_29($v0)
|
||||
lw $30, REG_GPR_30($v0)
|
||||
lw $31, REG_GPR_31($v0)
|
||||
|
||||
lw $1, REG_EPC($v0)
|
||||
mtc0 $1, EPC
|
||||
|
||||
# Restore 1 + 2 now
|
||||
lw $1, REG_GPR_1($v0)
|
||||
lw $2, REG_GPR_2($v0)
|
||||
|
||||
nop
|
||||
nop
|
||||
eret
|
||||
|
||||
.end _pspDebugExceptionResume
|
||||
147
src/debug/font.c
Normal file
147
src/debug/font.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* font.c - Debug Font.
|
||||
*
|
||||
* Copyright (c) 2005 Marcus R. Brown <mrbrown@ocgnet.org>
|
||||
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
||||
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
|
||||
*
|
||||
* $Id: font.c 540 2005-07-08 19:35:10Z warren $
|
||||
*/
|
||||
#include <psptypes.h>
|
||||
|
||||
u8 msx[]=
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x3c\x42\xa5\x81\xa5\x99\x42\x3c"
|
||||
"\x3c\x7e\xdb\xff\xff\xdb\x66\x3c\x6c\xfe\xfe\xfe\x7c\x38\x10\x00"
|
||||
"\x10\x38\x7c\xfe\x7c\x38\x10\x00\x10\x38\x54\xfe\x54\x10\x38\x00"
|
||||
"\x10\x38\x7c\xfe\xfe\x10\x38\x00\x00\x00\x00\x30\x30\x00\x00\x00"
|
||||
"\xff\xff\xff\xe7\xe7\xff\xff\xff\x38\x44\x82\x82\x82\x44\x38\x00"
|
||||
"\xc7\xbb\x7d\x7d\x7d\xbb\xc7\xff\x0f\x03\x05\x79\x88\x88\x88\x70"
|
||||
"\x38\x44\x44\x44\x38\x10\x7c\x10\x30\x28\x24\x24\x28\x20\xe0\xc0"
|
||||
"\x3c\x24\x3c\x24\x24\xe4\xdc\x18\x10\x54\x38\xee\x38\x54\x10\x00"
|
||||
"\x10\x10\x10\x7c\x10\x10\x10\x10\x10\x10\x10\xff\x00\x00\x00\x00"
|
||||
"\x00\x00\x00\xff\x10\x10\x10\x10\x10\x10\x10\xf0\x10\x10\x10\x10"
|
||||
"\x10\x10\x10\x1f\x10\x10\x10\x10\x10\x10\x10\xff\x10\x10\x10\x10"
|
||||
"\x10\x10\x10\x10\x10\x10\x10\x10\x00\x00\x00\xff\x00\x00\x00\x00"
|
||||
"\x00\x00\x00\x1f\x10\x10\x10\x10\x00\x00\x00\xf0\x10\x10\x10\x10"
|
||||
"\x10\x10\x10\x1f\x00\x00\x00\x00\x10\x10\x10\xf0\x00\x00\x00\x00"
|
||||
"\x81\x42\x24\x18\x18\x24\x42\x81\x01\x02\x04\x08\x10\x20\x40\x80"
|
||||
"\x80\x40\x20\x10\x08\x04\x02\x01\x00\x10\x10\xff\x10\x10\x00\x00"
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x20\x20\x20\x20\x00\x00\x20\x00"
|
||||
"\x50\x50\x50\x00\x00\x00\x00\x00\x50\x50\xf8\x50\xf8\x50\x50\x00"
|
||||
"\x20\x78\xa0\x70\x28\xf0\x20\x00\xc0\xc8\x10\x20\x40\x98\x18\x00"
|
||||
"\x40\xa0\x40\xa8\x90\x98\x60\x00\x10\x20\x40\x00\x00\x00\x00\x00"
|
||||
"\x10\x20\x40\x40\x40\x20\x10\x00\x40\x20\x10\x10\x10\x20\x40\x00"
|
||||
"\x20\xa8\x70\x20\x70\xa8\x20\x00\x00\x20\x20\xf8\x20\x20\x00\x00"
|
||||
"\x00\x00\x00\x00\x00\x20\x20\x40\x00\x00\x00\x78\x00\x00\x00\x00"
|
||||
"\x00\x00\x00\x00\x00\x60\x60\x00\x00\x00\x08\x10\x20\x40\x80\x00"
|
||||
"\x70\x88\x98\xa8\xc8\x88\x70\x00\x20\x60\xa0\x20\x20\x20\xf8\x00"
|
||||
"\x70\x88\x08\x10\x60\x80\xf8\x00\x70\x88\x08\x30\x08\x88\x70\x00"
|
||||
"\x10\x30\x50\x90\xf8\x10\x10\x00\xf8\x80\xe0\x10\x08\x10\xe0\x00"
|
||||
"\x30\x40\x80\xf0\x88\x88\x70\x00\xf8\x88\x10\x20\x20\x20\x20\x00"
|
||||
"\x70\x88\x88\x70\x88\x88\x70\x00\x70\x88\x88\x78\x08\x10\x60\x00"
|
||||
"\x00\x00\x20\x00\x00\x20\x00\x00\x00\x00\x20\x00\x00\x20\x20\x40"
|
||||
"\x18\x30\x60\xc0\x60\x30\x18\x00\x00\x00\xf8\x00\xf8\x00\x00\x00"
|
||||
"\xc0\x60\x30\x18\x30\x60\xc0\x00\x70\x88\x08\x10\x20\x00\x20\x00"
|
||||
"\x70\x88\x08\x68\xa8\xa8\x70\x00\x20\x50\x88\x88\xf8\x88\x88\x00"
|
||||
"\xf0\x48\x48\x70\x48\x48\xf0\x00\x30\x48\x80\x80\x80\x48\x30\x00"
|
||||
"\xe0\x50\x48\x48\x48\x50\xe0\x00\xf8\x80\x80\xf0\x80\x80\xf8\x00"
|
||||
"\xf8\x80\x80\xf0\x80\x80\x80\x00\x70\x88\x80\xb8\x88\x88\x70\x00"
|
||||
"\x88\x88\x88\xf8\x88\x88\x88\x00\x70\x20\x20\x20\x20\x20\x70\x00"
|
||||
"\x38\x10\x10\x10\x90\x90\x60\x00\x88\x90\xa0\xc0\xa0\x90\x88\x00"
|
||||
"\x80\x80\x80\x80\x80\x80\xf8\x00\x88\xd8\xa8\xa8\x88\x88\x88\x00"
|
||||
"\x88\xc8\xc8\xa8\x98\x98\x88\x00\x70\x88\x88\x88\x88\x88\x70\x00"
|
||||
"\xf0\x88\x88\xf0\x80\x80\x80\x00\x70\x88\x88\x88\xa8\x90\x68\x00"
|
||||
"\xf0\x88\x88\xf0\xa0\x90\x88\x00\x70\x88\x80\x70\x08\x88\x70\x00"
|
||||
"\xf8\x20\x20\x20\x20\x20\x20\x00\x88\x88\x88\x88\x88\x88\x70\x00"
|
||||
"\x88\x88\x88\x88\x50\x50\x20\x00\x88\x88\x88\xa8\xa8\xd8\x88\x00"
|
||||
"\x88\x88\x50\x20\x50\x88\x88\x00\x88\x88\x88\x70\x20\x20\x20\x00"
|
||||
"\xf8\x08\x10\x20\x40\x80\xf8\x00\x70\x40\x40\x40\x40\x40\x70\x00"
|
||||
"\x00\x00\x80\x40\x20\x10\x08\x00\x70\x10\x10\x10\x10\x10\x70\x00"
|
||||
"\x20\x50\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8\x00"
|
||||
"\x40\x20\x10\x00\x00\x00\x00\x00\x00\x00\x70\x08\x78\x88\x78\x00"
|
||||
"\x80\x80\xb0\xc8\x88\xc8\xb0\x00\x00\x00\x70\x88\x80\x88\x70\x00"
|
||||
"\x08\x08\x68\x98\x88\x98\x68\x00\x00\x00\x70\x88\xf8\x80\x70\x00"
|
||||
"\x10\x28\x20\xf8\x20\x20\x20\x00\x00\x00\x68\x98\x98\x68\x08\x70"
|
||||
"\x80\x80\xf0\x88\x88\x88\x88\x00\x20\x00\x60\x20\x20\x20\x70\x00"
|
||||
"\x10\x00\x30\x10\x10\x10\x90\x60\x40\x40\x48\x50\x60\x50\x48\x00"
|
||||
"\x60\x20\x20\x20\x20\x20\x70\x00\x00\x00\xd0\xa8\xa8\xa8\xa8\x00"
|
||||
"\x00\x00\xb0\xc8\x88\x88\x88\x00\x00\x00\x70\x88\x88\x88\x70\x00"
|
||||
"\x00\x00\xb0\xc8\xc8\xb0\x80\x80\x00\x00\x68\x98\x98\x68\x08\x08"
|
||||
"\x00\x00\xb0\xc8\x80\x80\x80\x00\x00\x00\x78\x80\xf0\x08\xf0\x00"
|
||||
"\x40\x40\xf0\x40\x40\x48\x30\x00\x00\x00\x90\x90\x90\x90\x68\x00"
|
||||
"\x00\x00\x88\x88\x88\x50\x20\x00\x00\x00\x88\xa8\xa8\xa8\x50\x00"
|
||||
"\x00\x00\x88\x50\x20\x50\x88\x00\x00\x00\x88\x88\x98\x68\x08\x70"
|
||||
"\x00\x00\xf8\x10\x20\x40\xf8\x00\x18\x20\x20\x40\x20\x20\x18\x00"
|
||||
"\x20\x20\x20\x00\x20\x20\x20\x00\xc0\x20\x20\x10\x20\x20\xc0\x00"
|
||||
"\x40\xa8\x10\x00\x00\x00\x00\x00\x00\x00\x20\x50\xf8\x00\x00\x00"
|
||||
"\x70\x88\x80\x80\x88\x70\x20\x60\x90\x00\x00\x90\x90\x90\x68\x00"
|
||||
"\x10\x20\x70\x88\xf8\x80\x70\x00\x20\x50\x70\x08\x78\x88\x78\x00"
|
||||
"\x48\x00\x70\x08\x78\x88\x78\x00\x20\x10\x70\x08\x78\x88\x78\x00"
|
||||
"\x20\x00\x70\x08\x78\x88\x78\x00\x00\x70\x80\x80\x80\x70\x10\x60"
|
||||
"\x20\x50\x70\x88\xf8\x80\x70\x00\x50\x00\x70\x88\xf8\x80\x70\x00"
|
||||
"\x20\x10\x70\x88\xf8\x80\x70\x00\x50\x00\x00\x60\x20\x20\x70\x00"
|
||||
"\x20\x50\x00\x60\x20\x20\x70\x00\x40\x20\x00\x60\x20\x20\x70\x00"
|
||||
"\x50\x00\x20\x50\x88\xf8\x88\x00\x20\x00\x20\x50\x88\xf8\x88\x00"
|
||||
"\x10\x20\xf8\x80\xf0\x80\xf8\x00\x00\x00\x6c\x12\x7e\x90\x6e\x00"
|
||||
"\x3e\x50\x90\x9c\xf0\x90\x9e\x00\x60\x90\x00\x60\x90\x90\x60\x00"
|
||||
"\x90\x00\x00\x60\x90\x90\x60\x00\x40\x20\x00\x60\x90\x90\x60\x00"
|
||||
"\x40\xa0\x00\xa0\xa0\xa0\x50\x00\x40\x20\x00\xa0\xa0\xa0\x50\x00"
|
||||
"\x90\x00\x90\x90\xb0\x50\x10\xe0\x50\x00\x70\x88\x88\x88\x70\x00"
|
||||
"\x50\x00\x88\x88\x88\x88\x70\x00\x20\x20\x78\x80\x80\x78\x20\x20"
|
||||
"\x18\x24\x20\xf8\x20\xe2\x5c\x00\x88\x50\x20\xf8\x20\xf8\x20\x00"
|
||||
"\xc0\xa0\xa0\xc8\x9c\x88\x88\x8c\x18\x20\x20\xf8\x20\x20\x20\x40"
|
||||
"\x10\x20\x70\x08\x78\x88\x78\x00\x10\x20\x00\x60\x20\x20\x70\x00"
|
||||
"\x20\x40\x00\x60\x90\x90\x60\x00\x20\x40\x00\x90\x90\x90\x68\x00"
|
||||
"\x50\xa0\x00\xa0\xd0\x90\x90\x00\x28\x50\x00\xc8\xa8\x98\x88\x00"
|
||||
"\x00\x70\x08\x78\x88\x78\x00\xf8\x00\x60\x90\x90\x90\x60\x00\xf0"
|
||||
"\x20\x00\x20\x40\x80\x88\x70\x00\x00\x00\x00\xf8\x80\x80\x00\x00"
|
||||
"\x00\x00\x00\xf8\x08\x08\x00\x00\x84\x88\x90\xa8\x54\x84\x08\x1c"
|
||||
"\x84\x88\x90\xa8\x58\xa8\x3c\x08\x20\x00\x00\x20\x20\x20\x20\x00"
|
||||
"\x00\x00\x24\x48\x90\x48\x24\x00\x00\x00\x90\x48\x24\x48\x90\x00"
|
||||
"\x28\x50\x20\x50\x88\xf8\x88\x00\x28\x50\x70\x08\x78\x88\x78\x00"
|
||||
"\x28\x50\x00\x70\x20\x20\x70\x00\x28\x50\x00\x20\x20\x20\x70\x00"
|
||||
"\x28\x50\x00\x70\x88\x88\x70\x00\x50\xa0\x00\x60\x90\x90\x60\x00"
|
||||
"\x28\x50\x00\x88\x88\x88\x70\x00\x50\xa0\x00\xa0\xa0\xa0\x50\x00"
|
||||
"\xfc\x48\x48\x48\xe8\x08\x50\x20\x00\x50\x00\x50\x50\x50\x10\x20"
|
||||
"\xc0\x44\xc8\x54\xec\x54\x9e\x04\x10\xa8\x40\x00\x00\x00\x00\x00"
|
||||
"\x00\x20\x50\x88\x50\x20\x00\x00\x88\x10\x20\x40\x80\x28\x00\x00"
|
||||
"\x7c\xa8\xa8\x68\x28\x28\x28\x00\x38\x40\x30\x48\x48\x30\x08\x70"
|
||||
"\x00\x00\x00\x00\x00\x00\xff\xff\xf0\xf0\xf0\xf0\x0f\x0f\x0f\x0f"
|
||||
"\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00"
|
||||
"\x00\x00\x00\x3c\x3c\x00\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00"
|
||||
"\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x0f\x0f\x0f\x0f\xf0\xf0\xf0\xf0"
|
||||
"\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\x03\x03\x03\x03\x03\x03\x03\x03"
|
||||
"\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x11\x22\x44\x88\x11\x22\x44\x88"
|
||||
"\x88\x44\x22\x11\x88\x44\x22\x11\xfe\x7c\x38\x10\x00\x00\x00\x00"
|
||||
"\x00\x00\x00\x00\x10\x38\x7c\xfe\x80\xc0\xe0\xf0\xe0\xc0\x80\x00"
|
||||
"\x01\x03\x07\x0f\x07\x03\x01\x00\xff\x7e\x3c\x18\x18\x3c\x7e\xff"
|
||||
"\x81\xc3\xe7\xff\xff\xe7\xc3\x81\xf0\xf0\xf0\xf0\x00\x00\x00\x00"
|
||||
"\x00\x00\x00\x00\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x00\x00\x00\x00"
|
||||
"\x00\x00\x00\x00\xf0\xf0\xf0\xf0\x33\x33\xcc\xcc\x33\x33\xcc\xcc"
|
||||
"\x00\x20\x20\x50\x50\x88\xf8\x00\x20\x20\x70\x20\x70\x20\x20\x00"
|
||||
"\x00\x00\x00\x50\x88\xa8\x50\x00\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
"\x00\x00\x00\x00\xff\xff\xff\xff\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0"
|
||||
"\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\xff\xff\xff\xff\x00\x00\x00\x00"
|
||||
"\x00\x00\x68\x90\x90\x90\x68\x00\x30\x48\x48\x70\x48\x48\x70\xc0"
|
||||
"\xf8\x88\x80\x80\x80\x80\x80\x00\xf8\x50\x50\x50\x50\x50\x98\x00"
|
||||
"\xf8\x88\x40\x20\x40\x88\xf8\x00\x00\x00\x78\x90\x90\x90\x60\x00"
|
||||
"\x00\x50\x50\x50\x50\x68\x80\x80\x00\x50\xa0\x20\x20\x20\x20\x00"
|
||||
"\xf8\x20\x70\xa8\xa8\x70\x20\xf8\x20\x50\x88\xf8\x88\x50\x20\x00"
|
||||
"\x70\x88\x88\x88\x50\x50\xd8\x00\x30\x40\x40\x20\x50\x50\x50\x20"
|
||||
"\x00\x00\x00\x50\xa8\xa8\x50\x00\x08\x70\xa8\xa8\xa8\x70\x80\x00"
|
||||
"\x38\x40\x80\xf8\x80\x40\x38\x00\x70\x88\x88\x88\x88\x88\x88\x00"
|
||||
"\x00\xf8\x00\xf8\x00\xf8\x00\x00\x20\x20\xf8\x20\x20\x00\xf8\x00"
|
||||
"\xc0\x30\x08\x30\xc0\x00\xf8\x00\x18\x60\x80\x60\x18\x00\xf8\x00"
|
||||
"\x10\x28\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\xa0\x40"
|
||||
"\x00\x20\x00\xf8\x00\x20\x00\x00\x00\x50\xa0\x00\x50\xa0\x00\x00"
|
||||
"\x00\x18\x24\x24\x18\x00\x00\x00\x00\x30\x78\x78\x30\x00\x00\x00"
|
||||
"\x00\x00\x00\x00\x30\x00\x00\x00\x3e\x20\x20\x20\xa0\x60\x20\x00"
|
||||
"\xa0\x50\x50\x50\x00\x00\x00\x00\x40\xa0\x20\x40\xe0\x00\x00\x00"
|
||||
"\x00\x38\x38\x38\x38\x38\x38\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||
|
||||
|
||||
|
||||
91
src/debug/gdb-kernellib.c
Normal file
91
src/debug/gdb-kernellib.c
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* gdb-kernellib.c - GDB support functions for kernel mode.
|
||||
*
|
||||
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
||||
*
|
||||
* $Id: gdb-kernellib.c 1492 2005-11-26 23:19:30Z mrbrown $
|
||||
*/
|
||||
#include <pspkernel.h>
|
||||
#include <pspdebug.h>
|
||||
|
||||
/* GDB Debug putchar */
|
||||
void putDebugChar(char ch)
|
||||
{
|
||||
pspDebugSioPutchar(ch);
|
||||
}
|
||||
|
||||
/* GDB Debug getchar */
|
||||
char getDebugChar(void)
|
||||
{
|
||||
int ch = 0;
|
||||
|
||||
while(1)
|
||||
{
|
||||
ch = pspDebugSioGetchar();
|
||||
if(ch != -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
void sceKernelDcacheWBinvAll(void);
|
||||
void sceKernelIcacheClearAll(void);
|
||||
|
||||
void _gdbSupportLibFlushCaches(void)
|
||||
{
|
||||
pspKernelSetKernelPC();
|
||||
sceKernelDcacheWBinvAll();
|
||||
sceKernelIcacheClearAll();
|
||||
}
|
||||
|
||||
int _gdbSupportLibReadByte(unsigned char *address, unsigned char *dest)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
addr = (u32) address;
|
||||
if((addr >= 0x08400000) && (addr < 0x0a000000))
|
||||
{
|
||||
*dest = *address;
|
||||
return 1;
|
||||
}
|
||||
else if((addr >= 0x88000000) && (addr < 0x8a000000))
|
||||
{
|
||||
*dest = *address;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _gdbSupportLibWriteByte(char val, unsigned char *dest)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
addr = (u32) dest;
|
||||
if((addr >= 0x08400000) && (addr < 0x0a000000))
|
||||
{
|
||||
*dest = val;
|
||||
return 1;
|
||||
}
|
||||
else if((addr >= 0x88000000) && (addr < 0x8a000000))
|
||||
{
|
||||
*dest = val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _gdbSupportLibInit(void)
|
||||
{
|
||||
/* Do nothing */
|
||||
|
||||
return 0;
|
||||
}
|
||||
822
src/debug/gdb-stub.c
Normal file
822
src/debug/gdb-stub.c
Normal file
@@ -0,0 +1,822 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* gdb-stub.c - Simple remote GDB stub for the psp.
|
||||
*
|
||||
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
||||
*
|
||||
* $Id: gdb-stub.c 1152 2005-10-16 20:37:00Z tyranid $
|
||||
*/
|
||||
|
||||
/* Note: there is the odd small bit which comes from the gdb stubs/linux mips stub */
|
||||
/* As far as I am aware they didn't have an explicit license on them so... */
|
||||
|
||||
#include <pspkernel.h>
|
||||
#include <pspdebug.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_PRINTF(fmt, ...) pspDebugScreenPrintf(fmt, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_PRINTF(fmt, ...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* breakpoint and test functions
|
||||
*/
|
||||
void pspDebugBreakpoint(void);
|
||||
void putDebugChar(char ch);
|
||||
char getDebugChar(void);
|
||||
int _gdbSupportLibWriteByte(char val, unsigned char *dest);
|
||||
int _gdbSupportLibReadByte(unsigned char *address, unsigned char *dest);
|
||||
//void _pspDebugExceptionResume(void);
|
||||
void pspDebugResumeFromException(void);
|
||||
void _gdbSupportLibFlushCaches(void);
|
||||
extern u32 _pspDebugResumePatch;
|
||||
|
||||
extern int sceKernelSuspendIntr(void);
|
||||
extern void sceKernelResumeIntr(int intr);
|
||||
|
||||
static void handle_exception(PspDebugRegBlock *regs);
|
||||
|
||||
#define MAX_BUF 2048
|
||||
|
||||
void _GdbExceptionHandler(void);
|
||||
static PspDebugRegBlock *_GdbExceptRegs;
|
||||
static int initialised = 0;
|
||||
static char input[MAX_BUF];
|
||||
static char output[MAX_BUF];
|
||||
static const char hexchars[]="0123456789abcdef";
|
||||
static char last_cmd = 0;
|
||||
static int attached = 0;
|
||||
|
||||
/* Define a software breakpoint structure */
|
||||
struct sw_breakpoint
|
||||
{
|
||||
unsigned int addr;
|
||||
unsigned int oldinst;
|
||||
unsigned int active;
|
||||
};
|
||||
|
||||
static struct sw_breakpoint g_stepbp[2];
|
||||
|
||||
/*
|
||||
* send the packet in buffer.
|
||||
*/
|
||||
static void putpacket(unsigned char *buffer)
|
||||
{
|
||||
unsigned char checksum;
|
||||
int count;
|
||||
unsigned char ch;
|
||||
|
||||
/*
|
||||
* $<packet info>#<checksum>.
|
||||
*/
|
||||
|
||||
do {
|
||||
putDebugChar('$');
|
||||
checksum = 0;
|
||||
count = 0;
|
||||
|
||||
while ((ch = buffer[count]) != 0) {
|
||||
checksum += ch;
|
||||
count += 1;
|
||||
putDebugChar(ch);
|
||||
}
|
||||
|
||||
putDebugChar('#');
|
||||
putDebugChar(hexchars[(checksum >> 4) & 0xf]);
|
||||
putDebugChar(hexchars[checksum & 0xf]);
|
||||
|
||||
DEBUG_PRINTF("calculated checksum = %02X\n", checksum);
|
||||
}
|
||||
while ((getDebugChar() & 0x7f) != '+');
|
||||
}
|
||||
|
||||
static char get_char(void)
|
||||
{
|
||||
int ch;
|
||||
|
||||
while((ch = pspDebugSioGetchar()) == -1);
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
/*
|
||||
* send the packet in buffer.
|
||||
*/
|
||||
static int stdout_handler(const char *data, int len)
|
||||
{
|
||||
unsigned char checksum;
|
||||
int count;
|
||||
unsigned char ch;
|
||||
|
||||
if(!attached)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* $<packet info>#<checksum>.
|
||||
*/
|
||||
|
||||
do {
|
||||
pspDebugSioPutchar('$');
|
||||
pspDebugSioPutchar('O');
|
||||
|
||||
checksum = 'O';
|
||||
count = 0;
|
||||
|
||||
while(1)
|
||||
{
|
||||
if(count == len)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ch = hexchars[(data[count] >> 4) & 0xF];
|
||||
pspDebugSioPutchar(ch);
|
||||
checksum += ch;
|
||||
ch = hexchars[data[count] & 0xF];
|
||||
pspDebugSioPutchar(ch);
|
||||
checksum += ch;
|
||||
count += 1;
|
||||
}
|
||||
|
||||
pspDebugSioPutchar('#');
|
||||
pspDebugSioPutchar(hexchars[(checksum >> 4) & 0xf]);
|
||||
pspDebugSioPutchar(hexchars[checksum & 0xf]);
|
||||
}
|
||||
while ((get_char() & 0x7f) != '+');
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert ch from a hex digit to an int
|
||||
*/
|
||||
static int hex(unsigned char ch)
|
||||
{
|
||||
if (ch >= 'a' && ch <= 'f')
|
||||
return ch-'a'+10;
|
||||
if (ch >= '0' && ch <= '9')
|
||||
return ch-'0';
|
||||
if (ch >= 'A' && ch <= 'F')
|
||||
return ch-'A'+10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* scan for the sequence $<data>#<checksum>
|
||||
*/
|
||||
static void getpacket(char *buffer)
|
||||
{
|
||||
unsigned char checksum;
|
||||
unsigned char xmitcsum;
|
||||
int i;
|
||||
int count;
|
||||
unsigned char ch;
|
||||
|
||||
do {
|
||||
/*
|
||||
* wait around for the start character,
|
||||
* ignore all other characters
|
||||
*/
|
||||
while ((ch = (getDebugChar() & 0x7f)) != '$') ;
|
||||
|
||||
checksum = 0;
|
||||
xmitcsum = -1;
|
||||
count = 0;
|
||||
|
||||
/*
|
||||
* now, read until a # or end of buffer is found
|
||||
*/
|
||||
while (count < MAX_BUF) {
|
||||
ch = getDebugChar();
|
||||
if (ch == '#')
|
||||
break;
|
||||
checksum = checksum + ch;
|
||||
buffer[count] = ch;
|
||||
count = count + 1;
|
||||
}
|
||||
|
||||
if (count >= MAX_BUF)
|
||||
continue;
|
||||
|
||||
buffer[count] = 0;
|
||||
|
||||
if (ch == '#') {
|
||||
xmitcsum = hex(getDebugChar() & 0x7f) << 4;
|
||||
xmitcsum |= hex(getDebugChar() & 0x7f);
|
||||
|
||||
if (checksum != xmitcsum)
|
||||
putDebugChar('-'); /* failed checksum */
|
||||
else {
|
||||
putDebugChar('+'); /* successful transfer */
|
||||
|
||||
/*
|
||||
* if a sequence char is present,
|
||||
* reply the sequence ID
|
||||
*/
|
||||
if (buffer[2] == ':') {
|
||||
putDebugChar(buffer[0]);
|
||||
putDebugChar(buffer[1]);
|
||||
|
||||
/*
|
||||
* remove sequence chars from buffer
|
||||
*/
|
||||
count = strlen(buffer);
|
||||
for (i=3; i <= count; i++)
|
||||
buffer[i-3] = buffer[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (checksum != xmitcsum);
|
||||
}
|
||||
|
||||
static struct hard_trap_info {
|
||||
unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */
|
||||
unsigned char signo; /* Signal that we map this trap into */
|
||||
} hard_trap_info[] = {
|
||||
{ 6, SIGBUS }, /* instruction bus error */
|
||||
{ 7, SIGBUS }, /* data bus error */
|
||||
{ 9, SIGTRAP }, /* break */
|
||||
{ 10, SIGILL }, /* reserved instruction */
|
||||
{ 12, SIGFPE }, /* overflow */
|
||||
{ 13, SIGTRAP }, /* trap */
|
||||
{ 14, SIGSEGV }, /* virtual instruction cache coherency */
|
||||
{ 15, SIGFPE }, /* floating point exception */
|
||||
{ 23, SIGSEGV }, /* watch */
|
||||
{ 31, SIGSEGV }, /* virtual data cache coherency */
|
||||
{ 0, 0} /* Must be last */
|
||||
};
|
||||
|
||||
static int computeSignal(int tt)
|
||||
{
|
||||
struct hard_trap_info *ht;
|
||||
|
||||
for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
|
||||
if (ht->tt == tt)
|
||||
return ht->signo;
|
||||
|
||||
return SIGHUP; /* default for things we don't know about */
|
||||
}
|
||||
|
||||
|
||||
static void _GdbTrapEntry(PspDebugRegBlock *regs)
|
||||
{
|
||||
/* Get the current priority and increment by one ? */
|
||||
_GdbExceptRegs = regs;
|
||||
handle_exception(regs);
|
||||
|
||||
/* Flush caches */
|
||||
_gdbSupportLibFlushCaches();
|
||||
|
||||
pspDebugResumeFromException();
|
||||
}
|
||||
|
||||
int _gdbSupportLibInit(void);
|
||||
|
||||
void pspDebugGdbStubInit(void)
|
||||
{
|
||||
_gdbSupportLibInit();
|
||||
/* Read out any pending data */
|
||||
memset(g_stepbp, 0, 2 * sizeof(struct sw_breakpoint));
|
||||
pspDebugInstallStdoutHandler(stdout_handler);
|
||||
pspDebugInstallStderrHandler(stdout_handler);
|
||||
|
||||
pspDebugInstallErrorHandler(_GdbTrapEntry);
|
||||
|
||||
initialised = 1;
|
||||
attached = 1;
|
||||
}
|
||||
|
||||
static char *mem2hex(unsigned char *mem, char *buf, int count)
|
||||
{
|
||||
unsigned char ch;
|
||||
|
||||
while (count-- > 0) {
|
||||
if (_gdbSupportLibReadByte(mem++, &ch) == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*buf++ = hexchars[(ch >> 4) & 0xf];
|
||||
*buf++ = hexchars[ch & 0xf];
|
||||
}
|
||||
|
||||
*buf = 0;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char *hex2mem(char *buf, char *mem, int count, int binary)
|
||||
{
|
||||
int i;
|
||||
unsigned char ch;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
if (binary) {
|
||||
ch = *buf++;
|
||||
if (ch == 0x7d)
|
||||
ch = 0x20 ^ *buf++;
|
||||
}
|
||||
else {
|
||||
ch = hex(*buf++) << 4;
|
||||
ch |= hex(*buf++);
|
||||
}
|
||||
if (_gdbSupportLibWriteByte(ch, (unsigned char *) mem++) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
static int hexToInt(char **ptr, unsigned int *intValue)
|
||||
{
|
||||
int numChars = 0;
|
||||
int hexValue;
|
||||
|
||||
*intValue = 0;
|
||||
|
||||
while (**ptr) {
|
||||
hexValue = hex(**ptr);
|
||||
if (hexValue < 0)
|
||||
break;
|
||||
|
||||
*intValue = (*intValue << 4) | hexValue;
|
||||
numChars ++;
|
||||
|
||||
(*ptr)++;
|
||||
}
|
||||
|
||||
return numChars;
|
||||
}
|
||||
|
||||
#define SW_BREAK_INST 0x0000000d
|
||||
/* Define some opcode stuff for the stepping function */
|
||||
#define BEQ_OPCODE 0x4
|
||||
#define BEQL_OPCODE 0x14
|
||||
#define BGTZ_OPCODE 0x7
|
||||
#define BGTZL_OPCODE 0x17
|
||||
#define BLEZ_OPCODE 0x6
|
||||
#define BLEZL_OPCODE 0x16
|
||||
#define BNE_OPCODE 0x5
|
||||
#define BNEL_OPCODE 0x15
|
||||
|
||||
/* Reg Imm */
|
||||
#define REGIMM_OPCODE 0x1
|
||||
#define BGEZ_OPCODE 0x1
|
||||
#define BGEZAL_OPCODE 0x11
|
||||
#define BGEZALL_OPCODE 0x13
|
||||
#define BGEZL_OPCODE 0x3
|
||||
#define BLTZ_OPCODE 0
|
||||
#define BLTZAL_OPCODE 0x10
|
||||
#define BLTZALL_OPCODE 0x12
|
||||
#define BLTZL_OPCODE 0x2
|
||||
|
||||
#define J_OPCODE 0x2
|
||||
#define JAL_OPCODE 0x3
|
||||
|
||||
/* Special opcode */
|
||||
#define SPECIAL_OPCODE 0
|
||||
#define JALR_OPCODE 0x9
|
||||
#define JR_OPCODE 0x8
|
||||
|
||||
/* Cop Branches (all the same) */
|
||||
#define COP0_OPCODE 0x10
|
||||
#define COP1_OPCODE 0x11
|
||||
#define COP2_OPCODE 0x12
|
||||
#define BCXF_OPCODE 0x100
|
||||
#define BCXFL_OPCODE 0x102
|
||||
#define BCXT_OPCODE 0x101
|
||||
#define BCXTL_OPCODE 0x103
|
||||
|
||||
/* Generic step command , if skip then will try to skip over jals */
|
||||
static void step_generic(PspDebugRegBlock *regs, int skip)
|
||||
{
|
||||
u32 opcode;
|
||||
u32 epc;
|
||||
u32 targetpc;
|
||||
int branch = 0;
|
||||
int cond = 0;
|
||||
int link = 0;
|
||||
|
||||
epc = regs->epc;
|
||||
targetpc = epc + 4;
|
||||
|
||||
opcode = _lw(epc);
|
||||
|
||||
switch(opcode >> 26)
|
||||
{
|
||||
case BEQ_OPCODE:
|
||||
case BEQL_OPCODE:
|
||||
case BGTZ_OPCODE:
|
||||
case BGTZL_OPCODE:
|
||||
case BLEZ_OPCODE:
|
||||
case BLEZL_OPCODE:
|
||||
case BNE_OPCODE:
|
||||
case BNEL_OPCODE:
|
||||
{
|
||||
short ofs;
|
||||
|
||||
ofs = (short) (opcode & 0xffff);
|
||||
cond = 1;
|
||||
branch = 1;
|
||||
targetpc += ofs * 4;
|
||||
}
|
||||
break;
|
||||
case REGIMM_OPCODE: {
|
||||
switch((opcode >> 16) & 0x1f)
|
||||
{
|
||||
case BGEZ_OPCODE:
|
||||
case BGEZAL_OPCODE:
|
||||
case BGEZALL_OPCODE:
|
||||
case BGEZL_OPCODE:
|
||||
case BLTZ_OPCODE:
|
||||
case BLTZAL_OPCODE:
|
||||
case BLTZALL_OPCODE:
|
||||
case BLTZL_OPCODE: {
|
||||
short ofs;
|
||||
|
||||
ofs = (short) (opcode & 0xffff);
|
||||
cond = 1;
|
||||
branch = 1;
|
||||
targetpc += ofs * 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JAL_OPCODE: link = 1;
|
||||
case J_OPCODE: {
|
||||
u32 ofs;
|
||||
|
||||
ofs = opcode & 0x3ffffff;
|
||||
targetpc = (ofs << 2) | (targetpc & 0xf0000000);
|
||||
branch = 1;
|
||||
cond = 0;
|
||||
}
|
||||
break;
|
||||
case SPECIAL_OPCODE:
|
||||
{
|
||||
switch(opcode & 0x3f)
|
||||
{
|
||||
case JALR_OPCODE: link = 1;
|
||||
case JR_OPCODE:
|
||||
{
|
||||
u32 rs;
|
||||
|
||||
rs = (opcode >> 21) & 0x1f;
|
||||
targetpc = regs->r[rs];
|
||||
branch = 1;
|
||||
cond = 0;
|
||||
}
|
||||
break;
|
||||
};
|
||||
}
|
||||
break;
|
||||
case COP0_OPCODE:
|
||||
case COP1_OPCODE:
|
||||
case COP2_OPCODE:
|
||||
{
|
||||
switch((opcode >> 16) & 0x3ff)
|
||||
{
|
||||
case BCXF_OPCODE:
|
||||
case BCXFL_OPCODE:
|
||||
case BCXT_OPCODE:
|
||||
case BCXTL_OPCODE:
|
||||
{
|
||||
short ofs;
|
||||
|
||||
ofs = (short) (opcode & 0xffff);
|
||||
cond = 1;
|
||||
branch = 1;
|
||||
targetpc += ofs * 4;
|
||||
}
|
||||
break;
|
||||
};
|
||||
}
|
||||
break;
|
||||
};
|
||||
|
||||
if(link && skip)
|
||||
{
|
||||
g_stepbp[1].addr = epc + 8;
|
||||
g_stepbp[1].oldinst = _lw(epc + 8);
|
||||
g_stepbp[1].active = 1;
|
||||
_sw(SW_BREAK_INST, epc + 8);
|
||||
}
|
||||
else if(branch)
|
||||
{
|
||||
g_stepbp[0].addr = targetpc;
|
||||
g_stepbp[0].oldinst = _lw(targetpc);
|
||||
g_stepbp[0].active = 1;
|
||||
_sw(SW_BREAK_INST, targetpc);
|
||||
|
||||
if((cond) && (targetpc != (epc + 8)))
|
||||
{
|
||||
g_stepbp[1].addr = epc + 8;
|
||||
g_stepbp[1].oldinst = _lw(epc + 8);
|
||||
g_stepbp[1].active = 1;
|
||||
_sw(SW_BREAK_INST, epc + 8);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
g_stepbp[0].addr = targetpc;
|
||||
g_stepbp[0].active = 1;
|
||||
g_stepbp[0].oldinst = _lw(targetpc);
|
||||
_sw(SW_BREAK_INST, targetpc);
|
||||
}
|
||||
}
|
||||
|
||||
void build_trap_cmd(int sigval, PspDebugRegBlock *regs)
|
||||
{
|
||||
char *ptr;
|
||||
/*
|
||||
* reply to host that an exception has occurred
|
||||
*/
|
||||
ptr = output;
|
||||
*ptr++ = 'T';
|
||||
*ptr++ = hexchars[(sigval >> 4) & 0xf];
|
||||
*ptr++ = hexchars[sigval & 0xf];
|
||||
|
||||
/*
|
||||
* Send Error PC
|
||||
*/
|
||||
*ptr++ = hexchars[37 >> 4];
|
||||
*ptr++ = hexchars[37 & 0xf];
|
||||
*ptr++ = ':';
|
||||
ptr = mem2hex((unsigned char *) ®s->epc, ptr, sizeof(u32));
|
||||
*ptr++ = ';';
|
||||
|
||||
/*
|
||||
* Send frame pointer
|
||||
*/
|
||||
*ptr++ = hexchars[30 >> 4];
|
||||
*ptr++ = hexchars[30 & 0xf];
|
||||
*ptr++ = ':';
|
||||
ptr = mem2hex((unsigned char *)®s->r[30], ptr, sizeof(u32));
|
||||
*ptr++ = ';';
|
||||
|
||||
/*
|
||||
* Send stack pointer
|
||||
*/
|
||||
*ptr++ = hexchars[29 >> 4];
|
||||
*ptr++ = hexchars[29 & 0xf];
|
||||
*ptr++ = ':';
|
||||
ptr = mem2hex((unsigned char *)®s->r[29], ptr, sizeof(u32));
|
||||
*ptr++ = ';';
|
||||
|
||||
*ptr++ = 0;
|
||||
}
|
||||
|
||||
static void handle_query(char *str)
|
||||
{
|
||||
static SceUID threads[100];
|
||||
static int thread_count = 0;
|
||||
static int thread_loc = 0;
|
||||
|
||||
switch(str[0])
|
||||
{
|
||||
case 'f':
|
||||
if(strncmp(str, "fThreadInfo", strlen("fThreadInfo")) == 0)
|
||||
{
|
||||
thread_count = sceKernelGetThreadmanIdList(SCE_KERNEL_TMID_Thread, threads, 100, &thread_count);
|
||||
if(thread_count > 0)
|
||||
{
|
||||
thread_loc = 0;
|
||||
output[0] = 'm';
|
||||
mem2hex((unsigned char *) &threads[thread_loc], &output[1], 4);
|
||||
output[9] = 0;
|
||||
thread_loc++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if(strncmp(str, "sThreadInfo", strlen("sThreadInfo")) == 0)
|
||||
{
|
||||
if(thread_loc < thread_count)
|
||||
{
|
||||
output[0] = 'm';
|
||||
mem2hex((unsigned char *) &threads[thread_loc], &output[1], 4);
|
||||
output[9] = 0;
|
||||
thread_loc++;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(output, "l");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
static void handle_exception (PspDebugRegBlock *regs)
|
||||
{
|
||||
int trap;
|
||||
int sigval;
|
||||
unsigned int addr;
|
||||
unsigned int length;
|
||||
char *ptr;
|
||||
int bflag = 0;
|
||||
|
||||
trap = (regs->cause & 0x7c) >> 2;
|
||||
sigval = computeSignal(trap);
|
||||
|
||||
if(sigval == SIGHUP)
|
||||
{
|
||||
DEBUG_PRINTF("Trap %d\n", trap);
|
||||
}
|
||||
|
||||
/* We stopped in breakpoint, so set epc to our ra */
|
||||
if((regs->epc == (u32) pspDebugBreakpoint) && (trap == 9))
|
||||
{
|
||||
regs->epc = regs->r[31];
|
||||
}
|
||||
|
||||
/* If step breakpoints set then put back the old values */
|
||||
if(g_stepbp[0].active)
|
||||
{
|
||||
_sw(g_stepbp[0].oldinst, g_stepbp[0].addr);
|
||||
g_stepbp[0].active = 0;
|
||||
}
|
||||
|
||||
if(g_stepbp[1].active)
|
||||
{
|
||||
_sw(g_stepbp[1].oldinst, g_stepbp[1].addr);
|
||||
g_stepbp[1].active = 0;
|
||||
}
|
||||
|
||||
if(last_cmd != 0)
|
||||
{
|
||||
build_trap_cmd(sigval, regs);
|
||||
putpacket((unsigned char *) output);
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
getpacket(input);
|
||||
DEBUG_PRINTF("Received packet '%s'\n", input);
|
||||
|
||||
output[0] = 0;
|
||||
|
||||
switch (input[0])
|
||||
{
|
||||
case '?':
|
||||
if(last_cmd == 0)
|
||||
{
|
||||
build_trap_cmd(sigval, regs);
|
||||
}
|
||||
else
|
||||
{
|
||||
output[0] = 'S';
|
||||
output[1] = hexchars[sigval >> 4];
|
||||
output[2] = hexchars[sigval & 0xf];
|
||||
output[3] = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
ptr = &input[1];
|
||||
if (hexToInt(&ptr, &addr))
|
||||
{
|
||||
regs->epc = addr;
|
||||
}
|
||||
|
||||
goto restart;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
putpacket((unsigned char *) output);
|
||||
attached = 0;
|
||||
goto restart;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
ptr = output;
|
||||
ptr = (char*) mem2hex((unsigned char *)®s->r[0], ptr, 32*sizeof(u32)); /* r0...r31 */
|
||||
ptr = (char*) mem2hex((unsigned char *)®s->status, ptr, 6*sizeof(u32)); /* cp0 */
|
||||
ptr = (char*) mem2hex((unsigned char *)®s->fpr[0], ptr, 32*sizeof(u32)); /* f0...31 */
|
||||
ptr = (char*) mem2hex((unsigned char *)®s->fsr, ptr, 2*sizeof(u32)); /* cp1 */
|
||||
ptr = (char*) mem2hex((unsigned char *)®s->frame_ptr, ptr, 2*sizeof(u32)); /* frp */
|
||||
ptr = (char*) mem2hex((unsigned char *)®s->index, ptr, 16*sizeof(u32)); /* cp0 */
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
ptr = &input[1];
|
||||
hex2mem(ptr, (char *)®s->r[0], 32*sizeof(unsigned int), 0);
|
||||
ptr += 32*(2*sizeof(unsigned int));
|
||||
hex2mem(ptr, (char *)®s->status, 6*sizeof(unsigned int), 0);
|
||||
ptr += 6*(2*sizeof(unsigned int));
|
||||
hex2mem(ptr, (char *)®s->fpr[0], 32*sizeof(unsigned int), 0);
|
||||
ptr += 32*(2*sizeof(unsigned int));
|
||||
hex2mem(ptr, (char *)®s->fsr, 2*sizeof(unsigned int), 0);
|
||||
ptr += 2*(2*sizeof(unsigned int));
|
||||
hex2mem(ptr, (char *)®s->frame_ptr, 2*sizeof(unsigned int), 0);
|
||||
ptr += 2*(2*sizeof(unsigned int));
|
||||
hex2mem(ptr, (char *)®s->index, 16*sizeof(unsigned int), 0);
|
||||
strcpy(output,"OK");
|
||||
break;
|
||||
|
||||
/*
|
||||
* mAA..AA,LLLL Read LLLL bytes at address AA..AA
|
||||
*/
|
||||
case 'm':
|
||||
ptr = &input[1];
|
||||
|
||||
if (hexToInt(&ptr, &addr)
|
||||
&& *ptr++ == ','
|
||||
&& hexToInt(&ptr, &length)) {
|
||||
if (mem2hex((unsigned char *)addr, output, length))
|
||||
break;
|
||||
strcpy (output, "E03");
|
||||
} else
|
||||
strcpy(output,"E01");
|
||||
break;
|
||||
|
||||
/*
|
||||
* XAA..AA,LLLL: Write LLLL escaped binary bytes at address AA.AA
|
||||
*/
|
||||
case 'X':
|
||||
bflag = 1;
|
||||
/* fall through */
|
||||
|
||||
/*
|
||||
* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK
|
||||
*/
|
||||
case 'M':
|
||||
ptr = &input[1];
|
||||
|
||||
if (hexToInt(&ptr, &addr)
|
||||
&& *ptr++ == ','
|
||||
&& hexToInt(&ptr, &length)
|
||||
&& *ptr++ == ':') {
|
||||
if (hex2mem(ptr, (char *)addr, length, bflag))
|
||||
strcpy(output, "OK");
|
||||
else
|
||||
strcpy(output, "E03");
|
||||
}
|
||||
else
|
||||
strcpy(output, "E02");
|
||||
bflag = 0;
|
||||
break;
|
||||
|
||||
case 's': ptr = &input[1];
|
||||
if (hexToInt(&ptr, &addr))
|
||||
{
|
||||
regs->epc = addr;
|
||||
}
|
||||
|
||||
step_generic(regs, 0);
|
||||
goto restart;
|
||||
break;
|
||||
|
||||
case 'q': handle_query(&input[1]);
|
||||
break;
|
||||
|
||||
/*
|
||||
* kill the program; let us try to restart the machine
|
||||
* Reset the whole machine.
|
||||
*/
|
||||
case 'k':
|
||||
case 'r': sceKernelExitGame();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* reply to the request
|
||||
*/
|
||||
|
||||
putpacket((unsigned char *) output);
|
||||
|
||||
} /* while */
|
||||
|
||||
restart:
|
||||
last_cmd = input[0];
|
||||
return ;
|
||||
|
||||
}
|
||||
|
||||
/* Define the breakpoint function */
|
||||
asm (
|
||||
".global pspDebugBreakpoint\n"
|
||||
".set noreorder\n"
|
||||
"pspDebugBreakpoint:\tbreak\n"
|
||||
"jr $31\n"
|
||||
"nop\n"
|
||||
);
|
||||
195
src/debug/gdb-userlib.c
Normal file
195
src/debug/gdb-userlib.c
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* gdb-userlib.c - GDB support functions for user mode.
|
||||
*
|
||||
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
||||
*
|
||||
* $Id: gdb-userlib.c 2166 2007-02-04 10:52:49Z tyranid $
|
||||
*/
|
||||
#include <pspkernel.h>
|
||||
#include <pspdebug.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static int sio_fd = -1;
|
||||
|
||||
/* GDB Debug putchar */
|
||||
void putDebugChar(char ch)
|
||||
{
|
||||
sceIoWrite(sio_fd, &ch, 1);
|
||||
}
|
||||
|
||||
/* GDB Debug getchar */
|
||||
char getDebugChar(void)
|
||||
{
|
||||
char ch = 0;
|
||||
int count = 0;
|
||||
|
||||
while(count <= 0)
|
||||
{
|
||||
count = sceIoRead(sio_fd, &ch, 1);
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
int g_initialised = 0;
|
||||
|
||||
static int io_init(PspIoDrvArg *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_exit(PspIoDrvArg *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_read(PspIoDrvFileArg *arg, char *data, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
int ch;
|
||||
|
||||
while(ret < len)
|
||||
{
|
||||
ch = pspDebugSioGetchar();
|
||||
if(ch != -1)
|
||||
{
|
||||
data[ret++] = ch & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int io_write(PspIoDrvFileArg *arg, const char *data, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
while(ret < len)
|
||||
{
|
||||
pspDebugSioPutchar(data[ret++]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void sceKernelDcacheWBinvAll(void);
|
||||
void sceKernelIcacheClearAll(void);
|
||||
|
||||
static int io_devctl(PspIoDrvFileArg *arg, const char *devname, unsigned int cmd, void *indata, int inlen, void *outdata, int outlen)
|
||||
{
|
||||
pspKernelSetKernelPC();
|
||||
sceKernelDcacheWBinvAll();
|
||||
sceKernelIcacheClearAll();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PspIoDrvFuncs sio_funcs =
|
||||
{
|
||||
io_init,
|
||||
io_exit,
|
||||
NULL,
|
||||
NULL,
|
||||
io_read,
|
||||
io_write,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
io_devctl,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static PspIoDrv sio_driver =
|
||||
{
|
||||
"sio", 0x10, 0x800, "SIO", &sio_funcs
|
||||
};
|
||||
|
||||
int _gdbSupportLibReadByte(unsigned char *address, unsigned char *dest)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
addr = (u32) address;
|
||||
if((addr >= 0x08400000) && (addr < 0x0a000000))
|
||||
{
|
||||
*dest = *address;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
else if((addr >= 0x88000000) && (addr < 0x8a000000))
|
||||
{
|
||||
*dest = *address;
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _gdbSupportLibWriteByte(char val, unsigned char *dest)
|
||||
{
|
||||
u32 addr;
|
||||
|
||||
addr = (u32) dest;
|
||||
if((addr >= 0x08400000) && (addr < 0x0a000000))
|
||||
{
|
||||
*dest = val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
else if((addr >= 0x88000000) && (addr < 0x8a000000))
|
||||
{
|
||||
*dest = val;
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _gdbSupportLibFlushCaches(void)
|
||||
{
|
||||
sceIoDevctl("sio:", 0, NULL, 0, NULL, 0);
|
||||
}
|
||||
|
||||
int _gdbSupportLibInit(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if(!g_initialised)
|
||||
{
|
||||
(void) sceIoDelDrv("sio"); /* Ignore error */
|
||||
ret = sceIoAddDrv(&sio_driver);
|
||||
if(ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
sio_fd = sceIoOpen("sio:", PSP_O_RDWR, 0);
|
||||
|
||||
g_initialised = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
45
src/debug/kprintf.c
Normal file
45
src/debug/kprintf.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* kprintf.c - Basic Kprintf handling for applications.
|
||||
*
|
||||
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
||||
*
|
||||
* $Id: kprintf.c 1095 2005-09-27 21:02:16Z jim $
|
||||
*/
|
||||
|
||||
#include <pspkernel.h>
|
||||
#include <pspdebug.h>
|
||||
|
||||
/* The current kprintf handler */
|
||||
static PspDebugKprintfHandler curr_handler;
|
||||
|
||||
int sceKernelRegisterKprintfHandler(void *func, void *args);
|
||||
|
||||
/* Default kprintf handler */
|
||||
static void _pspDebugDefaultKprintfHandler(const char *format, u32 *args)
|
||||
{
|
||||
pspDebugScreenPrintf(format, args[0], args[1], args[2], args[3]);
|
||||
}
|
||||
|
||||
/* The registered kprintf handler */
|
||||
static void _pspDebugKprintfHandler(void *arg, const char *format, u32 *args)
|
||||
{
|
||||
if(curr_handler != NULL)
|
||||
{
|
||||
curr_handler(format, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
_pspDebugDefaultKprintfHandler(format, args);
|
||||
}
|
||||
}
|
||||
|
||||
/* Install a kprintf handler */
|
||||
int pspDebugInstallKprintfHandler(PspDebugKprintfHandler handler)
|
||||
{
|
||||
curr_handler = handler;
|
||||
return sceKernelRegisterKprintfHandler(_pspDebugKprintfHandler, NULL);
|
||||
}
|
||||
97
src/debug/profiler.c
Normal file
97
src/debug/profiler.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* profiler.c - Debug profiler functions.
|
||||
*
|
||||
* Copyright (c) 2005 Marcus R. Brown <mrbrown@ocgnet.org>
|
||||
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
||||
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
|
||||
*
|
||||
* $Id: profiler.c 2190 2007-02-25 21:00:40Z tyranid $
|
||||
*/
|
||||
#include <pspkernel.h>
|
||||
#include <pspdebug.h>
|
||||
|
||||
#define PROFILER_REG_BASE 0xBC400000
|
||||
#define PROFILER_REG_COUNT 21
|
||||
|
||||
void pspDebugProfilerEnable(void)
|
||||
{
|
||||
_sw(1, PROFILER_REG_BASE);
|
||||
}
|
||||
|
||||
void pspDebugProfilerDisable(void)
|
||||
{
|
||||
_sw(0, PROFILER_REG_BASE);
|
||||
asm("sync\r\n");
|
||||
}
|
||||
|
||||
void pspDebugProfilerClear(void)
|
||||
{
|
||||
u32 addr;
|
||||
int i;
|
||||
|
||||
addr = PROFILER_REG_BASE;
|
||||
/* Don't clear the enable register */
|
||||
for(i = 1; i < PROFILER_REG_COUNT; i++)
|
||||
{
|
||||
addr += 4;
|
||||
_sw(0, addr);
|
||||
}
|
||||
}
|
||||
|
||||
void pspDebugProfilerGetRegs(PspDebugProfilerRegs *regs)
|
||||
{
|
||||
u32 *p_regs;
|
||||
u32 addr;
|
||||
int i;
|
||||
|
||||
if(regs == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
p_regs = (u32 *) regs;
|
||||
|
||||
addr = PROFILER_REG_BASE;
|
||||
for(i = 0; i < PROFILER_REG_COUNT; i++)
|
||||
{
|
||||
p_regs[i] = _lw(addr);
|
||||
addr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void pspDebugProfilerPrint(void)
|
||||
{
|
||||
PspDebugProfilerRegs regs;
|
||||
|
||||
pspDebugProfilerGetRegs(®s);
|
||||
|
||||
pspDebugScreenPrintf("********** Profile ***********\n");
|
||||
pspDebugScreenPrintf("enable : %10u\n", regs.enable);
|
||||
pspDebugScreenPrintf("systemck : %10u [cycles]\n", regs.systemck);
|
||||
pspDebugScreenPrintf("cpu ck : %10u [cycles]\n", regs.cpuck);
|
||||
pspDebugScreenPrintf("stall : %10u [cycles]\n", regs.internal + regs.memory +
|
||||
regs.copz + regs.vfpu);
|
||||
pspDebugScreenPrintf("+(internal) : %10u [cycles]\n", regs.internal);
|
||||
pspDebugScreenPrintf("+--(memory) : %10u [cycles]\n", regs.memory);
|
||||
pspDebugScreenPrintf("+----(COPz) : %10u [cycles]\n", regs.copz);
|
||||
pspDebugScreenPrintf("+----(VFPU) : %10u [cycles]\n", regs.vfpu);
|
||||
pspDebugScreenPrintf("sleep : %10u [cycles]\n", regs.sleep);
|
||||
pspDebugScreenPrintf("bus access : %10u [cycles]\n", regs.bus_access);
|
||||
pspDebugScreenPrintf("uncached load : %10u [times]\n", regs.uncached_load);
|
||||
pspDebugScreenPrintf("uncached store : %10u [times]\n", regs.uncached_store);
|
||||
pspDebugScreenPrintf("cached load : %10u [times]\n", regs.cached_load);
|
||||
pspDebugScreenPrintf("cached store : %10u [times]\n", regs.cached_store);
|
||||
pspDebugScreenPrintf("I cache miss : %10u [times]\n", regs.i_miss);
|
||||
pspDebugScreenPrintf("D cache miss : %10u [times]\n", regs.d_miss);
|
||||
pspDebugScreenPrintf("D cache wb : %10u [times]\n", regs.d_writeback);
|
||||
pspDebugScreenPrintf("COP0 inst. : %10u [inst.]\n", regs.cop0_inst);
|
||||
pspDebugScreenPrintf("FPU inst. : %10u [inst.]\n", regs.fpu_inst);
|
||||
pspDebugScreenPrintf("VFPU inst. : %10u [inst.]\n", regs.vfpu_inst);
|
||||
pspDebugScreenPrintf("local bus : %10u [cycles]\n", regs.local_bus);
|
||||
}
|
||||
|
||||
|
||||
443
src/debug/pspdebug.h
Normal file
443
src/debug/pspdebug.h
Normal file
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* pspdebug.h - Prototypes for the pspDebug library
|
||||
*
|
||||
* Copyright (c) 2005 Marcus R. Brown <mrbrown@ocgnet.org>
|
||||
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
||||
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
|
||||
*
|
||||
* $Id: pspdebug.h 2450 2009-01-04 23:53:02Z oopo $
|
||||
*/
|
||||
#ifndef __DEBUG_H__
|
||||
#define __DEBUG_H__
|
||||
|
||||
#include <psptypes.h>
|
||||
#include <pspmoduleinfo.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @defgroup Debug Debug Utility Library */
|
||||
|
||||
/** @addtogroup Debug */
|
||||
/*@{*/
|
||||
|
||||
/**
|
||||
* Initialise the debug screen
|
||||
*/
|
||||
void pspDebugScreenInit(void);
|
||||
|
||||
/**
|
||||
* Extended debug screen init
|
||||
*
|
||||
* @param vram_base - Base address of frame buffer, if NULL then sets a default
|
||||
* @param mode - Colour mode
|
||||
* @param setup - Setup the screen if 1
|
||||
*/
|
||||
void pspDebugScreenInitEx(void *vram_base, int mode, int setup);
|
||||
|
||||
/**
|
||||
* Do a printf to the debug screen.
|
||||
*
|
||||
* @param fmt - Format string to print
|
||||
* @param ... - Arguments
|
||||
*/
|
||||
void pspDebugScreenPrintf(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
||||
|
||||
/**
|
||||
* Do a printf to the debug screen.
|
||||
* @note This is for kernel mode only as it uses a kernel function
|
||||
* to perform the printf instead of using vsnprintf, use normal printf for
|
||||
* user mode.
|
||||
*
|
||||
* @param format - Format string to print
|
||||
* @param ... - Arguments
|
||||
*/
|
||||
void pspDebugScreenKprintf(const char *format, ...) __attribute__((format(printf,1,2)));
|
||||
|
||||
/**
|
||||
* Enable or disable background colour writing (defaults to enabled)
|
||||
*
|
||||
* @param enable - Set 1 to to enable background color, 0 for disable
|
||||
*/
|
||||
void pspDebugScreenEnableBackColor(int enable);
|
||||
|
||||
/**
|
||||
* Set the background color for the text
|
||||
* @note To reset the entire screens bg colour you need to call pspDebugScreenClear
|
||||
*
|
||||
* @param color - A 32bit RGB colour
|
||||
*/
|
||||
void pspDebugScreenSetBackColor(u32 color);
|
||||
|
||||
/**
|
||||
* Set the text color
|
||||
*
|
||||
* @param color - A 32 bit RGB color
|
||||
*/
|
||||
void pspDebugScreenSetTextColor(u32 color);
|
||||
|
||||
/**
|
||||
* Set the color mode (you must have switched the frame buffer appropriately)
|
||||
*
|
||||
* @param mode - Color mode
|
||||
*/
|
||||
void pspDebugScreenSetColorMode(int mode);
|
||||
|
||||
/**
|
||||
* Draw a single character to the screen.
|
||||
*
|
||||
* @param x - The x co-ordinate to draw to (pixel units)
|
||||
* @param y - The y co-ordinate to draw to (pixel units)
|
||||
* @param color - The text color to draw
|
||||
* @param ch - The character to draw
|
||||
*/
|
||||
void pspDebugScreenPutChar(int x, int y, u32 color, u8 ch);
|
||||
|
||||
/**
|
||||
* Set the current X and Y co-ordinate for the screen (in character units)
|
||||
*/
|
||||
void pspDebugScreenSetXY(int x, int y);
|
||||
|
||||
/**
|
||||
* Set the video ram offset used for the screen
|
||||
*
|
||||
* @param offset - Offset in bytes
|
||||
*/
|
||||
void pspDebugScreenSetOffset(int offset);
|
||||
|
||||
/**
|
||||
* Set the video ram base used for the screen
|
||||
*
|
||||
* @param base - Base address in bytes
|
||||
*/
|
||||
void pspDebugScreenSetBase(u32* base);
|
||||
|
||||
/**
|
||||
* Get the current X co-ordinate (in character units)
|
||||
*
|
||||
* @return The X co-ordinate
|
||||
*/
|
||||
int pspDebugScreenGetX(void);
|
||||
|
||||
/**
|
||||
* Get the current Y co-ordinate (in character units)
|
||||
*
|
||||
* @return The Y co-ordinate
|
||||
*/
|
||||
int pspDebugScreenGetY(void);
|
||||
|
||||
/**
|
||||
* Clear the debug screen.
|
||||
*/
|
||||
void pspDebugScreenClear(void);
|
||||
|
||||
/**
|
||||
* Print non-nul terminated strings.
|
||||
*
|
||||
* @param buff - Buffer containing the text.
|
||||
* @param size - Size of the data
|
||||
*
|
||||
* @return The number of characters written
|
||||
*/
|
||||
int pspDebugScreenPrintData(const char *buff, int size);
|
||||
|
||||
/**
|
||||
* Print a string
|
||||
*
|
||||
* @param str - String
|
||||
*
|
||||
* @return The number of characters written
|
||||
*/
|
||||
int pspDebugScreenPuts(const char *str);
|
||||
|
||||
/**
|
||||
* Get a MIPS stack trace (might work :P)
|
||||
*
|
||||
* @param results - List of points to store the results of the trace, (up to max)
|
||||
* @param max - Maximum number of back traces
|
||||
*
|
||||
* @return The number of frames stored in results.
|
||||
*/
|
||||
int pspDebugGetStackTrace(unsigned int* results, int max);
|
||||
|
||||
/**
|
||||
* Enable the clear line function that allows debug to clear the screen
|
||||
*/
|
||||
void pspDebugScreenClearLineEnable(void);
|
||||
|
||||
/**
|
||||
* Disable the clear line function that causes flicker on constant refreshes
|
||||
*/
|
||||
void pspDebugScreenClearLineDisable(void);
|
||||
|
||||
/** Structure to hold the register data associated with an exception */
|
||||
typedef struct _PspDebugRegBlock
|
||||
{
|
||||
u32 frame[6];
|
||||
/** Array of the 32 GPRs */
|
||||
u32 r[32];
|
||||
/** The status register */
|
||||
u32 status;
|
||||
/** lo */
|
||||
u32 lo;
|
||||
u32 hi;
|
||||
u32 badvaddr;
|
||||
u32 cause;
|
||||
u32 epc;
|
||||
float fpr[32];
|
||||
u32 fsr;
|
||||
u32 fir;
|
||||
u32 frame_ptr;
|
||||
u32 unused;
|
||||
/* Unused on PSP */
|
||||
u32 index;
|
||||
u32 random;
|
||||
u32 entrylo0;
|
||||
u32 entrylo1;
|
||||
u32 context;
|
||||
u32 pagemask;
|
||||
u32 wired;
|
||||
u32 cop0_7;
|
||||
u32 cop0_8;
|
||||
u32 cop0_9;
|
||||
u32 entryhi;
|
||||
u32 cop0_11;
|
||||
u32 cop0_12;
|
||||
u32 cop0_13;
|
||||
u32 cop0_14;
|
||||
/* PRId should still be okay */
|
||||
u32 prid;
|
||||
u32 padding[100];
|
||||
} PspDebugRegBlock;
|
||||
|
||||
/** Defines a debug error handler */
|
||||
typedef void (*PspDebugErrorHandler)(PspDebugRegBlock *regs);
|
||||
|
||||
/**
|
||||
* Install an error handler to catch unhandled exceptions.
|
||||
*
|
||||
* @param handler - Pointer to a handler function. If set to NULL it will default
|
||||
* to resetting the screen and dumping the error.
|
||||
* @return < 0 on error
|
||||
*/
|
||||
int pspDebugInstallErrorHandler(PspDebugErrorHandler handler);
|
||||
|
||||
/**
|
||||
* Dump an exception to screen using the pspDebugScreen functions.
|
||||
* @note This function will not setup the screen for debug output, you should call sceDebugScreenInit
|
||||
* before using it if it isn't already.
|
||||
*
|
||||
* @param regs - Pointer to a register block.
|
||||
*
|
||||
*/
|
||||
void pspDebugDumpException(PspDebugRegBlock *regs);
|
||||
|
||||
/** Type for Kprintf handler */
|
||||
typedef int (*PspDebugKprintfHandler)(const char *format, u32 *args);
|
||||
|
||||
/**
|
||||
* Install a Kprintf handler into the system.
|
||||
*
|
||||
* @param handler - Function pointer to the handler.
|
||||
* @return < 0 on error.
|
||||
*/
|
||||
int pspDebugInstallKprintfHandler(PspDebugKprintfHandler handler);
|
||||
|
||||
/** Structure to hold a single stack trace entry */
|
||||
typedef struct _PspDebugStackTrace
|
||||
{
|
||||
/** The address which called the function */
|
||||
u32 call_addr;
|
||||
/** The address of the function called */
|
||||
u32 func_addr;
|
||||
} PspDebugStackTrace;
|
||||
|
||||
/**
|
||||
* Do a stack trace from the current exception.
|
||||
* @note This function really isn't too general purpose and it is more than likely to generate a few
|
||||
* false positives but I consider that better then missing out calls entirely. You have to use your
|
||||
* discretion, your code and a objdump to work out if some calls are completely surprious or not ;)
|
||||
*
|
||||
* @param regs - Pointer to a register block from an exception.
|
||||
* @param trace - Pointer to an array of PspDebugStackTrace structures.
|
||||
* @param max - The maximum number of traces to make.
|
||||
*
|
||||
* @return The number of functions found.
|
||||
*/
|
||||
int pspDebugGetStackTrace2(PspDebugRegBlock *regs, PspDebugStackTrace *trace, int max);
|
||||
|
||||
/** Structure to hold the psp profiler register values */
|
||||
typedef struct _PspDebugProfilerRegs
|
||||
{
|
||||
volatile u32 enable;
|
||||
volatile u32 systemck;
|
||||
volatile u32 cpuck;
|
||||
volatile u32 internal;
|
||||
volatile u32 memory;
|
||||
volatile u32 copz;
|
||||
volatile u32 vfpu;
|
||||
volatile u32 sleep;
|
||||
volatile u32 bus_access;
|
||||
volatile u32 uncached_load;
|
||||
volatile u32 uncached_store;
|
||||
volatile u32 cached_load;
|
||||
volatile u32 cached_store;
|
||||
volatile u32 i_miss;
|
||||
volatile u32 d_miss;
|
||||
volatile u32 d_writeback;
|
||||
volatile u32 cop0_inst;
|
||||
volatile u32 fpu_inst;
|
||||
volatile u32 vfpu_inst;
|
||||
volatile u32 local_bus;
|
||||
} PspDebugProfilerRegs;
|
||||
|
||||
/** Enables the profiler hardware */
|
||||
void pspDebugProfilerEnable(void);
|
||||
|
||||
/** Disables the profiler hardware */
|
||||
void pspDebugProfilerDisable(void);
|
||||
|
||||
/** Clear the profiler registers */
|
||||
void pspDebugProfilerClear(void);
|
||||
|
||||
/** Get the profiler register state
|
||||
*
|
||||
* @param regs - A pointer to a PspDebugProfilerRegs structure.
|
||||
*/
|
||||
void pspDebugProfilerGetRegs(PspDebugProfilerRegs *regs);
|
||||
|
||||
/** Print the profiler registers to screen */
|
||||
void pspDebugProfilerPrint(void);
|
||||
|
||||
/** Type for the debug print handlers */
|
||||
typedef int (*PspDebugPrintHandler)(const char *data, int len);
|
||||
|
||||
/** Type for the debug input handler */
|
||||
typedef int (*PspDebugInputHandler)(char *data, int len);
|
||||
|
||||
/**
|
||||
* Install a handler for stdin (so you can use normal stdio functions)
|
||||
*
|
||||
* @param handler - A pointer to input handler, NULL to disable.
|
||||
*
|
||||
* @return < 0 on error, else 0.
|
||||
*/
|
||||
int pspDebugInstallStdinHandler(PspDebugInputHandler handler);
|
||||
|
||||
/**
|
||||
* Install a print handler for stdout (so you can use normal print functions)
|
||||
*
|
||||
* @param handler - A pointer to print handler, NULL to disable.
|
||||
*
|
||||
* @return < 0 on error, else 0.
|
||||
*/
|
||||
int pspDebugInstallStdoutHandler(PspDebugPrintHandler handler);
|
||||
|
||||
/**
|
||||
* Install a print handler for stderr (so you can use normal print functions)
|
||||
*
|
||||
* @param handler - A pointer to print handler, NULL to disable.
|
||||
*
|
||||
* @return < 0 on error, else 0.
|
||||
*/
|
||||
int pspDebugInstallStderrHandler(PspDebugPrintHandler handler);
|
||||
|
||||
/**
|
||||
* Put a character to the remote sio.
|
||||
*
|
||||
* @param ch - Character to write.
|
||||
*/
|
||||
void pspDebugSioPutchar(int ch);
|
||||
|
||||
/**
|
||||
* Get a character from the remote sio
|
||||
*
|
||||
* @return The character read or -1 if no characters available.
|
||||
*/
|
||||
int pspDebugSioGetchar(void);
|
||||
|
||||
/**
|
||||
* Write a string to the sio port.
|
||||
*
|
||||
* @param str - String to write.
|
||||
*/
|
||||
void pspDebugSioPuts(const char *str);
|
||||
|
||||
/**
|
||||
* Write a set of data to the sio port
|
||||
*
|
||||
* @param data - Pointer to the data to send.
|
||||
* @param len - Length of the data.
|
||||
*
|
||||
* @return Number of characters written.
|
||||
*/
|
||||
int pspDebugSioPutData(const char *data, int len);
|
||||
|
||||
/**
|
||||
* Write a set of data to the sio port converting single
|
||||
* line feeds to CRLF and single CR to CRLF
|
||||
*
|
||||
* @param data - Pointer to the data to send.
|
||||
* @param len - Length of the data.
|
||||
*
|
||||
* @return Number of characters written.
|
||||
*/
|
||||
int pspDebugSioPutText(const char *data, int len);
|
||||
|
||||
/**
|
||||
* Initialise the remote SIO port (defaults to 4800 8N1).
|
||||
* @note will delay 2 seconds to wait for the power to come up.
|
||||
*/
|
||||
void pspDebugSioInit(void);
|
||||
|
||||
/**
|
||||
* Set the baud rate of the SIO, e.g. 4800/9600..115200.
|
||||
* @param baud - The baudrate to set.
|
||||
*/
|
||||
void pspDebugSioSetBaud(int baud);
|
||||
|
||||
/**
|
||||
* Enable debug character output. Needs to be called in order
|
||||
* for the default Kprintf handler to work.
|
||||
*/
|
||||
void pspDebugEnablePutchar(void);
|
||||
|
||||
/**
|
||||
* Install a kprintf debug putchar handler. Implicitly calls ::pspDebugEnablePutchar
|
||||
* so you do not need to call it explicitly. Sio must be initialised before calling
|
||||
* this function however.
|
||||
*/
|
||||
void pspDebugSioInstallKprintf(void);
|
||||
|
||||
/**
|
||||
* Install the gdb stub handler.
|
||||
*/
|
||||
void pspDebugGdbStubInit(void);
|
||||
|
||||
/**
|
||||
* Generate a breakpoint exception.
|
||||
*/
|
||||
void pspDebugBreakpoint(void);
|
||||
|
||||
/**
|
||||
* Enable the kprintf handler (once installed)
|
||||
*/
|
||||
void pspDebugSioEnableKprintf(void);
|
||||
|
||||
/**
|
||||
* Disable the kprintf handler (once installed)
|
||||
*/
|
||||
void pspDebugSioDisableKprintf(void);
|
||||
|
||||
/*@}*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
292
src/debug/pspdebugkb.c
Normal file
292
src/debug/pspdebugkb.c
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* pspdebugkb.c - Simple screen debug keyboard
|
||||
*
|
||||
* Copyright (c) 2006 Mike Mallett <mike@nerdcore.net>
|
||||
*
|
||||
* $Id: pspdebugkb.c 2112 2006-12-22 10:53:20Z tyranid $
|
||||
*/
|
||||
#include <pspdebug.h>
|
||||
#include <pspctrl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "pspdebugkb.h"
|
||||
|
||||
static char loCharTable[PSP_DEBUG_KB_NUM_ROWS][PSP_DEBUG_KB_NUM_CHARS] = {
|
||||
{ '`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=' },
|
||||
{ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\\' },
|
||||
{ '\0', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '\0' },
|
||||
{ '\0', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '\0', '\0' }
|
||||
};
|
||||
|
||||
static char hiCharTable[PSP_DEBUG_KB_NUM_ROWS][PSP_DEBUG_KB_NUM_CHARS] = {
|
||||
{ '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+' },
|
||||
{ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '|' },
|
||||
{ '\0', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '\0' },
|
||||
{ '\0', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', '\0', '\0' }
|
||||
};
|
||||
|
||||
static char *commandRow[] = { "Shift", "[ ]", "Back", "Clear", "Done" };
|
||||
|
||||
char charTable[PSP_DEBUG_KB_NUM_ROWS][PSP_DEBUG_KB_NUM_CHARS];
|
||||
|
||||
/* Switch charTable when Shift is pressed */
|
||||
void pspDebugKbShift(int* shiftState) {
|
||||
int i, j;
|
||||
|
||||
if (*shiftState != 0) {
|
||||
for (i=0; i<PSP_DEBUG_KB_NUM_ROWS; i++) {
|
||||
for (j=0; j<PSP_DEBUG_KB_NUM_CHARS; j++) {
|
||||
charTable[i][j] = loCharTable[i][j];
|
||||
}
|
||||
}
|
||||
*shiftState = 0;
|
||||
} else {
|
||||
for (i=0; i<PSP_DEBUG_KB_NUM_ROWS; i++) {
|
||||
for (j=0; j<PSP_DEBUG_KB_NUM_CHARS; j++) {
|
||||
charTable[i][j] = hiCharTable[i][j];
|
||||
}
|
||||
}
|
||||
*shiftState = 1;
|
||||
}
|
||||
pspDebugKbDrawBox();
|
||||
}
|
||||
|
||||
void pspDebugKbDrawKey(int row, int col, int highlight) {
|
||||
int i;
|
||||
int spacing = 0;
|
||||
int charsTo = 0;
|
||||
int charsTotal = 0;
|
||||
|
||||
if (highlight) {
|
||||
pspDebugScreenSetTextColor(PSP_DEBUG_KB_CHAR_HIGHLIGHT);
|
||||
pspDebugScreenSetBackColor(PSP_DEBUG_KB_BACK_HIGHLIGHT);
|
||||
} else {
|
||||
pspDebugScreenSetTextColor(PSP_DEBUG_KB_CHAR_COLOUR);
|
||||
pspDebugScreenSetBackColor(PSP_DEBUG_KB_BACK_COLOUR);
|
||||
}
|
||||
|
||||
if (row == PSP_DEBUG_KB_COMMAND_ROW) {
|
||||
for (i=0; i<PSP_DEBUG_KB_NUM_COMMANDS; i++) {
|
||||
charsTotal += strlen(commandRow[i]);
|
||||
if (i < col) { charsTo += strlen(commandRow[i]); }
|
||||
}
|
||||
spacing = (PSP_DEBUG_KB_BOX_WIDTH - charsTotal) / (PSP_DEBUG_KB_NUM_COMMANDS + 1);
|
||||
pspDebugScreenSetXY(PSP_DEBUG_KB_BOX_X + (spacing * (col + 1)) + charsTo, PSP_DEBUG_KB_BOX_Y + (PSP_DEBUG_KB_SPACING_Y * (row + 2)));
|
||||
pspDebugScreenPrintf("%s", commandRow[col]);
|
||||
} else {
|
||||
pspDebugScreenSetXY(PSP_DEBUG_KB_BOX_X + PSP_DEBUG_KB_OFFSET_X + (PSP_DEBUG_KB_SPACING_X * col), PSP_DEBUG_KB_BOX_Y + (PSP_DEBUG_KB_SPACING_Y * (row + 2)));
|
||||
if (charTable[row][col] == '\0') {
|
||||
pspDebugScreenPrintf(" ");
|
||||
} else {
|
||||
pspDebugScreenPrintf("%c", charTable[row][col]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pspDebugKbClearBox() {
|
||||
int i, j;
|
||||
|
||||
pspDebugScreenSetTextColor(PSP_DEBUG_KB_CHAR_COLOUR);
|
||||
pspDebugScreenSetBackColor(PSP_DEBUG_KB_BACK_COLOUR);
|
||||
|
||||
for (i = PSP_DEBUG_KB_BOX_X; i <= PSP_DEBUG_KB_BOX_X + PSP_DEBUG_KB_BOX_WIDTH; i++) {
|
||||
for (j = PSP_DEBUG_KB_BOX_Y; j <= PSP_DEBUG_KB_BOX_Y + PSP_DEBUG_KB_BOX_HEIGHT; j++) {
|
||||
pspDebugScreenSetXY(i, j);
|
||||
pspDebugScreenPrintf(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pspDebugKbDrawBox() {
|
||||
int i, j;
|
||||
|
||||
pspDebugScreenSetTextColor(PSP_DEBUG_KB_CHAR_COLOUR);
|
||||
pspDebugScreenSetBackColor(PSP_DEBUG_KB_BACK_COLOUR);
|
||||
|
||||
pspDebugScreenSetXY(PSP_DEBUG_KB_BOX_X, PSP_DEBUG_KB_BOX_Y);
|
||||
pspDebugScreenPrintf("+");
|
||||
pspDebugScreenSetXY(PSP_DEBUG_KB_BOX_X, PSP_DEBUG_KB_BOX_Y + PSP_DEBUG_KB_BOX_HEIGHT);
|
||||
pspDebugScreenPrintf("+");
|
||||
pspDebugScreenSetXY(PSP_DEBUG_KB_BOX_X + PSP_DEBUG_KB_BOX_WIDTH, PSP_DEBUG_KB_BOX_Y);
|
||||
pspDebugScreenPrintf("+");
|
||||
pspDebugScreenSetXY(PSP_DEBUG_KB_BOX_X + PSP_DEBUG_KB_BOX_WIDTH, PSP_DEBUG_KB_BOX_Y + PSP_DEBUG_KB_BOX_HEIGHT);
|
||||
pspDebugScreenPrintf("+");
|
||||
|
||||
for (i = 1; i < PSP_DEBUG_KB_BOX_WIDTH; i++) {
|
||||
pspDebugScreenSetXY(PSP_DEBUG_KB_BOX_X + i, PSP_DEBUG_KB_BOX_Y);
|
||||
pspDebugScreenPrintf("-");
|
||||
pspDebugScreenSetXY(PSP_DEBUG_KB_BOX_X + i, PSP_DEBUG_KB_BOX_Y + PSP_DEBUG_KB_BOX_HEIGHT);
|
||||
pspDebugScreenPrintf("-");
|
||||
}
|
||||
|
||||
for (i = 1; i < PSP_DEBUG_KB_BOX_HEIGHT; i++) {
|
||||
pspDebugScreenSetXY(PSP_DEBUG_KB_BOX_X, PSP_DEBUG_KB_BOX_Y + i);
|
||||
pspDebugScreenPrintf("|");
|
||||
pspDebugScreenSetXY(PSP_DEBUG_KB_BOX_X + PSP_DEBUG_KB_BOX_WIDTH, PSP_DEBUG_KB_BOX_Y + i);
|
||||
pspDebugScreenPrintf("|");
|
||||
}
|
||||
|
||||
for (i = 0; i < PSP_DEBUG_KB_NUM_ROWS; i++) {
|
||||
for (j = 0; j < PSP_DEBUG_KB_NUM_CHARS; j++) {
|
||||
pspDebugKbDrawKey(i, j, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < PSP_DEBUG_KB_NUM_COMMANDS; i++) {
|
||||
pspDebugKbDrawKey(PSP_DEBUG_KB_COMMAND_ROW, i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void pspDebugKbDrawString(char* str) {
|
||||
int i;
|
||||
|
||||
pspDebugScreenSetTextColor(PSP_DEBUG_KB_CHAR_COLOUR);
|
||||
pspDebugScreenSetBackColor(PSP_DEBUG_KB_BACK_COLOUR);
|
||||
|
||||
pspDebugScreenSetXY(PSP_DEBUG_KB_BOX_X + ((PSP_DEBUG_KB_BOX_WIDTH - PSP_DEBUG_KB_MAXLEN) / 2), PSP_DEBUG_KB_BOX_Y + 1);
|
||||
for (i=0; i<PSP_DEBUG_KB_MAXLEN; i++) {
|
||||
pspDebugScreenPrintf("_");
|
||||
}
|
||||
|
||||
pspDebugScreenSetXY(PSP_DEBUG_KB_BOX_X + ((PSP_DEBUG_KB_BOX_WIDTH - PSP_DEBUG_KB_MAXLEN) / 2), PSP_DEBUG_KB_BOX_Y + 1);
|
||||
pspDebugScreenPrintf("%s", str);
|
||||
}
|
||||
|
||||
void pspDebugKbInit(char* str) {
|
||||
int row = PSP_DEBUG_KB_COMMAND_ROW;
|
||||
int col = PSP_DEBUG_KB_NUM_COMMANDS - 1;
|
||||
int shifted = 1;
|
||||
int inputDelay = 200000;
|
||||
|
||||
sceCtrlSetSamplingCycle(0);
|
||||
sceCtrlSetSamplingMode(PSP_CTRL_MODE_DIGITAL);
|
||||
|
||||
SceCtrlData input, lastinput;
|
||||
sceCtrlReadBufferPositive(&input, 1);
|
||||
sceCtrlReadBufferPositive(&lastinput, 1);
|
||||
|
||||
unsigned int inputTime = input.TimeStamp;
|
||||
|
||||
pspDebugKbClearBox();
|
||||
|
||||
// Initialize charTable
|
||||
pspDebugKbShift(&shifted);
|
||||
|
||||
pspDebugKbDrawBox();
|
||||
pspDebugKbDrawKey(row, col, 1);
|
||||
pspDebugKbDrawString(str);
|
||||
|
||||
while (1) {
|
||||
sceCtrlReadBufferPositive(&input, 1);
|
||||
|
||||
if (input.Buttons & PSP_CTRL_LEFT && col > 0
|
||||
&& (row == PSP_DEBUG_KB_COMMAND_ROW || charTable[row][col - 1])
|
||||
&& (input.Buttons != lastinput.Buttons || input.TimeStamp >= inputTime + inputDelay)) {
|
||||
// Unhighlight the old character
|
||||
pspDebugKbDrawKey(row, col, 0);
|
||||
|
||||
// Print the new character highlighted
|
||||
pspDebugKbDrawKey(row, --col, 1);
|
||||
|
||||
// Update inputTime
|
||||
inputTime = input.TimeStamp;
|
||||
}
|
||||
if (input.Buttons & PSP_CTRL_RIGHT
|
||||
&& ((row == PSP_DEBUG_KB_COMMAND_ROW && col < PSP_DEBUG_KB_NUM_COMMANDS - 1)
|
||||
|| (row != PSP_DEBUG_KB_COMMAND_ROW && col < PSP_DEBUG_KB_NUM_CHARS - 1
|
||||
&& charTable[row][col + 1]))
|
||||
&& (input.Buttons != lastinput.Buttons || input.TimeStamp >= inputTime + inputDelay)) {
|
||||
pspDebugKbDrawKey(row, col, 0);
|
||||
pspDebugKbDrawKey(row, ++col, 1);
|
||||
inputTime = input.TimeStamp;
|
||||
}
|
||||
if (input.Buttons & PSP_CTRL_UP && row > 0
|
||||
&& (input.Buttons != lastinput.Buttons || input.TimeStamp >= inputTime + inputDelay)) {
|
||||
if (row == PSP_DEBUG_KB_COMMAND_ROW) {
|
||||
pspDebugKbDrawKey(row, col, 0);
|
||||
if (col == PSP_DEBUG_KB_NUM_COMMANDS - 1) {
|
||||
col = PSP_DEBUG_KB_NUM_CHARS - 1;
|
||||
} else {
|
||||
col = (col * (PSP_DEBUG_KB_NUM_CHARS - 1)) / (PSP_DEBUG_KB_NUM_COMMANDS - 1);
|
||||
}
|
||||
do {
|
||||
row--;
|
||||
} while (charTable[row][col] == '\0' && row > 0);
|
||||
pspDebugKbDrawKey(row, col, 1);
|
||||
} else if (charTable[row - 1][col]) {
|
||||
pspDebugKbDrawKey(row, col, 0);
|
||||
pspDebugKbDrawKey(--row, col, 1);
|
||||
}
|
||||
inputTime = input.TimeStamp;
|
||||
}
|
||||
if (input.Buttons & PSP_CTRL_DOWN && row != PSP_DEBUG_KB_COMMAND_ROW
|
||||
&& (input.Buttons != lastinput.Buttons || input.TimeStamp >= inputTime + inputDelay)) {
|
||||
pspDebugKbDrawKey(row, col, 0);
|
||||
do {
|
||||
row++;
|
||||
} while (charTable[row][col] == '\0' &&
|
||||
row != PSP_DEBUG_KB_COMMAND_ROW);
|
||||
if (row == PSP_DEBUG_KB_COMMAND_ROW) {
|
||||
col = (col * (PSP_DEBUG_KB_NUM_COMMANDS - 1)) / (PSP_DEBUG_KB_NUM_CHARS - 1);
|
||||
}
|
||||
pspDebugKbDrawKey(row, col, 1);
|
||||
inputTime = input.TimeStamp;
|
||||
}
|
||||
|
||||
if (input.Buttons != lastinput.Buttons && input.Buttons & PSP_CTRL_SELECT) {
|
||||
pspDebugKbShift(&shifted);
|
||||
pspDebugKbDrawKey(row, col, 1);
|
||||
}
|
||||
|
||||
if (input.Buttons != lastinput.Buttons
|
||||
&& (input.Buttons & PSP_CTRL_CROSS || input.Buttons & PSP_CTRL_CIRCLE)) {
|
||||
if (row == PSP_DEBUG_KB_COMMAND_ROW) {
|
||||
switch(col) {
|
||||
case 0: // Shift
|
||||
pspDebugKbShift(&shifted);
|
||||
pspDebugKbDrawKey(row, col, 1);
|
||||
break;
|
||||
case 1: // Space
|
||||
if (strlen(str) < PSP_DEBUG_KB_MAXLEN) {
|
||||
snprintf(str, strlen(str)+2, "%s ", str);
|
||||
pspDebugKbDrawString(str);
|
||||
}
|
||||
break;
|
||||
case 2: // Back
|
||||
if (strlen(str) > 0) {
|
||||
str[strlen(str)-1] = '\0';
|
||||
pspDebugKbDrawString(str);
|
||||
}
|
||||
break;
|
||||
case 3: // Clear
|
||||
bzero(str, PSP_DEBUG_KB_MAXLEN);
|
||||
pspDebugKbDrawString(str);
|
||||
break;
|
||||
case 4:
|
||||
// Clean up the screen
|
||||
pspDebugKbClearBox();
|
||||
return;
|
||||
};
|
||||
} else {
|
||||
if (strlen(str) < PSP_DEBUG_KB_MAXLEN) {
|
||||
snprintf(str, strlen(str)+2, "%s%c", str, charTable[row][col]);
|
||||
pspDebugKbDrawString(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (input.Buttons != lastinput.Buttons
|
||||
&& (input.Buttons & PSP_CTRL_TRIANGLE || input.Buttons & PSP_CTRL_SQUARE)) {
|
||||
if (strlen(str) > 0) {
|
||||
str[strlen(str)-1] = '\0';
|
||||
pspDebugKbDrawString(str);
|
||||
}
|
||||
}
|
||||
|
||||
lastinput = input;
|
||||
}
|
||||
}
|
||||
96
src/debug/pspdebugkb.h
Normal file
96
src/debug/pspdebugkb.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* pspdebugkb.h - Simple screen debug keyboard
|
||||
*
|
||||
* Copyright (c) 2006 Mike Mallett <mike@nerdcore.net>
|
||||
*
|
||||
* $Id: pspdebugkb.h 2110 2006-12-19 14:50:27Z tyranid $
|
||||
*/
|
||||
|
||||
#ifndef __PSPDEBUGKB_H
|
||||
#define __PSPDEBUGKB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum PspDebugKbSettings {
|
||||
/** Maximum string length */
|
||||
PSP_DEBUG_KB_MAXLEN = 40,
|
||||
/** Place the box' upper-left corner at this location */
|
||||
PSP_DEBUG_KB_BOX_X = 6,
|
||||
PSP_DEBUG_KB_BOX_Y = 8,
|
||||
/** FG and BG colour of unhighlighted characters */
|
||||
PSP_DEBUG_KB_CHAR_COLOUR = 0xffffffff,
|
||||
PSP_DEBUG_KB_BACK_COLOUR = 0xff000000,
|
||||
/** FG and BG colour of highlighted character */
|
||||
PSP_DEBUG_KB_CHAR_HIGHLIGHT = 0xff00ff00,
|
||||
PSP_DEBUG_KB_BACK_HIGHLIGHT = 0xff101010,
|
||||
/** Indent the printed characters by (X_OFFSET,Y_OFFSET) */
|
||||
PSP_DEBUG_KB_OFFSET_X = 6,
|
||||
PSP_DEBUG_KB_OFFSET_Y = 4,
|
||||
/** Distance from one character to the next */
|
||||
PSP_DEBUG_KB_SPACING_X = 3,
|
||||
PSP_DEBUG_KB_SPACING_Y = 2,
|
||||
/** Number of columns/rows (respectively) in charTable(s) */
|
||||
PSP_DEBUG_KB_NUM_CHARS = 13,
|
||||
PSP_DEBUG_KB_NUM_ROWS = 4,
|
||||
/** Box width and height */
|
||||
PSP_DEBUG_KB_BOX_WIDTH = (PSP_DEBUG_KB_NUM_CHARS * PSP_DEBUG_KB_SPACING_X) + (2 * PSP_DEBUG_KB_OFFSET_X),
|
||||
PSP_DEBUG_KB_BOX_HEIGHT = ((PSP_DEBUG_KB_NUM_ROWS + 1) * PSP_DEBUG_KB_SPACING_Y) + PSP_DEBUG_KB_OFFSET_Y,
|
||||
/** Array index of commandRow */
|
||||
PSP_DEBUG_KB_COMMAND_ROW = 4,
|
||||
/** Number of commands on bottom row */
|
||||
PSP_DEBUG_KB_NUM_COMMANDS = 5
|
||||
};
|
||||
|
||||
/**
|
||||
* Switch charTable when SHIFT is pressed
|
||||
*
|
||||
* @param shiftState - Pointer to an int indicating Caps Lock
|
||||
*/
|
||||
void pspDebugKbShift(int *shiftState);
|
||||
|
||||
/**
|
||||
* Draw the specified key on the keyboard.
|
||||
*
|
||||
* @param row - The row of the character to print (in charTable)
|
||||
* @param col - The column of the character to print (in charTable)
|
||||
* @param highlight - 0 for plain; otherwise highlighted
|
||||
*/
|
||||
void pspDebugKbDrawKey(int row, int col, int highlight);
|
||||
|
||||
/**
|
||||
* Draw the string at the top of the box
|
||||
*
|
||||
* @param str - The string to print
|
||||
*/
|
||||
void pspDebugKbDrawString(char *str);
|
||||
|
||||
/**
|
||||
* Clear the area where the box resides.
|
||||
* Called from pspDebugKbDrawBox and pspDebugKbInit (on exit).
|
||||
*/
|
||||
void pspDebugKbClearBox();
|
||||
|
||||
/**
|
||||
* Draw the entire box on the desbug screen.
|
||||
* Called from shift() and doInputBox(char*)
|
||||
*/
|
||||
void pspDebugKbDrawBox();
|
||||
|
||||
/**
|
||||
* Make the text box happen
|
||||
*
|
||||
* @param str - The string to edit
|
||||
*/
|
||||
void pspDebugKbInit(char *str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
478
src/debug/scr_printf.c
Normal file
478
src/debug/scr_printf.c
Normal file
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* scr_printf.c - Debug screen functions.
|
||||
*
|
||||
* Copyright (c) 2005 Marcus R. Brown <mrbrown@ocgnet.org>
|
||||
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
||||
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
|
||||
*
|
||||
* $Id: scr_printf.c 2450 2009-01-04 23:53:02Z oopo $
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <psptypes.h>
|
||||
#include <pspkernel.h>
|
||||
#include <pspdisplay.h>
|
||||
#include <pspsysclib.h>
|
||||
#include <pspge.h>
|
||||
#include <stdarg.h>
|
||||
#include <pspdebug.h>
|
||||
#include <string.h>
|
||||
|
||||
#define PSP_SCREEN_WIDTH 480
|
||||
#define PSP_SCREEN_HEIGHT 272
|
||||
#define PSP_LINE_SIZE 512
|
||||
|
||||
/* baseado nas libs do Duke... */
|
||||
|
||||
#ifdef F_pspDebugScreenInit
|
||||
void _pspDebugScreenClearLine( int Y);
|
||||
|
||||
static int X = 0, Y = 0;
|
||||
static int MX=68, MY=34;
|
||||
static u32 bg_col = 0, fg_col = 0xFFFFFFFF;
|
||||
static int bg_enable = 1;
|
||||
static void* g_vram_base = (u32 *) 0x04000000;
|
||||
static int g_vram_offset = 0;
|
||||
static int g_vram_mode = PSP_DISPLAY_PIXEL_FORMAT_8888;
|
||||
static int init = 0;
|
||||
static int clearline_en = 1;
|
||||
|
||||
static u16 convert_8888_to_565(u32 color)
|
||||
{
|
||||
int r, g, b;
|
||||
|
||||
b = (color >> 19) & 0x1F;
|
||||
g = (color >> 10) & 0x3F;
|
||||
r = (color >> 3) & 0x1F;
|
||||
|
||||
return r | (g << 5) | (b << 11);
|
||||
}
|
||||
|
||||
static u16 convert_8888_to_5551(u32 color)
|
||||
{
|
||||
int r, g, b, a;
|
||||
|
||||
a = (color >> 24) ? 0x8000 : 0;
|
||||
b = (color >> 19) & 0x1F;
|
||||
g = (color >> 11) & 0x1F;
|
||||
r = (color >> 3) & 0x1F;
|
||||
|
||||
return a | r | (g << 5) | (b << 10);
|
||||
}
|
||||
|
||||
static u16 convert_8888_to_4444(u32 color)
|
||||
{
|
||||
int r, g, b, a;
|
||||
|
||||
a = (color >> 28) & 0xF;
|
||||
b = (color >> 20) & 0xF;
|
||||
g = (color >> 12) & 0xF;
|
||||
r = (color >> 4) & 0xF;
|
||||
|
||||
return (a << 12) | r | (g << 4) | (b << 8);
|
||||
}
|
||||
|
||||
static void clear_screen_16(u16 color)
|
||||
{
|
||||
int x;
|
||||
u16 *vram = g_vram_base;
|
||||
|
||||
vram += (g_vram_offset >> 1);
|
||||
|
||||
for(x = 0; x < (PSP_LINE_SIZE * PSP_SCREEN_HEIGHT); x++)
|
||||
{
|
||||
*vram++ = color;
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_screen_32(u32 color)
|
||||
{
|
||||
int x;
|
||||
u32 *vram = g_vram_base;
|
||||
vram += (g_vram_offset>>2);
|
||||
|
||||
for(x = 0; x < (PSP_LINE_SIZE * PSP_SCREEN_HEIGHT); x++)
|
||||
{
|
||||
*vram++ = color;
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_screen(u32 color)
|
||||
{
|
||||
if(g_vram_mode == PSP_DISPLAY_PIXEL_FORMAT_8888)
|
||||
{
|
||||
clear_screen_32(color);
|
||||
}
|
||||
else
|
||||
{
|
||||
u16 c = 0;
|
||||
switch(g_vram_mode)
|
||||
{
|
||||
case PSP_DISPLAY_PIXEL_FORMAT_565: c = convert_8888_to_565(color);
|
||||
break;
|
||||
case PSP_DISPLAY_PIXEL_FORMAT_5551: c = convert_8888_to_5551(color);
|
||||
break;
|
||||
case PSP_DISPLAY_PIXEL_FORMAT_4444: c = convert_8888_to_4444(color);
|
||||
break;
|
||||
};
|
||||
clear_screen_16(c);
|
||||
}
|
||||
}
|
||||
|
||||
void pspDebugScreenInitEx(void *vram_base, int mode, int setup)
|
||||
{
|
||||
switch(mode)
|
||||
{
|
||||
case PSP_DISPLAY_PIXEL_FORMAT_565:
|
||||
case PSP_DISPLAY_PIXEL_FORMAT_5551:
|
||||
case PSP_DISPLAY_PIXEL_FORMAT_4444:
|
||||
case PSP_DISPLAY_PIXEL_FORMAT_8888:
|
||||
break;
|
||||
default: mode = PSP_DISPLAY_PIXEL_FORMAT_8888;
|
||||
};
|
||||
|
||||
X = Y = 0;
|
||||
/* Place vram in uncached memory */
|
||||
if(vram_base == NULL)
|
||||
{
|
||||
vram_base = (void*) (0x40000000 | (u32) sceGeEdramGetAddr());
|
||||
}
|
||||
g_vram_base = vram_base;
|
||||
g_vram_offset = 0;
|
||||
g_vram_mode = mode;
|
||||
if(setup)
|
||||
{
|
||||
sceDisplaySetMode(0, PSP_SCREEN_WIDTH, PSP_SCREEN_HEIGHT);
|
||||
sceDisplaySetFrameBuf((void *) g_vram_base, PSP_LINE_SIZE, mode, 1);
|
||||
}
|
||||
clear_screen(bg_col);
|
||||
init = 1;
|
||||
}
|
||||
|
||||
void pspDebugScreenInit()
|
||||
{
|
||||
X = Y = 0;
|
||||
pspDebugScreenInitEx(NULL, PSP_DISPLAY_PIXEL_FORMAT_8888, 1);
|
||||
}
|
||||
|
||||
void pspDebugScreenEnableBackColor(int enable)
|
||||
{
|
||||
bg_enable = enable;
|
||||
}
|
||||
|
||||
void pspDebugScreenSetBackColor(u32 colour)
|
||||
{
|
||||
bg_col = colour;
|
||||
}
|
||||
|
||||
void pspDebugScreenSetTextColor(u32 colour)
|
||||
{
|
||||
fg_col = colour;
|
||||
}
|
||||
|
||||
void pspDebugScreenSetColorMode(int mode)
|
||||
{
|
||||
switch(mode)
|
||||
{
|
||||
case PSP_DISPLAY_PIXEL_FORMAT_565:
|
||||
case PSP_DISPLAY_PIXEL_FORMAT_5551:
|
||||
case PSP_DISPLAY_PIXEL_FORMAT_4444:
|
||||
case PSP_DISPLAY_PIXEL_FORMAT_8888:
|
||||
break;
|
||||
default: mode = PSP_DISPLAY_PIXEL_FORMAT_8888;
|
||||
};
|
||||
|
||||
g_vram_mode = mode;
|
||||
}
|
||||
|
||||
int pspDebugScreenGetX()
|
||||
{
|
||||
return X;
|
||||
}
|
||||
|
||||
int pspDebugScreenGetY()
|
||||
{
|
||||
return Y;
|
||||
}
|
||||
|
||||
void pspDebugScreenClear()
|
||||
{
|
||||
int y;
|
||||
|
||||
if(!init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for(y=0;y<MY;y++)
|
||||
{
|
||||
_pspDebugScreenClearLine(y);
|
||||
}
|
||||
|
||||
pspDebugScreenSetXY(0,0);
|
||||
clear_screen(bg_col);
|
||||
}
|
||||
|
||||
void pspDebugScreenSetXY(int x, int y)
|
||||
{
|
||||
if( x<MX && x>=0 ) X=x;
|
||||
if( y<MY && y>=0 ) Y=y;
|
||||
}
|
||||
|
||||
void pspDebugScreenSetOffset(int offset)
|
||||
{
|
||||
g_vram_offset = offset;
|
||||
}
|
||||
|
||||
void pspDebugScreenSetBase(u32* base)
|
||||
{
|
||||
g_vram_base = base;
|
||||
}
|
||||
|
||||
extern u8 msx[];
|
||||
|
||||
static void debug_put_char_32(int x, int y, u32 color, u32 bgc, u8 ch)
|
||||
{
|
||||
int i,j, l;
|
||||
u8 *font;
|
||||
u32 *vram_ptr;
|
||||
u32 *vram;
|
||||
|
||||
if(!init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
vram = g_vram_base;
|
||||
vram += (g_vram_offset >> 2) + x;
|
||||
vram += (y * PSP_LINE_SIZE);
|
||||
|
||||
font = &msx[ (int)ch * 8];
|
||||
for (i=l=0; i < 8; i++, l+= 8, font++)
|
||||
{
|
||||
vram_ptr = vram;
|
||||
for (j=0; j < 8; j++)
|
||||
{
|
||||
if ((*font & (128 >> j)))
|
||||
*vram_ptr = color;
|
||||
else if(bg_enable)
|
||||
*vram_ptr = bgc;
|
||||
|
||||
vram_ptr++;
|
||||
}
|
||||
vram += PSP_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void debug_put_char_16(int x, int y, u16 color, u16 bgc, u8 ch)
|
||||
{
|
||||
int i,j, l;
|
||||
u8 *font;
|
||||
u16 *vram_ptr;
|
||||
u16 *vram;
|
||||
|
||||
if(!init)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
vram = g_vram_base;
|
||||
vram += (g_vram_offset >> 1) + x;
|
||||
vram += (y * PSP_LINE_SIZE);
|
||||
|
||||
font = &msx[ (int)ch * 8];
|
||||
for (i=l=0; i < 8; i++, l+= 8, font++)
|
||||
{
|
||||
vram_ptr = vram;
|
||||
for (j=0; j < 8; j++)
|
||||
{
|
||||
if ((*font & (128 >> j)))
|
||||
*vram_ptr = color;
|
||||
else if(bg_enable)
|
||||
*vram_ptr = bgc;
|
||||
|
||||
vram_ptr++;
|
||||
}
|
||||
vram += PSP_LINE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pspDebugScreenPutChar( int x, int y, u32 color, u8 ch)
|
||||
{
|
||||
if(g_vram_mode == PSP_DISPLAY_PIXEL_FORMAT_8888)
|
||||
{
|
||||
debug_put_char_32(x, y, color, bg_col, ch);
|
||||
}
|
||||
else
|
||||
{
|
||||
u16 c = 0;
|
||||
u16 b = 0;
|
||||
switch(g_vram_mode)
|
||||
{
|
||||
case PSP_DISPLAY_PIXEL_FORMAT_565: c = convert_8888_to_565(color);
|
||||
b = convert_8888_to_565(bg_col);
|
||||
break;
|
||||
case PSP_DISPLAY_PIXEL_FORMAT_5551: c = convert_8888_to_5551(color);
|
||||
b = convert_8888_to_5551(bg_col);
|
||||
break;
|
||||
case PSP_DISPLAY_PIXEL_FORMAT_4444: c = convert_8888_to_4444(color);
|
||||
b = convert_8888_to_4444(bg_col);
|
||||
break;
|
||||
};
|
||||
debug_put_char_16(x, y, c, b, ch);
|
||||
}
|
||||
}
|
||||
|
||||
void _pspDebugScreenClearLine( int Y)
|
||||
{
|
||||
if(clearline_en)
|
||||
{
|
||||
int i;
|
||||
if(bg_enable)
|
||||
{
|
||||
for (i=0; i < MX; i++)
|
||||
{
|
||||
pspDebugScreenPutChar( i*7 , Y * 8, bg_col, 219);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void pspDebugScreenClearLineEnable(void)
|
||||
{
|
||||
clearline_en = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
void pspDebugScreenClearLineDisable(void)
|
||||
{
|
||||
clearline_en = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Print non-nul terminated strings */
|
||||
int pspDebugScreenPrintData(const char *buff, int size)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
char c;
|
||||
|
||||
if(!init)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
c = buff[i];
|
||||
switch (c)
|
||||
{
|
||||
case '\r':
|
||||
X = 0;
|
||||
break;
|
||||
case '\n':
|
||||
X = 0;
|
||||
Y ++;
|
||||
if (Y == MY)
|
||||
Y = 0;
|
||||
_pspDebugScreenClearLine(Y);
|
||||
break;
|
||||
case '\t':
|
||||
for (j = 0; j < 5; j++) {
|
||||
pspDebugScreenPutChar( X*7 , Y * 8, fg_col, ' ');
|
||||
X++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pspDebugScreenPutChar( X*7 , Y * 8, fg_col, c);
|
||||
X++;
|
||||
if (X == MX)
|
||||
{
|
||||
X = 0;
|
||||
Y++;
|
||||
if (Y == MY)
|
||||
Y = 0;
|
||||
_pspDebugScreenClearLine(Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int pspDebugScreenPuts(const char *str)
|
||||
{
|
||||
return pspDebugScreenPrintData(str, strlen(str));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pspDebugScreenPrintf
|
||||
void pspDebugScreenPrintf(const char *format, ...)
|
||||
{
|
||||
va_list opt;
|
||||
char buff[2048];
|
||||
int bufsz;
|
||||
|
||||
va_start(opt, format);
|
||||
bufsz = vsnprintf( buff, (size_t) sizeof(buff), format, opt);
|
||||
(void) pspDebugScreenPrintData(buff, bufsz);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Kernel screen printf, uses the prnt function instead of vsnprintf */
|
||||
#ifdef F_pspDebugScreenKprintf
|
||||
|
||||
#define MAX_CLI 4096
|
||||
#define CTX_BUF_SIZE 128
|
||||
|
||||
struct prnt_ctx
|
||||
{
|
||||
unsigned short len;
|
||||
char buf[CTX_BUF_SIZE];
|
||||
};
|
||||
|
||||
static void cb(struct prnt_ctx *ctx, int type)
|
||||
{
|
||||
if(type == 0x200)
|
||||
{
|
||||
ctx->len = 0;
|
||||
}
|
||||
else if(type == 0x201)
|
||||
{
|
||||
pspDebugScreenPrintData(ctx->buf, ctx->len);
|
||||
ctx->len = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(type != '\r')
|
||||
{
|
||||
ctx->buf[ctx->len++] = type;
|
||||
if(ctx->len == CTX_BUF_SIZE)
|
||||
{
|
||||
pspDebugScreenPrintData(ctx->buf, ctx->len);
|
||||
ctx->len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pspDebugScreenKprintf(const char *format, ...)
|
||||
{
|
||||
struct prnt_ctx ctx;
|
||||
va_list opt;
|
||||
|
||||
ctx.len = 0;
|
||||
|
||||
va_start(opt, format);
|
||||
|
||||
prnt((prnt_callback) cb, (void*) &ctx, format, opt);
|
||||
|
||||
va_end(opt);
|
||||
}
|
||||
#endif
|
||||
|
||||
178
src/debug/sio.c
Normal file
178
src/debug/sio.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* sio.c - Some basic SIO (remote port) functions.
|
||||
*
|
||||
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
||||
*
|
||||
* $Id: sio.c 2152 2007-01-27 10:09:15Z tyranid $
|
||||
*/
|
||||
|
||||
#include <pspkernel.h>
|
||||
#include <pspdebug.h>
|
||||
#include <pspsyscon.h>
|
||||
|
||||
/* Define some important parameters, not really sure on names. Probably doesn't matter */
|
||||
#define PSP_UART4_FIFO 0xBE500000
|
||||
#define PSP_UART4_STAT 0xBE500018
|
||||
#define PSP_UART4_DIV1 0xBE500024
|
||||
#define PSP_UART4_DIV2 0xBE500028
|
||||
#define PSP_UART4_CTRL 0xBE50002C
|
||||
#define PSP_UART_CLK 96000000
|
||||
#define PSP_UART_TXFULL 0x20
|
||||
#define PSP_UART_RXEMPTY 0x10
|
||||
|
||||
static int g_enablekprintf = 0;
|
||||
|
||||
/* Some function prototypes we will need */
|
||||
int sceHprmEnd(void);
|
||||
int sceSysregUartIoEnable(int uart);
|
||||
extern u32 sceKernelRemoveByDebugSection;
|
||||
|
||||
void pspDebugSioPutchar(int ch)
|
||||
{
|
||||
while(_lw(PSP_UART4_STAT) & PSP_UART_TXFULL);
|
||||
_sw(ch, PSP_UART4_FIFO);
|
||||
}
|
||||
|
||||
int pspDebugSioGetchar(void)
|
||||
{
|
||||
if(_lw(PSP_UART4_STAT) & PSP_UART_RXEMPTY)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _lw(PSP_UART4_FIFO);
|
||||
}
|
||||
|
||||
void pspDebugSioPuts(const char *str)
|
||||
{
|
||||
while(*str)
|
||||
{
|
||||
pspDebugSioPutchar(*str);
|
||||
str++;
|
||||
}
|
||||
|
||||
pspDebugSioPutchar('\r');
|
||||
pspDebugSioPutchar('\n');
|
||||
}
|
||||
|
||||
int pspDebugSioPutData(const char *data, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
pspDebugSioPutchar(data[i]);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Put data to SIO converting any line feeds as necessary */
|
||||
int pspDebugSioPutText(const char *data, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
/* If just line feed add a carriage return */
|
||||
if(data[i] == '\n')
|
||||
{
|
||||
if(((i > 0) && (data[i-1] != '\r')) || (i == 0))
|
||||
{
|
||||
pspDebugSioPutchar('\r');
|
||||
}
|
||||
}
|
||||
|
||||
pspDebugSioPutchar(data[i]);
|
||||
|
||||
if((i < (len - 1)) && (data[i] == '\r') && (data[i+1] != '\n'))
|
||||
{
|
||||
pspDebugSioPutchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void pspDebugSioSetBaud(int baud)
|
||||
{
|
||||
int div1, div2;
|
||||
|
||||
/* rate set using the rough formula div1 = (PSP_UART_CLK / baud) >> 6 and
|
||||
* div2 = (PSP_UART_CLK / baud) & 0x3F
|
||||
* The uart4 driver actually uses a slightly different formula for div 2 (it
|
||||
* adds 32 before doing the AND, but it doesn't seem to make a difference
|
||||
*/
|
||||
div1 = PSP_UART_CLK / baud;
|
||||
div2 = div1 & 0x3F;
|
||||
div1 >>= 6;
|
||||
|
||||
_sw(div1, PSP_UART4_DIV1);
|
||||
_sw(div2, PSP_UART4_DIV2);
|
||||
_sw(0x60, PSP_UART4_CTRL);
|
||||
}
|
||||
|
||||
void pspDebugSioInit(void)
|
||||
{
|
||||
/* Shut down the remote driver */
|
||||
sceHprmEnd();
|
||||
/* Enable UART 4 */
|
||||
sceSysregUartIoEnable(4);
|
||||
/* Enable remote control power */
|
||||
sceSysconCtrlHRPower(1);
|
||||
/* Delay thread for a but */
|
||||
sceKernelDelayThread(2000000);
|
||||
}
|
||||
|
||||
static u32 *get_debug_register(void)
|
||||
{
|
||||
u32 *pData;
|
||||
u32 ptr;
|
||||
|
||||
pData = (u32 *) (0x80000000 | ((sceKernelRemoveByDebugSection & 0x03FFFFFF) << 2));
|
||||
ptr = ((pData[0] & 0xFFFF) << 16) + (short) (pData[2] & 0xFFFF);
|
||||
|
||||
return (u32 *) ptr;
|
||||
}
|
||||
|
||||
void pspDebugEnablePutchar(void)
|
||||
{
|
||||
u32 *pData;
|
||||
|
||||
pData = get_debug_register();
|
||||
*pData |= 0x1000;
|
||||
}
|
||||
|
||||
static void PutCharDebug(unsigned short *data, unsigned int type)
|
||||
{
|
||||
if(((type & 0xFF00) == 0) && (g_enablekprintf))
|
||||
{
|
||||
if(type == '\n')
|
||||
{
|
||||
pspDebugSioPutchar('\r');
|
||||
}
|
||||
|
||||
pspDebugSioPutchar(type);
|
||||
}
|
||||
}
|
||||
|
||||
void pspDebugSioInstallKprintf(void)
|
||||
{
|
||||
pspDebugEnablePutchar();
|
||||
sceKernelRegisterDebugPutchar(PutCharDebug);
|
||||
g_enablekprintf = 1;
|
||||
}
|
||||
|
||||
void pspDebugSioEnableKprintf(void)
|
||||
{
|
||||
g_enablekprintf = 1;
|
||||
}
|
||||
|
||||
void pspDebugSioDisableKprintf(void)
|
||||
{
|
||||
g_enablekprintf = 0;
|
||||
}
|
||||
111
src/debug/stacktrace.c
Normal file
111
src/debug/stacktrace.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* callstack.c - Return stack generation for MIPS processors.
|
||||
*
|
||||
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
||||
*
|
||||
* $Id: stacktrace.c 1095 2005-09-27 21:02:16Z jim $
|
||||
*/
|
||||
|
||||
#include <pspkernel.h>
|
||||
#include <pspdebug.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CALL 0x0C000000
|
||||
#define CALL_MASK 0xFC000000
|
||||
#define IS_CALL(x) (((x) & CALL_MASK) == CALL)
|
||||
#define CALL_ADDR(x) (((x) & ~CALL_MASK) << 2)
|
||||
|
||||
extern u32 _ftext;
|
||||
extern u32 _etext;
|
||||
|
||||
/* Ideally should be something which is automatic */
|
||||
#define ELF_START (&_ftext)
|
||||
#define ELF_END (&_etext)
|
||||
|
||||
/* This is a blatently wrong way of doing a stack trace, but I felt as long as you use some intelligence you
|
||||
could easily work out if some calls in the trace were invalid :P */
|
||||
static int _pspDebugDoStackTrace(u32 *sp, u32 *sp_end, u32 *ra, PspDebugStackTrace *trace, int max)
|
||||
{
|
||||
int count = 0;
|
||||
int recurse = 0;
|
||||
|
||||
if((ra >= (ELF_START + 2)) && (ra < ELF_END) && (IS_CALL(ra[-2])))
|
||||
{
|
||||
trace[count].func_addr = CALL_ADDR(ra[-2]);
|
||||
trace[count].call_addr = (u32) (&ra[-2]);
|
||||
count++;
|
||||
}
|
||||
|
||||
while((count < max) && (sp < sp_end))
|
||||
{
|
||||
u32 *addr;
|
||||
/* Try and find all the pointers on the stack, then see if they are within range
|
||||
and point to a valid return address. There is possible false positives with this
|
||||
but tbh it is better than nothing */
|
||||
addr = (u32*) *sp;
|
||||
|
||||
/* Check that the address could possibly be a valid ra address */
|
||||
if((addr >= (ELF_START + 2)) && (addr < ELF_END))
|
||||
{
|
||||
if(IS_CALL(addr[-2]))
|
||||
{
|
||||
if((count == 1) && (addr == ra) && (!recurse))
|
||||
{
|
||||
/* Set recurse to 1 so any further calls from ra will be caught */
|
||||
/* This is not ideal, but it is to try and prevent the more likely case
|
||||
of the first ra being found on the stack when first parsing */
|
||||
recurse = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
trace[count].func_addr = CALL_ADDR(addr[-2]);
|
||||
trace[count].call_addr = (u32) (&addr[-2]);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sp++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int pspDebugGetStackTrace2(PspDebugRegBlock *regs, PspDebugStackTrace *trace, int max)
|
||||
{
|
||||
u32 *curr_sp;
|
||||
u32 *sp_end;
|
||||
u32 *curr_ra;
|
||||
int curr_thid;
|
||||
int count = 0;
|
||||
SceKernelThreadInfo th_stat;
|
||||
|
||||
/* This is a real simple (and dirty way) of getting a stack trace, none of this code following shitz */
|
||||
/* Relies on the system not being totally vaporised on an exception */
|
||||
|
||||
if((trace == NULL) || (max < 1))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
curr_thid = sceKernelGetThreadId();
|
||||
if(curr_thid >= 0)
|
||||
{
|
||||
memset(&th_stat, 0, sizeof(th_stat));
|
||||
th_stat.size = sizeof(th_stat);
|
||||
if(sceKernelReferThreadStatus(curr_thid, &th_stat) >= 0)
|
||||
{
|
||||
sp_end = (u32*) ((u8*) th_stat.stack + th_stat.stackSize);
|
||||
curr_sp = (u32*) (regs->r[29] & ~3);
|
||||
curr_ra = (u32*) (regs->r[31]);
|
||||
|
||||
count = _pspDebugDoStackTrace(curr_sp, sp_end, curr_ra, trace, max);
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
291
src/debug/stdio.c
Normal file
291
src/debug/stdio.c
Normal file
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* PSP Software Development Kit - http://www.pspdev.org
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* stdio.c - Debug functions to enable stdout and stderr handlers
|
||||
*
|
||||
* Copyright (c) 2005 Marcus R. Brown <mrbrown@ocgnet.org>
|
||||
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
||||
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
|
||||
*
|
||||
* $Id: stdio.c 1925 2006-05-29 14:22:53Z tyranid $
|
||||
*/
|
||||
#include <pspkernel.h>
|
||||
#include <pspdebug.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define dbgprintf pspDebugScreenPrintf
|
||||
|
||||
static int g_initialised = 0;
|
||||
static PspDebugInputHandler g_stdin_handler = NULL;
|
||||
static PspDebugPrintHandler g_stdout_handler = NULL;
|
||||
static PspDebugPrintHandler g_stderr_handler = NULL;
|
||||
static SceUID g_in_sema = 0;
|
||||
/* Probably stdout and stderr should not be guarded by the same mutex */
|
||||
static SceUID g_out_sema = 0;
|
||||
|
||||
static int io_init(PspIoDrvArg *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_exit(PspIoDrvArg *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_open(PspIoDrvFileArg *arg, char *file, int mode, SceMode mask)
|
||||
{
|
||||
if((arg->fs_num != STDIN_FILENO) && (arg->fs_num != STDOUT_FILENO) && (arg->fs_num != STDERR_FILENO))
|
||||
{
|
||||
return SCE_KERNEL_ERROR_NOFILE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_close(PspIoDrvFileArg *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_read(PspIoDrvFileArg *arg, char *data, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
(void) sceKernelWaitSema(g_in_sema, 1, 0);
|
||||
if((arg->fs_num == STDIN_FILENO) && (g_stdin_handler != NULL))
|
||||
{
|
||||
ret = g_stdin_handler(data, len);
|
||||
}
|
||||
(void) sceKernelSignalSema(g_in_sema, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int io_write(PspIoDrvFileArg *arg, const char *data, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
(void) sceKernelWaitSema(g_out_sema, 1, 0);
|
||||
if((arg->fs_num == STDOUT_FILENO) && (g_stdout_handler != NULL))
|
||||
{
|
||||
ret = g_stdout_handler(data, len);
|
||||
}
|
||||
else if((arg->fs_num == STDERR_FILENO) && (g_stderr_handler != NULL))
|
||||
{
|
||||
ret = g_stderr_handler(data, len);
|
||||
}
|
||||
(void) sceKernelSignalSema(g_out_sema, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static SceOff io_lseek(PspIoDrvFileArg *arg, SceOff ofs, int whence)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_ioctl(PspIoDrvFileArg *arg, unsigned int cmd, void *indata, int inlen, void *outdata, int outlen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_remove(PspIoDrvFileArg *arg, const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_mkdir(PspIoDrvFileArg *arg, const char *name, SceMode mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_rmdir(PspIoDrvFileArg *arg, const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_dopen(PspIoDrvFileArg *arg, const char *dir)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_dclose(PspIoDrvFileArg *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_dread(PspIoDrvFileArg *arg, SceIoDirent *dir)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_getstat(PspIoDrvFileArg *arg, const char *file, SceIoStat *stat)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_chstat(PspIoDrvFileArg *arg, const char *file, SceIoStat *stat, int bits)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_rename(PspIoDrvFileArg *arg, const char *oldname, const char *newname)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_chdir(PspIoDrvFileArg *arg, const char *dir)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_mount(PspIoDrvFileArg *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_umount(PspIoDrvFileArg *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_devctl(PspIoDrvFileArg *arg, const char *devname, unsigned int cmd, void *indata, int inlen, void *outdata, int outlen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_unknown(PspIoDrvFileArg *arg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PspIoDrvFuncs tty_funcs =
|
||||
{
|
||||
io_init,
|
||||
io_exit,
|
||||
io_open,
|
||||
io_close,
|
||||
io_read,
|
||||
io_write,
|
||||
io_lseek,
|
||||
io_ioctl,
|
||||
io_remove,
|
||||
io_mkdir,
|
||||
io_rmdir,
|
||||
io_dopen,
|
||||
io_dclose,
|
||||
io_dread,
|
||||
io_getstat,
|
||||
io_chstat,
|
||||
io_rename,
|
||||
io_chdir,
|
||||
io_mount,
|
||||
io_umount,
|
||||
io_devctl,
|
||||
io_unknown,
|
||||
};
|
||||
|
||||
static PspIoDrv tty_driver =
|
||||
{
|
||||
"tty", 0x10, 0x800, "TTY", &tty_funcs
|
||||
};
|
||||
|
||||
static int tty_init(void)
|
||||
{
|
||||
int ret;
|
||||
(void) sceIoDelDrv("tty"); /* Ignore error */
|
||||
ret = sceIoAddDrv(&tty_driver);
|
||||
if(ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
g_in_sema = sceKernelCreateSema("TtyInMutex", 0, 1, 1, NULL);
|
||||
if(g_in_sema < 0)
|
||||
{
|
||||
return g_in_sema;
|
||||
}
|
||||
|
||||
g_out_sema = sceKernelCreateSema("TtyOutMutex", 0, 1, 1, NULL);
|
||||
if(g_out_sema < 0)
|
||||
{
|
||||
return g_out_sema;
|
||||
}
|
||||
|
||||
ret = sceIoReopen("tty0:", PSP_O_RDONLY, 0777, sceKernelStdin());
|
||||
if(ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sceKernelStdoutReopen("tty1:", PSP_O_WRONLY, 0777);
|
||||
if(ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sceKernelStderrReopen("tty2:", PSP_O_WRONLY, 0777);
|
||||
if(ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
g_initialised = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pspDebugInstallStdinHandler(PspDebugInputHandler handler)
|
||||
{
|
||||
if(g_initialised == 0)
|
||||
{
|
||||
int ret;
|
||||
ret = tty_init();
|
||||
if(ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
g_stdin_handler = handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pspDebugInstallStdoutHandler(PspDebugPrintHandler handler)
|
||||
{
|
||||
if(g_initialised == 0)
|
||||
{
|
||||
int ret;
|
||||
ret = tty_init();
|
||||
if(ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
g_stdout_handler = handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pspDebugInstallStderrHandler(PspDebugPrintHandler handler)
|
||||
{
|
||||
if(g_initialised == 0)
|
||||
{
|
||||
int ret;
|
||||
ret = tty_init();
|
||||
if(ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
g_stderr_handler = handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user