aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorspicyjpeg <thatspicyjpeg@gmail.com>2022-10-13 23:21:32 +0200
committerspicyjpeg <thatspicyjpeg@gmail.com>2022-10-13 23:21:32 +0200
commitb458ea70700739bf8a64217af369c7ace08fc954 (patch)
tree77281ebd18e5049fcb1c86718854ff3ce91e54c2
parent8e92156bc6a977651771d2cf91ac5800a0e9a913 (diff)
downloadpsn00bsdk-b458ea70700739bf8a64217af369c7ace08fc954.tar.gz
Fix dropped IRQs, clean up psxcd and psxetc logging
-rw-r--r--doc/known_bugs.md7
-rw-r--r--examples/system/childexec/CMakeLists.txt18
-rw-r--r--examples/system/childexec/child/child.c8
-rw-r--r--examples/system/childexec/parent.c27
-rw-r--r--libpsn00b/psxcd/isofs.c20
-rw-r--r--libpsn00b/psxcd/psxcd.c9
-rw-r--r--libpsn00b/psxetc/dl.c98
-rw-r--r--libpsn00b/psxetc/interrupts.c50
8 files changed, 107 insertions, 130 deletions
diff --git a/doc/known_bugs.md b/doc/known_bugs.md
index 9e4785c..620a805 100644
--- a/doc/known_bugs.md
+++ b/doc/known_bugs.md
@@ -37,11 +37,6 @@ fixed.
due to the SPU status register being emulated incorrectly. They work as
expected on other emulators as well as on real hardware.
-`psxcd`:
-
-- Custom callbacks registered using `CdReadyCallback()` seem to be unstable on
- DuckStation (and possibly on real hardware), occasionally dropping sectors.
-
`psxetc`:
- `DL_LoadSymbolMapFromFile()`, `DL_LoadDLLFromFile()` and `dlopen()` have been
@@ -54,4 +49,4 @@ fixed.
See [README.md in the examples directory](../examples/README.md#examples-summary).
-----------------------------------------
-_Last updated on 2022-10-11 by spicyjpeg_
+_Last updated on 2022-10-13 by spicyjpeg_
diff --git a/examples/system/childexec/CMakeLists.txt b/examples/system/childexec/CMakeLists.txt
index 0c25ca4..e542d2a 100644
--- a/examples/system/childexec/CMakeLists.txt
+++ b/examples/system/childexec/CMakeLists.txt
@@ -13,14 +13,14 @@ project(
file(GLOB _sources *.c)
file(GLOB _child_sources child/*.c)
-psn00bsdk_add_executable(parent GPREL ${_sources})
-psn00bsdk_add_executable(child GPREL ${_child_sources})
-#psn00bsdk_add_cd_image(childexec_iso childexec iso.xml DEPENDS parent)
+psn00bsdk_add_executable(childexec GPREL ${_sources})
+psn00bsdk_add_executable(childexec_child GPREL ${_child_sources})
+#psn00bsdk_add_cd_image(childexec_iso childexec iso.xml DEPENDS childexec)
-psn00bsdk_target_incbin(parent PRIVATE ball16c ball16c.tim)
+psn00bsdk_target_incbin(childexec PRIVATE ball16c ball16c.tim)
psn00bsdk_target_incbin(
- parent PRIVATE child_exe
- ${PROJECT_BINARY_DIR}/child.exe
+ childexec PRIVATE child_exe
+ ${PROJECT_BINARY_DIR}/childexec_child.exe
)
# Relocate the child executable to a non-default address to prevent it from
@@ -28,9 +28,9 @@ psn00bsdk_target_incbin(
# NOTE: child executables are not position-independent and can't be relocated
# at runtime. If you need your code to be relocatable (e.g. to load it into a
# dynamically-allocated buffer), consider using a DLL instead.
-target_link_options(child PRIVATE -Ttext=0x80030000)
+target_link_options(childexec_child PRIVATE -Ttext=0x80030000)
# Make sure the child executable is built before the parent.
-add_dependencies(parent child)
+add_dependencies(childexec childexec_child)
-install(FILES ${PROJECT_BINARY_DIR}/parent.exe TYPE BIN)
+install(FILES ${PROJECT_BINARY_DIR}/childexec.exe TYPE BIN)
diff --git a/examples/system/childexec/child/child.c b/examples/system/childexec/child/child.c
index bd17440..dcfbfaf 100644
--- a/examples/system/childexec/child/child.c
+++ b/examples/system/childexec/child/child.c
@@ -98,8 +98,8 @@ MATRIX light_mtx = {
char pad_buff[2][34];
/* Function declarations */
-void init();
-void display();
+void init(void);
+void display(void);
/* Main function */
@@ -245,7 +245,7 @@ int main(int argc, const char *argv[]) {
}
-void init() {
+void init(void) {
/* Reset the GPU, also installs a VSync event handler */
ResetGraph( 0 );
@@ -300,7 +300,7 @@ void init() {
}
-void display() {
+void display(void) {
/* Wait for GPU to finish drawing and vertical retrace */
DrawSync( 0 );
diff --git a/examples/system/childexec/parent.c b/examples/system/childexec/parent.c
index 3e7d218..83d964c 100644
--- a/examples/system/childexec/parent.c
+++ b/examples/system/childexec/parent.c
@@ -67,12 +67,12 @@ extern const uint32_t ball16c[];
TIM_IMAGE tim;
-void run_child();
+void run_child(void);
char pad_buff[2][34];
-void init() {
+void init(void) {
int i;
@@ -270,10 +270,7 @@ typedef struct {
// Child program address
extern char child_exe[];
-// Manually defined as its not defined in psxapi by default
-void SetDefaultExitFromException();
-
-void run_child() {
+void run_child(void) {
// Arguments for the child program
char *args[] =
@@ -289,29 +286,23 @@ void run_child() {
// Copy child executable to its intended adddress
memcpy((void*)exe->param.t_addr, child_exe+2048, exe->param.t_size);
- // Enter critical section to prepare for program execution
- EnterCriticalSection();
+ // Prepare for program execution and disable interrupts
+ //EnterCriticalSection();
+ StopCallback();
// Stop pads, enable auto acknowledge
StopPAD();
ChangeClearPAD(1);
ChangeClearRCnt(3, 1);
-
- // Set default exception handler just in case
- //SetDefaultExitFromException();
-
- // Last three function calls could be relegated to
- // a StopCallback() function in the future.
-
+
// Execute child
printf("Child exec!\n");
Exec(&exe->param, 3, args);
// Restore interrupts for this PS-EXE
- EnterCriticalSection();
RestartCallback();
- ExitCriticalSection();
-
+ //ExitCriticalSection();
+
// Re-init and re-enable pads
InitPAD(pad_buff[0], 34, pad_buff[1], 34);
StartPAD();
diff --git a/libpsn00b/psxcd/isofs.c b/libpsn00b/psxcd/isofs.c
index fb1f6c9..16e64ef 100644
--- a/libpsn00b/psxcd/isofs.c
+++ b/libpsn00b/psxcd/isofs.c
@@ -148,7 +148,7 @@ static int _CdReadIsoDirectory(int lba)
CdIntToPos(lba, &loc);
i = CdPosToInt(&loc);
- _LOG("psxcd_dbg: Seek to sector %d\n", i);
+ _LOG("psxcd: Seek to sector %d\n", i);
if( !CdControl(CdlSetloc, (uint8_t*)&loc, 0) )
{
@@ -232,7 +232,7 @@ static void dump_directory(void)
strncpy(namebuff,
_cd_iso_directory_buff+dir_pos+sizeof(ISO_DIR_ENTRY), dir_entry->identifierLen);
- _LOG("P:%d L:%d %s\n", dir_pos, dir_entry->identifierLen, namebuff);
+ _LOG("psxcd: P:%d L:%d %s\n", dir_pos, dir_entry->identifierLen, namebuff);
dir_pos += dir_entry->entryLength;
i++;
@@ -251,7 +251,7 @@ static void dump_directory(void)
}
}
- _LOG("--\n");
+ _LOG("psxcd: --\n");
}
@@ -534,7 +534,7 @@ CdlFILE *CdSearchFile(CdlFILE *fp, const char *filename)
}
#ifndef NDEBUG
- dump_directory();
+ //dump_directory();
#endif
if( find_dir_entry(fp->name, &dir_entry) )
@@ -582,7 +582,7 @@ CdlDIR *CdOpenDir(const char* path)
for( i=1; i<num_dirs; i++ )
{
rbuff = resolve_pathtable_path( i, tpath_rbuff+127 );
- _LOG( "psxcd_dbg: Found = %s|\n", rbuff );
+ _LOG( "psxcd: Found = %s|\n", rbuff );
if( rbuff )
{
@@ -596,14 +596,14 @@ CdlDIR *CdOpenDir(const char* path)
if( !found_dir )
{
- _LOG( "psxcd_dbg: Directory path not found.\n" );
+ _LOG( "psxcd: Directory path not found.\n" );
return NULL;
}
- _LOG( "psxcd_dbg: Found directory at record %d!\n", found_dir );
+ _LOG( "psxcd: Found directory at record %d!\n", found_dir );
get_pathtable_entry( found_dir, &tbl_entry, NULL );
- _LOG( "psxcd_dbg: Directory LBA = %d\n", tbl_entry.dirOffs );
+ _LOG( "psxcd: Directory LBA = %d\n", tbl_entry.dirOffs );
_CdReadIsoDirectory( tbl_entry.dirOffs );
@@ -668,11 +668,11 @@ int CdReadDir(CdlDIR *dir, CdlFILE* file)
file->size = dir_entry->entrySize.lsb;
- _LOG("dir_entry->entryLength = %d, ", dir_entry->entryLength);
+ _LOG("psxcd: dir_entry->entryLength = %d, ", dir_entry->entryLength);
d_dir->_pos += dir_entry->entryLength;
- _LOG("d_dir->_pos = %d\n", d_dir->_pos);
+ _LOG("psxcd: d_dir->_pos = %d\n", d_dir->_pos);
// Check if padding is reached (end of record sector)
if( d_dir->_dir[d_dir->_pos] == 0 )
diff --git a/libpsn00b/psxcd/psxcd.c b/libpsn00b/psxcd/psxcd.c
index 65dea48..160a1ed 100644
--- a/libpsn00b/psxcd/psxcd.c
+++ b/libpsn00b/psxcd/psxcd.c
@@ -46,7 +46,7 @@ int CdInit(void) {
CdControl(CdlDemute, 0, 0);
_LOG("psxcd: setup done\n");
} else {
- _LOG("psxcd: initialization error, bad disc/drive or no disc inserted\n");
+ _LOG("psxcd: setup error, bad disc/drive or no disc inserted\n");
}
return 1;
@@ -106,14 +106,8 @@ int CdControlF(unsigned char com, const void *param)
param_len = 2;
break;
case CdlSetmode:
- param_len = 1;
- break;
case CdlSetsession:
- param_len = 1;
- break;
case CdlTest:
- param_len = 1;
- break;
case CdlGetTD:
param_len = 1;
break;
@@ -126,6 +120,7 @@ int CdControlF(unsigned char com, const void *param)
_cd_control(CdlSetloc, param, 3);
_cd_last_setloc = *((CdlLOC*)param);
}
+ break;
}
// Issue CD command
diff --git a/libpsn00b/psxetc/dl.c b/libpsn00b/psxetc/dl.c
index 3d8f3ab..cf4e466 100644
--- a/libpsn00b/psxetc/dl.c
+++ b/libpsn00b/psxetc/dl.c
@@ -34,9 +34,6 @@
/* Compile options */
-// Uncomment before building to enable debug logging (via printf()).
-//#define DEBUG
-
// Comment before building to disable functions that rely on BIOS file APIs,
// i.e. DL_LoadSymbolMapFromFile() and DL_LoadDLLFromFile().
// FIXME: those seem to be broken currently, and shouldn't be used anyway
@@ -95,7 +92,7 @@ void *_dl_resolve_helper(DLL *dll, uint32_t index) {
address = DL_GetSymbolByName(_name);
if (!address) {
- _LOG("psxetc: FATAL! Can't resolve %s, locking up\n", _name);
+ _LOG("psxetc: FATAL! can't resolve %s, locking up\n", _name);
while (1)
__asm__ volatile("nop");
}
@@ -136,7 +133,7 @@ static uint32_t _elf_hash(const char *str) {
static uint8_t *_dl_load_file(const char *filename, size_t *size_output) {
int32_t fd = open(filename, 1);
if (fd < 0) {
- _LOG("psxetc: Can't open %s, error = %d\n", filename, fd);
+ _LOG("psxetc: can't open %s, error = %d\n", filename, fd);
_ERROR(RTLD_E_FILE_OPEN, 0);
}
@@ -147,11 +144,11 @@ static uint8_t *_dl_load_file(const char *filename, size_t *size_output) {
uint8_t *buffer = malloc(size);
if (!buffer) {
- _LOG("psxetc: Unable to allocate %d bytes for %s\n", size, filename);
+ _LOG("psxetc: unable to allocate %d bytes for %s\n", size, filename);
_ERROR(RTLD_E_FILE_ALLOC, 0);
}
- _LOG("psxetc: Loading %s (%d bytes)..", filename, size);
+ //_LOG("psxetc: loading %s (%d bytes)..", filename, size);
for (uint32_t offset = 0; offset < size; ) {
int32_t length = read(fd, &(buffer[offset]), 0x800);
@@ -164,7 +161,7 @@ static uint8_t *_dl_load_file(const char *filename, size_t *size_output) {
_ERROR(RTLD_E_FILE_READ, 0);
}
- _LOG(".");
+ //_LOG(".");
offset += length;
}
@@ -196,7 +193,7 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) {
_symbol_map.nbucket = entries;
_symbol_map.nchain = entries;
_LOG(
- "psxetc: Allocating nbucket = %d, nchain = %d\n",
+ "psxetc: allocating nbucket = %d, nchain = %d\n",
_symbol_map.nbucket,
entries
);
@@ -208,7 +205,7 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) {
_symbol_map.chain = malloc(sizeof(uint32_t) * entries);
if (!_symbol_map.entries || !_symbol_map.bucket || !_symbol_map.chain) {
- _LOG("psxetc: Unable to allocate symbol map table\n");
+ _LOG("psxetc: unable to allocate symbol map table\n");
_ERROR(RTLD_E_MAP_ALLOC, -1);
}
@@ -251,13 +248,10 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) {
(_type == 'D') || // .data
(_type == 'B') // .bss
)) {
- _LOG(
- "psxetc: Map sym: %08x,%08x [%c %s]\n",
- address,
- _size,
- _type,
- name
- );
+ //_LOG(
+ //"psxetc: map sym: %08x,%08x [%c %s]\n",
+ //address, _size, _type, name
+ //);
MapEntry *entry = &(_symbol_map.entries[index]);
entry->hash = hash;
@@ -280,7 +274,7 @@ int32_t DL_ParseSymbolMap(const char *ptr, size_t size) {
pos++;
}
- _LOG("psxetc: Parsed %d symbols\n", entries);
+ _LOG("psxetc: parsed %d symbols\n", entries);
if (!entries)
_ERROR(RTLD_E_NO_SYMBOLS, -1);
@@ -313,7 +307,7 @@ void DL_UnloadSymbolMap(void) {
void *DL_GetSymbolByName(const char *name) {
if (!_symbol_map.entries) {
- _LOG("psxetc: Attempted lookup with no map loaded\n");
+ _LOG("psxetc: attempted lookup with no map loaded\n");
_ERROR(RTLD_E_NO_MAP, 0);
}
@@ -326,9 +320,8 @@ void *DL_GetSymbolByName(const char *name) {
for (uint32_t i = _symbol_map.bucket[hash_mod]; i != 0xffffffff;) {
if (i >= _symbol_map.nchain) {
_LOG(
- "psxetc: GetSymbolByName() index out of bounds (i = %d, n = %d)\n",
- i,
- _symbol_map.nchain
+ "psxetc: GetSymbolByName() index out of bounds (%d >= %d)\n",
+ i, _symbol_map.nchain
);
_ERROR(RTLD_E_HASH_LOOKUP, 0);
}
@@ -336,14 +329,14 @@ void *DL_GetSymbolByName(const char *name) {
MapEntry *entry = &(_symbol_map.entries[i]);
if (hash == entry->hash) {
- _LOG("psxetc: Map lookup [%s = %08x]\n", name, entry->ptr);
+ //_LOG("psxetc: map lookup [%s = %08x]\n", name, entry->ptr);
return entry->ptr;
}
i = _symbol_map.chain[i];
}
- _LOG("psxetc: Map lookup [%s not found]\n", name);
+ _LOG("psxetc: map lookup [%s not found]\n", name);
_ERROR(RTLD_E_MAP_SYMBOL, 0);
}
@@ -359,14 +352,14 @@ DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode) {
DLL *dll = malloc(sizeof(DLL));
if (!dll) {
- _LOG("psxetc: Unable to allocate DLL struct\n");
+ _LOG("psxetc: unable to allocate DLL struct\n");
_ERROR(RTLD_E_DLL_ALLOC, 0);
}
dll->ptr = ptr;
dll->malloc_ptr = (mode & RTLD_FREE_ON_DESTROY) ? ptr : 0;
dll->size = size;
- _LOG("psxetc: Initializing DLL at %08x\n", ptr);
+ _LOG("psxetc: initializing DLL at %08x\n", ptr);
// Interpret the key-value pairs in the .dynamic section to obtain info
// about all the other sections. The pairs are null-terminated, which makes
@@ -375,33 +368,33 @@ DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode) {
uint32_t first_got_sym = 0;
for (Elf32_Dyn *dyn = (Elf32_Dyn *) ptr; dyn->d_tag; dyn++) {
- _LOG("psxetc: .dynamic %08x=%08x ", dyn->d_tag, dyn->d_un.d_val);
+ //_LOG("psxetc: .dynamic %08x=%08x ", dyn->d_tag, dyn->d_un.d_val);
switch (dyn->d_tag) {
// Offset of .got section
case DT_PLTGOT:
- _LOG("[PLTGOT]\n");
+ //_LOG("[PLTGOT]\n");
dll->got = (void *) (ptr + dyn->d_un.d_val);
break;
// Offset of .hash section
case DT_HASH:
- _LOG("[HASH]\n");
+ //_LOG("[HASH]\n");
dll->hash = (void *) (ptr + dyn->d_un.d_val);
break;
// Offset of .dynstr (NOT .strtab) section
case DT_STRTAB:
- _LOG("[STRTAB]\n");
+ //_LOG("[STRTAB]\n");
dll->strtab = (void *) (ptr + dyn->d_un.d_val);
break;
// Offset of .dynsym (NOT .symtab) section
case DT_SYMTAB:
- _LOG("[SYMTAB]\n");
+ //_LOG("[SYMTAB]\n");
dll->symtab = (void *) (ptr + dyn->d_un.d_val);
break;
@@ -413,67 +406,67 @@ DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode) {
// Length of each .dynsym entry
case DT_SYMENT:
- _LOG("[SYMENT]\n");
+ //_LOG("[SYMENT]\n");
// Only 16-byte symbol table entries are supported.
if (dyn->d_un.d_val != sizeof(Elf32_Sym)) {
free(dll);
- _LOG("psxetc: Invalid symtab entry size %d\n", dyn->d_un.d_val);
+ _LOG("psxetc: invalid DLL symtab entry size %d\n", dyn->d_un.d_val);
_ERROR(RTLD_E_DLL_FORMAT, 0);
}
break;
// MIPS ABI (?) version
case DT_MIPS_RLD_VERSION:
- _LOG("[MIPS_RLD_VERSION]\n");
+ //_LOG("[MIPS_RLD_VERSION]\n");
// Versions other than 1 are unsupported (do they even exist?).
if (dyn->d_un.d_val != 1) {
free(dll);
- _LOG("psxetc: Invalid DLL version %d\n", dyn->d_un.d_val);
+ _LOG("psxetc: invalid DLL version %d\n", dyn->d_un.d_val);
_ERROR(RTLD_E_DLL_FORMAT, 0);
}
break;
// DLL/ABI flags
case DT_MIPS_FLAGS:
- _LOG("[MIPS_FLAGS]\n");
+ //_LOG("[MIPS_FLAGS]\n");
// Shortcut pointers (whatever they are) are not supported.
if (dyn->d_un.d_val & RHF_QUICKSTART) {
free(dll);
- _LOG("psxetc: Invalid flags\n");
+ _LOG("psxetc: invalid DLL flags\n");
_ERROR(RTLD_E_DLL_FORMAT, 0);
}
break;
// Number of local (not to resolve) GOT entries
case DT_MIPS_LOCAL_GOTNO:
- _LOG("[MIPS_LOCAL_GOTNO]\n");
+ //_LOG("[MIPS_LOCAL_GOTNO]\n");
local_got_len = dyn->d_un.d_val;
break;
// Base address DLL was compiled for
case DT_MIPS_BASE_ADDRESS:
- _LOG("[MIPS_BASE_ADDRESS]\n");
+ //_LOG("[MIPS_BASE_ADDRESS]\n");
// Base addresses other than zero are not supported. It would
// be easy enough to support them, but why?
if (dyn->d_un.d_val) {
free(dll);
- _LOG("psxetc: Invalid base address %08x\n", dyn->d_un.d_val);
+ _LOG("psxetc: invalid DLL base address %08x\n", dyn->d_un.d_val);
_ERROR(RTLD_E_DLL_FORMAT, 0);
}
break;
// Number of symbol table entries
case DT_MIPS_SYMTABNO:
- _LOG("[MIPS_SYMTABNO]\n");
+ //_LOG("[MIPS_SYMTABNO]\n");
dll->symbol_count = dyn->d_un.d_val;
break;
@@ -485,7 +478,7 @@ DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode) {
// Index of first symbol table entry which has a matching GOT entry
case DT_MIPS_GOTSYM:
- _LOG("[MIPS_GOTSYM]\n");
+ //_LOG("[MIPS_GOTSYM]\n");
first_got_sym = dyn->d_un.d_val;
break;
@@ -495,8 +488,8 @@ DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode) {
//_LOG("[MIPS_HIPAGENO]\n");
//break;
- default:
- _LOG("[ignored]\n");
+ //default:
+ //_LOG("[ignored]\n");
}
}
@@ -510,8 +503,7 @@ DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode) {
dll->got_length = local_got_len + (dll->symbol_count - first_got_sym) - 2;
_LOG(
"psxetc: %d symbols, %d GOT entries\n",
- dll->symbol_count,
- dll->got_length
+ dll->symbol_count, dll->got_length
);
// Relocate the DLL by adding its base address to all pointers in the GOT
@@ -538,12 +530,10 @@ DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode) {
continue;
sym->st_value += (uint32_t) ptr;
- _LOG(
- "psxetc: DLL sym: %08x,%08x [%s]\n",
- sym->st_value,
- sym->st_size,
- _name
- );
+ //_LOG(
+ //"psxetc: DLL sym: %08x,%08x [%s]\n",
+ //sym->st_value, sym->st_size, _name
+ //);
// If RTLD_NOW was passed, resolve GOT entries ahead of time by
// cross-referencing them with the symbol table.
@@ -651,7 +641,7 @@ void *DL_GetDLLSymbol(const DLL *dll, const char *name) {
// provided.
for (uint32_t i = bucket[hash_mod]; i != 0xffffffff;) {
if (i >= nchain) {
- _LOG("psxetc: DL_GetDLLSymbol() index out of bounds (i = %d, n = %d)\n", i, nchain);
+ _LOG("psxetc: DL_GetDLLSymbol() index out of bounds (%d >= %d)\n", i, nchain);
_ERROR(RTLD_E_HASH_LOOKUP, 0);
}
@@ -659,7 +649,7 @@ void *DL_GetDLLSymbol(const DLL *dll, const char *name) {
const char *_name = &(dll->strtab[sym->st_name]);
if (!strcmp(name, _name)) {
- _LOG("psxetc: DLL lookup [%s = %08x]\n", name, sym->st_value);
+ //_LOG("psxetc: DLL lookup [%s = %08x]\n", name, sym->st_value);
return sym->st_value;
}
diff --git a/libpsn00b/psxetc/interrupts.c b/libpsn00b/psxetc/interrupts.c
index 1b5ac32..cc9d12c 100644
--- a/libpsn00b/psxetc/interrupts.c
+++ b/libpsn00b/psxetc/interrupts.c
@@ -53,40 +53,46 @@ static const struct JMP_BUF _isr_jmp_buf = {
/* Internal IRQ and DMA handlers */
static void _global_isr(void) {
- uint16_t stat = IRQ_STAT, mask = IRQ_MASK;
+ uint16_t stat = IRQ_STAT & IRQ_MASK;
- // Clear all IRQ flags in one shot. This is not the "proper" way to do it
- // but it's much faster than clearing one flag at a time.
- IRQ_STAT = ~mask;
+ for (; stat; stat = IRQ_STAT & IRQ_MASK) {
+ //for (int i = 0; i < NUM_IRQ_CHANNELS; i++) {
+ for (int i = 0, mask = 1; stat; i++, stat >>= 1, mask <<= 1) {
+ if (!(stat & 1))
+ continue;
- //for (int i = 0; i < NUM_IRQ_CHANNELS; i++) {
- for (int i = 0; stat; i++, stat >>= 1) {
- if (!(stat & 1))
- continue;
+ // Acknowledge the current IRQ. Note that clearing all IRQ flags in one
+ // shot would result in hard-to-debug race conditions (been there, done
+ // that).
+ IRQ_STAT = (uint16_t) (mask ^ 0xffff);
- if (_irq_handlers[i])
- _irq_handlers[i]();
+ if (_irq_handlers[i])
+ _irq_handlers[i]();
+ }
}
ReturnFromException();
}
static void _global_dma_handler(void) {
- uint32_t stat = DMA_DICR;
+ uint32_t dicr = DMA_DICR;
+ uint32_t stat = (dicr >> 24) & 0x7f;
+
+ for (; stat; dicr = DMA_DICR, stat = (dicr >> 24) & 0x7f) {
+ uint32_t base = dicr & 0x00ffffff;
- // Clear all DMA IRQ flags in one shot (note that flags are cleared by
- // writing 1 to them rather than 0).
- stat &= 0x7fff0000;
- DMA_DICR = stat;
- stat >>= 24;
+ //for (int i = 0; i < NUM_DMA_CHANNELS; i++) {
+ for (int i = 0, mask = (1 << 24); stat; i++, stat >>= 1, mask <<= 1) {
+ if (!(stat & 1))
+ continue;
- //for (int i = 0; i < NUM_DMA_CHANNELS; i++) {
- for (int i = 0; stat; i++, stat >>= 1) {
- if (!(stat & 1))
- continue;
+ // Acknowledge the current DMA channel's IRQ. For whatever reason
+ // DMA IRQ flags are cleared by writing 1 to them rather than 0.
+ DMA_DICR = base | mask;
- if (_dma_handlers[i])
- _dma_handlers[i]();
+ if (_dma_handlers[i])
+ _dma_handlers[i]();
+ }
}
}